This repository has been archived by the owner on May 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfilecache.go
129 lines (108 loc) · 2.54 KB
/
filecache.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
package filecache
import (
"bytes"
"encoding/gob"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
const cachedir = "/tmp"
// Set writes item to cache
func Set(key string, data interface{}, expire time.Duration) error {
key = regexp.MustCompile("[^a-zA-Z0-9_-]").ReplaceAllLiteralString(key, "")
file := fmt.Sprintf("fcache.%s.%v", key, strconv.FormatInt(time.Now().Add(expire).Unix(), 10))
fpath := filepath.Join(cachedir, file)
clean(key)
serialized, err := serialize(data)
if err != nil {
return err
}
var fmutex sync.RWMutex
fmutex.Lock()
defer fmutex.Unlock()
fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer fp.Close()
if _, err = fp.Write(serialized); err != nil {
return err
}
return nil
}
// Get reads item from cache
func Get(key string, dst interface{}) (bool, error) {
key = regexp.MustCompile("[^a-zA-Z0-9_-]").ReplaceAllLiteralString(key, "")
pattern := filepath.Join(cachedir, fmt.Sprintf("fcache.%s.*", key))
files, err := filepath.Glob(pattern)
if err != nil {
return false, err
}
if len(files) < 1 {
return false, nil
}
if _, err = os.Stat(files[0]); err != nil {
return false, err
}
fp, err := os.OpenFile(files[0], os.O_RDONLY, 0400)
if err != nil {
return false, err
}
defer fp.Close()
var serialized []byte
buf := make([]byte, 1024)
for {
var n int
n, err = fp.Read(buf)
serialized = append(serialized, buf[0:n]...)
if err != nil || err == io.EOF {
break
}
}
if err = deserialize(serialized, dst); err != nil {
return false, err
}
for _, file := range files {
exptime, err := strconv.ParseInt(strings.Split(file, ".")[2], 10, 64)
if err != nil {
return false, err
}
if exptime < time.Now().Unix() {
if _, err = os.Stat(file); err == nil {
os.Remove(file)
}
}
}
return true, nil
}
// clean removes item from cache
func clean(key string) error {
pattern := filepath.Join(cachedir, fmt.Sprintf("fcache.%s.*", key))
files, _ := filepath.Glob(pattern)
for _, file := range files {
if _, err := os.Stat(file); err == nil {
os.Remove(file)
}
}
return nil
}
// serialize encodes a value using binary
func serialize(src interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
if err := gob.NewEncoder(buf).Encode(src); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// deserialize decodes a value using binary
func deserialize(src []byte, dst interface{}) error {
buf := bytes.NewReader(src)
err := gob.NewDecoder(buf).Decode(dst)
return err
}