31a63c5d by astaxie

session: support memcache interface

1 parent 237aaadd
...@@ -137,10 +137,12 @@ func (rc *MemcacheCache) StartAndGC(config string) error { ...@@ -137,10 +137,12 @@ func (rc *MemcacheCache) StartAndGC(config string) error {
137 } 137 }
138 rc.conninfo = cf["conn"] 138 rc.conninfo = cf["conn"]
139 var err error 139 var err error
140 if rc.c != nil {
140 rc.c, err = rc.connectInit() 141 rc.c, err = rc.connectInit()
141 if err != nil { 142 if err != nil {
142 return errors.New("dial tcp conn error") 143 return errors.New("dial tcp conn error")
143 } 144 }
145 }
144 return nil 146 return nil
145 } 147 }
146 148
......
1 // Beego (http://beego.me/)
2 // @description beego is an open-source, high-performance web framework for the Go programming language.
3 // @link http://github.com/astaxie/beego for the canonical source repository
4 // @license http://github.com/astaxie/beego/blob/master/LICENSE
5 // @authors astaxie
6
7 package session
8
9 import (
10 "net/http"
11 "sync"
12
13 "github.com/astaxie/beego/session"
14
15 "github.com/beego/memcache"
16 )
17
18 var mempder = &MemProvider{}
19
20 // memcache session store
21 type MemcacheSessionStore struct {
22 c *memcache.Connection
23 sid string
24 lock sync.RWMutex
25 values map[interface{}]interface{}
26 maxlifetime int64
27 }
28
29 // set value in memcache session
30 func (rs *MemcacheSessionStore) Set(key, value interface{}) error {
31 rs.lock.Lock()
32 defer rs.lock.Unlock()
33 rs.values[key] = value
34 return nil
35 }
36
37 // get value in memcache session
38 func (rs *MemcacheSessionStore) Get(key interface{}) interface{} {
39 rs.lock.RLock()
40 defer rs.lock.RUnlock()
41 if v, ok := rs.values[key]; ok {
42 return v
43 } else {
44 return nil
45 }
46 }
47
48 // delete value in memcache session
49 func (rs *MemcacheSessionStore) Delete(key interface{}) error {
50 rs.lock.Lock()
51 defer rs.lock.Unlock()
52 delete(rs.values, key)
53 return nil
54 }
55
56 // clear all values in memcache session
57 func (rs *MemcacheSessionStore) Flush() error {
58 rs.lock.Lock()
59 defer rs.lock.Unlock()
60 rs.values = make(map[interface{}]interface{})
61 return nil
62 }
63
64 // get redis session id
65 func (rs *MemcacheSessionStore) SessionID() string {
66 return rs.sid
67 }
68
69 // save session values to redis
70 func (rs *MemcacheSessionStore) SessionRelease(w http.ResponseWriter) {
71 defer rs.c.Close()
72 // if rs.values is empty, return directly
73 if len(rs.values) < 1 {
74 rs.c.Delete(rs.sid)
75 return
76 }
77
78 b, err := session.EncodeGob(rs.values)
79 if err != nil {
80 return
81 }
82 rs.c.Set(rs.sid, 0, uint64(rs.maxlifetime), b)
83 }
84
85 // redis session provider
86 type MemProvider struct {
87 maxlifetime int64
88 savePath string
89 poolsize int
90 password string
91 }
92
93 // init redis session
94 // savepath like
95 // e.g. 127.0.0.1:9090
96 func (rp *MemProvider) SessionInit(maxlifetime int64, savePath string) error {
97 rp.maxlifetime = maxlifetime
98 rp.savePath = savePath
99 return nil
100 }
101
102 // read redis session by sid
103 func (rp *MemProvider) SessionRead(sid string) (session.SessionStore, error) {
104 conn, err := rp.connectInit()
105 if err != nil {
106 return nil, err
107 }
108 kvs, err := conn.Get(sid)
109 if err != nil {
110 return nil, err
111 }
112 var contain []byte
113 if len(kvs) > 0 {
114 contain = kvs[0].Value
115 }
116 var kv map[interface{}]interface{}
117 if len(contain) == 0 {
118 kv = make(map[interface{}]interface{})
119 } else {
120 kv, err = session.DecodeGob(contain)
121 if err != nil {
122 return nil, err
123 }
124 }
125
126 rs := &MemcacheSessionStore{c: conn, sid: sid, values: kv, maxlifetime: rp.maxlifetime}
127 return rs, nil
128 }
129
130 // check redis session exist by sid
131 func (rp *MemProvider) SessionExist(sid string) bool {
132 conn, err := rp.connectInit()
133 if err != nil {
134 return false
135 }
136 defer conn.Close()
137 if kvs, err := conn.Get(sid); err != nil || len(kvs) == 0 {
138 return false
139 } else {
140 return true
141 }
142 }
143
144 // generate new sid for redis session
145 func (rp *MemProvider) SessionRegenerate(oldsid, sid string) (session.SessionStore, error) {
146 conn, err := rp.connectInit()
147 if err != nil {
148 return nil, err
149 }
150 var contain []byte
151 if kvs, err := conn.Get(sid); err != nil || len(kvs) == 0 {
152 // oldsid doesn't exists, set the new sid directly
153 // ignore error here, since if it return error
154 // the existed value will be 0
155 conn.Set(sid, 0, uint64(rp.maxlifetime), []byte(""))
156 } else {
157 conn.Delete(oldsid)
158 conn.Set(sid, 0, uint64(rp.maxlifetime), kvs[0].Value)
159 contain = kvs[0].Value
160 }
161
162 var kv map[interface{}]interface{}
163 if len(contain) == 0 {
164 kv = make(map[interface{}]interface{})
165 } else {
166 kv, err = session.DecodeGob(contain)
167 if err != nil {
168 return nil, err
169 }
170 }
171
172 rs := &MemcacheSessionStore{c: conn, sid: sid, values: kv, maxlifetime: rp.maxlifetime}
173 return rs, nil
174 }
175
176 // delete redis session by id
177 func (rp *MemProvider) SessionDestroy(sid string) error {
178 conn, err := rp.connectInit()
179 if err != nil {
180 return err
181 }
182 defer conn.Close()
183
184 _, err = conn.Delete(sid)
185 if err != nil {
186 return err
187 }
188 return nil
189 }
190
191 // Impelment method, no used.
192 func (rp *MemProvider) SessionGC() {
193 return
194 }
195
196 // @todo
197 func (rp *MemProvider) SessionAll() int {
198 return 0
199 }
200
201 // connect to memcache and keep the connection.
202 func (rp *MemProvider) connectInit() (*memcache.Connection, error) {
203 c, err := memcache.Connect(rp.savePath)
204 if err != nil {
205 return nil, err
206 }
207 return c, nil
208 }
209
210 func init() {
211 session.Register("memcache", mempder)
212 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!