-
Notifications
You must be signed in to change notification settings - Fork 12
/
provider.go
229 lines (183 loc) · 4.93 KB
/
provider.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package file
import (
"errors"
"github.com/phachon/fasthttpsession"
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"sync"
"time"
)
// session file provider
const ProviderName = "file"
var (
fileProvider = NewProvider()
encrypt = fasthttpsession.NewEncrypt()
)
type Provider struct {
lock sync.RWMutex
file *file
config *Config
maxLifeTime int64
}
// new file provider
func NewProvider() *Provider {
return &Provider{
file: &file{},
config: &Config{},
}
}
// init provider config
func (fp *Provider) Init(lifeTime int64, fileConfig fasthttpsession.ProviderConfig) error {
if fileConfig.Name() != ProviderName {
return errors.New("session file provider init error, config must file config")
}
vc := reflect.ValueOf(fileConfig)
fc := vc.Interface().(*Config)
fp.config = fc
if fp.config.SavePath == "" {
return errors.New("session file provider init error, config savePath not empty")
}
if fp.config.SerializeFunc == nil {
fp.config.SerializeFunc = encrypt.GobEncode
}
if fp.config.UnSerializeFunc == nil {
fp.config.UnSerializeFunc = encrypt.GobDecode
}
fp.maxLifeTime = lifeTime
// create save path
os.MkdirAll(fp.config.SavePath, 0777)
return nil
}
// need gc
func (fp *Provider) NeedGC() bool {
return true
}
// session garbage collection
func (fp *Provider) GC() {
files, err := fp.file.walkDir(fp.config.SavePath, fp.config.Suffix)
if err == nil {
for _, file := range files {
if time.Now().Unix() >= (fp.maxLifeTime + fp.file.getModifyTime(file)) {
fp.lock.Lock()
filename := filepath.Base(file)
sessionId := strings.TrimRight(filename, fp.config.Suffix)
fp.removeSessionFile(sessionId)
fp.lock.Unlock()
}
}
}
}
// read session store by session id
func (fp *Provider) ReadStore(sessionId string) (fasthttpsession.SessionStore, error) {
fp.lock.Lock()
defer fp.lock.Unlock()
store := &Store{}
filePath, _, fullFileName := fp.getSessionFile(sessionId)
// file is exist
if fp.file.pathIsExists(fullFileName) {
sessionInfo, err := fp.file.getContent(fullFileName)
if err != nil {
return store, err
}
// unserialize sessionInfo
value, err := fp.config.UnSerializeFunc(sessionInfo)
if err != nil {
return store, err
}
store.Init(sessionId, value)
return store, nil
}
os.MkdirAll(filePath, 0777)
err := fp.file.createFile(fullFileName)
if err != nil {
return store, err
}
store.Init(sessionId, map[string]interface{}{})
return store, nil
}
// regenerate session
func (fp *Provider) Regenerate(oldSessionId string, sessionId string) (fasthttpsession.SessionStore, error) {
fp.lock.Lock()
defer fp.lock.Unlock()
store := &Store{}
_, _, oldFullFileName := fp.getSessionFile(oldSessionId)
filePath, _, fullFileName := fp.getSessionFile(sessionId)
if fp.file.pathIsExists(fullFileName) {
return store, errors.New("new sessionId file exist")
}
// create new session file
os.MkdirAll(filePath, 0777)
err := fp.file.createFile(fullFileName)
if err != nil {
return store, err
}
if fp.file.pathIsExists(oldFullFileName) {
// read old session info
sessionInfo, err := fp.file.getContent(fullFileName)
if err != nil {
return store, err
}
// write new session file
ioutil.WriteFile(fullFileName, sessionInfo, 0777)
// remove old session file
fp.removeSessionFile(oldSessionId)
// update new session file time
os.Chtimes(fullFileName, time.Now(), time.Now())
// unserialize sessionInfo
value, err := fp.config.UnSerializeFunc(sessionInfo)
if err != nil {
return store, err
}
store.Init(sessionId, value)
return store, nil
}
store.Init(sessionId, map[string]interface{}{})
return store, nil
}
// destroy session by sessionId
func (fp *Provider) Destroy(sessionId string) error {
fp.lock.Lock()
defer fp.lock.Unlock()
_, _, fullFileName := fp.getSessionFile(sessionId)
if fp.file.pathIsExists(fullFileName) {
fp.removeSessionFile(sessionId)
}
return nil
}
// session values count
func (fp *Provider) Count() int {
fp.lock.Lock()
defer fp.lock.Unlock()
count, _ := fp.file.count(fp.config.SavePath, fp.config.Suffix)
return count
}
// get session filePath, filename, fullFilename
func (fp *Provider) getSessionFile(sessionId string) (string, string, string) {
filePath := path.Join(fp.config.SavePath, string(sessionId[0]), string(sessionId[1]))
filename := sessionId + fp.config.Suffix
fullFilename := filepath.Join(filePath, filename)
return filePath, filename, fullFilename
}
// remove session file
func (fp *Provider) removeSessionFile(sessionId string) {
filePath, _, fullFileName := fp.getSessionFile(sessionId)
os.Remove(fullFileName)
// remove empty dir
s, _ := ioutil.ReadDir(filePath)
if len(s) == 0 {
os.RemoveAll(filePath)
}
filePath1 := path.Join(fp.config.SavePath, string(sessionId[0]))
s, _ = ioutil.ReadDir(filePath1)
if len(s) == 0 {
os.RemoveAll(filePath1)
}
}
// register session provider
func init() {
fasthttpsession.Register(ProviderName, fileProvider)
}