-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcache.go
137 lines (112 loc) · 2.91 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
Package glc is provides the local cache which is stored in memoroy or file.
This package creates `tmp` directory in case of using file cache.
Example:
mc := glc.NewMemoryCache(glc.DefaultMemoryCacheExpires)
// Set
if err := mc.Set("cacheKey", []byte('hoge')); err != nil {
log.Fatal(err)
}
// Get
data := mc.Get("cacheKey")
*/
package glc
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"time"
)
const (
// DefaultMemoryCacheExpires is 60 seconds
DefaultMemoryCacheExpires = 60 * time.Second
fileCacheDir = "tmp"
)
// MemoryCache is cache data in memory which has duration.
type MemoryCache struct {
item map[string]*Item
d time.Duration
m sync.RWMutex
}
// Item has cache item and expiration field.
type Item struct {
data []byte
exp int64
}
// Get returns a item or nil.
// If cache in local is nil or expiration date of the cache is earlier, this returns nil.
func (c *MemoryCache) Get(key string) []byte {
c.m.RLock()
defer c.m.RUnlock()
item, ok := c.item[key]
if !ok || item == nil {
return nil
}
if len(item.data) == 0 || item.exp < time.Now().UnixNano() {
return nil
}
return item.data
}
// Set add a new data for cache with a new key or replace an exist key.
func (c *MemoryCache) Set(key string, src []byte) error {
if c.item == nil {
return fmt.Errorf("error: nil map access")
}
if len(src) == 0 {
return fmt.Errorf("error: set no data")
}
c.m.Lock()
defer c.m.Unlock()
c.item[key] = &Item{
data: src,
exp: time.Now().Add(c.d).UnixNano(),
}
return nil
}
// NewMemoryCache creates a new MemoryCache for given a its expires as time.Duration.
func NewMemoryCache(d time.Duration) *MemoryCache {
return &MemoryCache{item: make(map[string]*Item), d: d}
}
// FileCache is cache data in local file.
type FileCache struct {
path string
m sync.RWMutex
}
// Get returns a data or nil.
// If cache in local file is nil or is not setted key, this returns nil.
func (c *FileCache) Get(key string) []byte {
c.m.RLock()
defer c.m.RUnlock()
fp := filepath.Join(c.path, key) + ".cache"
b, err := ioutil.ReadFile(fp)
if err != nil {
return nil
}
return b
}
// Set create a new file which is witten data as []byte.
// When it sets a new cache data, create a `{{ $key }}.cache` file,
// and overwrite it if cache file is exist.
func (c *FileCache) Set(key string, src []byte) error {
if len(src) == 0 {
return fmt.Errorf("error: set no data")
}
c.m.Lock()
defer c.m.Unlock()
fp := filepath.Join(c.path, key) + ".cache"
if err := ioutil.WriteFile(fp, src, os.ModePerm); err != nil {
return fmt.Errorf("set cache error. err: %v", err)
}
return nil
}
// NewFileCache returns FileCache pointer.
// If there is no temp directory named prefix, create temp directory for storing cache.
func NewFileCache(prefix string) (*FileCache, error) {
path, err := ioutil.TempDir("", prefix)
if err != nil {
return nil, err
}
return &FileCache{path: path}, nil
}