forked from fasthttp/session
-
Notifications
You must be signed in to change notification settings - Fork 0
/
provider.go
141 lines (104 loc) · 2.56 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
package memory
import (
"sync"
"time"
"github.com/savsgio/gotils/strconv"
)
var itemPool = &sync.Pool{
New: func() interface{} {
return new(item)
},
}
func acquireItem() *item {
return itemPool.Get().(*item)
}
func releaseItem(item *item) {
item.data = item.data[:0]
item.lastActiveTime = 0
item.expiration = 0
itemPool.Put(item)
}
// New returns a new memory provider configured
func New(cfg Config) (*Provider, error) {
p := &Provider{
config: cfg,
}
return p, nil
}
func (p *Provider) getSessionKey(sessionID []byte) string {
return strconv.B2S(sessionID)
}
// Get returns the data of the given session id
func (p *Provider) Get(id []byte) ([]byte, error) {
key := p.getSessionKey(id)
val, found := p.db.Load(key)
if !found || val == nil { // Not exist
return nil, nil
}
item := val.(*item)
return item.data, nil
}
// Save saves the session data and expiration from the given session id
func (p *Provider) Save(id, data []byte, expiration time.Duration) error {
key := p.getSessionKey(id)
item := acquireItem()
item.data = data
item.lastActiveTime = time.Now().UnixNano()
item.expiration = expiration
p.db.Store(key, item)
return nil
}
// Regenerate updates the session id and expiration with the new session id
// of the the given current session id
func (p *Provider) Regenerate(id, newID []byte, expiration time.Duration) error {
key := p.getSessionKey(id)
data, found := p.db.LoadAndDelete(key)
if found && data != nil {
item := data.(*item)
item.lastActiveTime = time.Now().UnixNano()
item.expiration = expiration
newKey := p.getSessionKey(newID)
p.db.Store(newKey, item)
}
return nil
}
func (p *Provider) destroy(key string) error {
val, found := p.db.LoadAndDelete(key)
if !found || val == nil {
return nil
}
releaseItem(val.(*item))
return nil
}
// Destroy destroys the session from the given id
func (p *Provider) Destroy(id []byte) error {
key := p.getSessionKey(id)
return p.destroy(key)
}
// Count returns the total of stored sessions
func (p *Provider) Count() (count int) {
p.db.Range(func(_, _ interface{}) bool {
count++
return true
})
return count
}
// NeedGC indicates if the GC needs to be run
func (p *Provider) NeedGC() bool {
return true
}
// GC destroys the expired sessions
func (p *Provider) GC() error {
now := time.Now().UnixNano()
p.db.Range(func(key, value interface{}) bool {
item := value.(*item)
if item.expiration == 0 {
return true
}
if now >= (item.lastActiveTime + item.expiration.Nanoseconds()) {
_ = p.destroy(key.(string))
}
return true
})
return nil
}