c5eabcf4 by astaxie

add file cache, thanks to gouki

1 parent b5b53b38
1 /**
2 * package: file
3 * User: gouki
4 * Date: 2013-10-22 - 14:22
5 */
6 package cache
7
8 import (
9 "bytes"
10 "crypto/md5"
11 "encoding/gob"
12 "encoding/hex"
13 "encoding/json"
14 "fmt"
15 "io"
16 "os"
17 "path"
18 "reflect"
19 "strconv"
20 "time"
21 )
22
23 func init() {
24 Register("file", NewFileCache())
25 }
26
27 type FileCacheItem struct {
28 Data interface{}
29 Lastaccess int64
30 Expired int64
31 }
32
33 var (
34 FileCachePath string = "cache"
35 FileCacheFileSuffix string = ".bin"
36 FileCacheDirectoryLevel int = 2
37 /**
38 * 默认永不过期
39 */
40 FileCacheEmbedExpiry int64 = 0
41 )
42
43 type FileCache struct {
44 CachePath string
45 FileSuffix string
46 DirectoryLevel int
47 EmbedExpiry int
48 }
49
50 func NewFileCache() *FileCache {
51 // return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
52 return &FileCache{}
53 }
54
55 func (this *FileCache) StartAndGC(config string) error {
56
57 var cfg map[string]string
58 json.Unmarshal([]byte(config), &cfg)
59 //fmt.Println(cfg)
60 if _, ok := cfg["CachePath"]; !ok {
61 cfg["CachePath"] = FileCachePath
62 }
63 if _, ok := cfg["FileSuffix"]; !ok {
64 cfg["FileSuffix"] = FileCacheFileSuffix
65 }
66 if _, ok := cfg["DirectoryLevel"]; !ok {
67 cfg["DirectoryLevel"] = strconv.Itoa(FileCacheDirectoryLevel)
68 }
69 if _, ok := cfg["EmbedExpiry"]; !ok {
70 cfg["EmbedExpiry"] = strconv.FormatInt(FileCacheEmbedExpiry, 10)
71 }
72 this.CachePath = cfg["CachePath"]
73 this.FileSuffix = cfg["FileSuffix"]
74 this.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"])
75 this.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"])
76
77 this.Init()
78 return nil
79 }
80
81 func (this *FileCache) Init() {
82 app := path.Dir(os.Args[0])
83 this.CachePath = path.Join(app, this.CachePath)
84 ok, err := exists(this.CachePath)
85 if err != nil { // print error
86 //fmt.Println(err)
87 }
88 if !ok {
89 if err = os.Mkdir(this.CachePath, os.ModePerm); err != nil {
90 //fmt.Println(err);
91 }
92 }
93 //fmt.Println(this.getCacheFileName("123456"));
94 }
95
96 func (this *FileCache) getCacheFileName(key string) string {
97 m := md5.New()
98 io.WriteString(m, key)
99 keyMd5 := hex.EncodeToString(m.Sum(nil))
100 cachePath := this.CachePath
101 //fmt.Println("cachepath : " , cachePath)
102 //fmt.Println("md5" , keyMd5);
103 switch this.DirectoryLevel {
104 case 2:
105 cachePath = path.Join(cachePath, keyMd5[0:2], keyMd5[2:4])
106 case 1:
107 cachePath = path.Join(cachePath, keyMd5[0:2])
108 }
109
110 ok, err := exists(cachePath)
111 if err != nil {
112 //fmt.Println(err)
113 }
114 if !ok {
115 if err = os.MkdirAll(cachePath, os.ModePerm); err != nil {
116 //fmt.Println(err);
117 }
118 }
119 return path.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, this.FileSuffix))
120 }
121
122 func (this *FileCache) Get(key string) interface{} {
123 filename := this.getCacheFileName(key)
124 filedata, err := File_get_contents(filename)
125 //fmt.Println("get length:" , len(filedata));
126 if err != nil {
127 return ""
128 }
129 var to FileCacheItem
130 Gob_decode([]byte(filedata), &to)
131 if to.Expired < time.Now().Unix() {
132 return ""
133 }
134 return to.Data
135 }
136
137 func (this *FileCache) Put(key string, val interface{}, timeout int64) error {
138 filename := this.getCacheFileName(key)
139 var item FileCacheItem
140 item.Data = val
141 if timeout == FileCacheEmbedExpiry {
142 item.Expired = time.Now().Unix() + (86400 * 365 * 10) //10年
143 } else {
144 item.Expired = time.Now().Unix() + timeout
145 }
146 item.Expired = time.Now().Unix() + timeout
147 item.Lastaccess = time.Now().Unix()
148 data, err := Gob_encode(item)
149 if err != nil {
150 return err
151 }
152 err = File_put_contents(filename, data)
153 return err
154 }
155
156 func (this *FileCache) Delete(key string) error {
157 filename := this.getCacheFileName(key)
158 if ok, _ := exists(filename); ok {
159 return os.Remove(filename)
160 }
161 return nil
162 }
163
164 func (this *FileCache) Incr(key string) error {
165 data := this.Get(key)
166 var incr int
167 fmt.Println(reflect.TypeOf(data).Name())
168 if reflect.TypeOf(data).Name() != "int" {
169 incr = 0
170 } else {
171 incr = data.(int) + 1
172 }
173 this.Put(key, incr, FileCacheEmbedExpiry)
174 return nil
175 }
176
177 func (this *FileCache) Decr(key string) error {
178 data := this.Get(key)
179 var decr int
180 if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 {
181 decr = 0
182 } else {
183 decr = data.(int) - 1
184 }
185 this.Put(key, decr, FileCacheEmbedExpiry)
186 return nil
187 }
188
189 func (this *FileCache) IsExist(key string) bool {
190 filename := this.getCacheFileName(key)
191 ret, _ := exists(filename)
192 return ret
193 }
194
195 func (this *FileCache) ClearAll() error {
196 //this.CachePath .递归删除
197
198 return nil
199 }
200
201 func exists(path string) (bool, error) {
202 _, err := os.Stat(path)
203 if err == nil {
204 return true, nil
205 }
206 if os.IsNotExist(err) {
207 return false, nil
208 }
209 return false, err
210 }
211
212 func File_get_contents(filename string) ([]byte, error) { //文件不存在时自动创建
213 f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
214 if err != nil {
215 return []byte(""), err
216 }
217 defer f.Close()
218 stat, err := f.Stat()
219 if err != nil {
220 return []byte(""), err
221 }
222 data := make([]byte, stat.Size())
223 result, err := f.Read(data)
224 if int64(result) == stat.Size() {
225 return data, err
226 }
227 return []byte(""), err
228 }
229
230 func File_put_contents(filename string, content []byte) error {
231 fp, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
232 if err != nil {
233 return err
234 }
235 defer fp.Close()
236 _, err = fp.Write(content)
237 return err
238 }
239 func Gob_encode(data interface{}) ([]byte, error) {
240 buf := bytes.NewBuffer(nil)
241 enc := gob.NewEncoder(buf)
242 err := enc.Encode(data)
243 if err != nil {
244 return nil, err
245 }
246 return buf.Bytes(), err
247 }
248
249 func Gob_decode(data []byte, to interface{}) error {
250 buf := bytes.NewBuffer(data)
251 dec := gob.NewDecoder(buf)
252 return dec.Decode(&to)
253 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!