forked from hanguofeng/gocaptcha
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cstore.go
164 lines (136 loc) · 3.06 KB
/
cstore.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
// Copyright 2013 hanguofeng. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package gocaptcha
import (
"crypto/md5"
enc "encoding/gob"
"encoding/hex"
"fmt"
"os"
"sync"
"time"
)
//CStore is the Captcha info store service
type CStore struct {
engine string
mu sync.RWMutex
data map[string]*CaptchaInfo
expiresTime time.Duration
gcProbability int
gcDivisor int
}
//CreateCStore will create a new CStore
func CreateCStore(expiresTime time.Duration, gcProbability int, gcDivisor int) *CStore {
store := new(CStore)
store.engine = STORE_ENGINE_BUILDIN
store.data = make(map[string]*CaptchaInfo)
store.expiresTime = expiresTime
store.gcProbability = gcProbability
store.gcDivisor = gcDivisor
return store
}
//Get captcha info by key
func (store *CStore) Get(key string) *CaptchaInfo {
defer store.gcWrapper() //run gc after get
store.mu.Lock()
defer store.mu.Unlock()
ret := store.data[key]
return ret
}
//Add captcha info and get the auto generated key
func (store *CStore) Add(captcha *CaptchaInfo) string {
store.mu.Lock()
defer store.mu.Unlock()
key := fmt.Sprintf("%s%s%x", captcha.Text, randStr(20), time.Now().UnixNano())
key = hex.EncodeToString(md5.New().Sum([]byte(key)))
key = key[:32]
store.data[key] = captcha
return key
}
//Update captcha info
func (store *CStore) Update(key string, captcha *CaptchaInfo) bool {
store.mu.Lock()
defer store.mu.Unlock()
store.data[key] = captcha
return true
}
//Del captcha info by key
func (store *CStore) Del(key string) {
store.mu.Lock()
defer store.mu.Unlock()
delete(store.data, key)
}
//Destroy the whole store
func (store *CStore) Destroy() {
for key := range store.data {
store.Del(key)
}
}
//OnConstruct load data
func (store *CStore) OnConstruct() {
}
//OnDestruct dump data
func (store *CStore) OnDestruct() {
}
//Dump the whole store
func (store *CStore) Dump(file string) error {
store.mu.Lock()
defer store.mu.Unlock()
pwd, err := os.Getwd()
if (nil == err) && ("" != pwd) {
f, err := os.Create(pwd + "/" + file)
if nil == err {
encoder := enc.NewEncoder(f)
err := encoder.Encode(store.data)
f.Close()
if nil == err {
return err
} else {
return nil
}
} else {
return err
}
} else {
return err
}
return nil
}
//LoadDumped file to store
func (store *CStore) LoadDumped(file string) error {
data := &map[string]*CaptchaInfo{}
pwd, err := os.Getwd()
if (nil == err) && ("" != pwd) {
f, err := os.Open(pwd + "/" + file)
if nil == err {
decoder := enc.NewDecoder(f)
err := decoder.Decode(data)
f.Close()
if nil == err {
store.data = *data
return nil
} else {
return err
}
} else {
return err
}
} else {
return err
}
return err
}
func (store *CStore) gcWrapper() {
//run PROBABILITY
if rnd(0, store.gcDivisor) == store.gcProbability {
go store.gc()
}
}
func (store *CStore) gc() {
for key, val := range store.data {
if val.CreateTime.Add(store.expiresTime).Before(time.Now()) {
store.Del(key)
}
}
}