session: support memcache interface
Showing
2 changed files
with
217 additions
and
3 deletions
| ... | @@ -137,9 +137,11 @@ func (rc *MemcacheCache) StartAndGC(config string) error { | ... | @@ -137,9 +137,11 @@ 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 | rc.c, err = rc.connectInit() | 140 | if rc.c != nil { |
| 141 | if err != nil { | 141 | rc.c, err = rc.connectInit() |
| 142 | return errors.New("dial tcp conn error") | 142 | if err != nil { |
| 143 | return errors.New("dial tcp conn error") | ||
| 144 | } | ||
| 143 | } | 145 | } |
| 144 | return nil | 146 | return nil |
| 145 | } | 147 | } | ... | ... |
session/memcache/sess_memcache.go
0 → 100644
| 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 | } |
-
Please register or sign in to post a comment