add file cache, thanks to gouki
Showing
1 changed file
with
253 additions
and
0 deletions
cache/file.go
0 → 100644
| 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 | } |
-
Please register or sign in to post a comment