github.com/astaxie/beego@v1.12.3/session/redis/sess_redis.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package redis for session provider 16 // 17 // depend on github.com/gomodule/redigo/redis 18 // 19 // go install github.com/gomodule/redigo/redis 20 // 21 // Usage: 22 // import( 23 // _ "github.com/astaxie/beego/session/redis" 24 // "github.com/astaxie/beego/session" 25 // ) 26 // 27 // func init() { 28 // globalSessions, _ = session.NewManager("redis", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070"}``) 29 // go globalSessions.GC() 30 // } 31 // 32 // more docs: http://beego.me/docs/module/session.md 33 package redis 34 35 import ( 36 "net/http" 37 "strconv" 38 "strings" 39 "sync" 40 "time" 41 42 "github.com/astaxie/beego/session" 43 44 "github.com/gomodule/redigo/redis" 45 ) 46 47 var redispder = &Provider{} 48 49 // MaxPoolSize redis max pool size 50 var MaxPoolSize = 100 51 52 // SessionStore redis session store 53 type SessionStore struct { 54 p *redis.Pool 55 sid string 56 lock sync.RWMutex 57 values map[interface{}]interface{} 58 maxlifetime int64 59 } 60 61 // Set value in redis session 62 func (rs *SessionStore) Set(key, value interface{}) error { 63 rs.lock.Lock() 64 defer rs.lock.Unlock() 65 rs.values[key] = value 66 return nil 67 } 68 69 // Get value in redis session 70 func (rs *SessionStore) Get(key interface{}) interface{} { 71 rs.lock.RLock() 72 defer rs.lock.RUnlock() 73 if v, ok := rs.values[key]; ok { 74 return v 75 } 76 return nil 77 } 78 79 // Delete value in redis session 80 func (rs *SessionStore) Delete(key interface{}) error { 81 rs.lock.Lock() 82 defer rs.lock.Unlock() 83 delete(rs.values, key) 84 return nil 85 } 86 87 // Flush clear all values in redis session 88 func (rs *SessionStore) Flush() error { 89 rs.lock.Lock() 90 defer rs.lock.Unlock() 91 rs.values = make(map[interface{}]interface{}) 92 return nil 93 } 94 95 // SessionID get redis session id 96 func (rs *SessionStore) SessionID() string { 97 return rs.sid 98 } 99 100 // SessionRelease save session values to redis 101 func (rs *SessionStore) SessionRelease(w http.ResponseWriter) { 102 b, err := session.EncodeGob(rs.values) 103 if err != nil { 104 return 105 } 106 c := rs.p.Get() 107 defer c.Close() 108 c.Do("SETEX", rs.sid, rs.maxlifetime, string(b)) 109 } 110 111 // Provider redis session provider 112 type Provider struct { 113 maxlifetime int64 114 savePath string 115 poolsize int 116 password string 117 dbNum int 118 poollist *redis.Pool 119 } 120 121 // SessionInit init redis session 122 // savepath like redis server addr,pool size,password,dbnum,IdleTimeout second 123 // e.g. 127.0.0.1:6379,100,astaxie,0,30 124 func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { 125 rp.maxlifetime = maxlifetime 126 configs := strings.Split(savePath, ",") 127 if len(configs) > 0 { 128 rp.savePath = configs[0] 129 } 130 if len(configs) > 1 { 131 poolsize, err := strconv.Atoi(configs[1]) 132 if err != nil || poolsize < 0 { 133 rp.poolsize = MaxPoolSize 134 } else { 135 rp.poolsize = poolsize 136 } 137 } else { 138 rp.poolsize = MaxPoolSize 139 } 140 if len(configs) > 2 { 141 rp.password = configs[2] 142 } 143 if len(configs) > 3 { 144 dbnum, err := strconv.Atoi(configs[3]) 145 if err != nil || dbnum < 0 { 146 rp.dbNum = 0 147 } else { 148 rp.dbNum = dbnum 149 } 150 } else { 151 rp.dbNum = 0 152 } 153 var idleTimeout time.Duration = 0 154 if len(configs) > 4 { 155 timeout, err := strconv.Atoi(configs[4]) 156 if err == nil && timeout > 0 { 157 idleTimeout = time.Duration(timeout) * time.Second 158 } 159 } 160 rp.poollist = &redis.Pool{ 161 Dial: func() (redis.Conn, error) { 162 c, err := redis.Dial("tcp", rp.savePath) 163 if err != nil { 164 return nil, err 165 } 166 if rp.password != "" { 167 if _, err = c.Do("AUTH", rp.password); err != nil { 168 c.Close() 169 return nil, err 170 } 171 } 172 // some redis proxy such as twemproxy is not support select command 173 if rp.dbNum > 0 { 174 _, err = c.Do("SELECT", rp.dbNum) 175 if err != nil { 176 c.Close() 177 return nil, err 178 } 179 } 180 return c, err 181 }, 182 MaxIdle: rp.poolsize, 183 } 184 185 rp.poollist.IdleTimeout = idleTimeout 186 187 return rp.poollist.Get().Err() 188 } 189 190 // SessionRead read redis session by sid 191 func (rp *Provider) SessionRead(sid string) (session.Store, error) { 192 c := rp.poollist.Get() 193 defer c.Close() 194 195 var kv map[interface{}]interface{} 196 197 kvs, err := redis.String(c.Do("GET", sid)) 198 if err != nil && err != redis.ErrNil { 199 return nil, err 200 } 201 if len(kvs) == 0 { 202 kv = make(map[interface{}]interface{}) 203 } else { 204 if kv, err = session.DecodeGob([]byte(kvs)); err != nil { 205 return nil, err 206 } 207 } 208 209 rs := &SessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime} 210 return rs, nil 211 } 212 213 // SessionExist check redis session exist by sid 214 func (rp *Provider) SessionExist(sid string) bool { 215 c := rp.poollist.Get() 216 defer c.Close() 217 218 if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 { 219 return false 220 } 221 return true 222 } 223 224 // SessionRegenerate generate new sid for redis session 225 func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { 226 c := rp.poollist.Get() 227 defer c.Close() 228 229 if existed, _ := redis.Int(c.Do("EXISTS", oldsid)); existed == 0 { 230 // oldsid doesn't exists, set the new sid directly 231 // ignore error here, since if it return error 232 // the existed value will be 0 233 c.Do("SET", sid, "", "EX", rp.maxlifetime) 234 } else { 235 c.Do("RENAME", oldsid, sid) 236 c.Do("EXPIRE", sid, rp.maxlifetime) 237 } 238 return rp.SessionRead(sid) 239 } 240 241 // SessionDestroy delete redis session by id 242 func (rp *Provider) SessionDestroy(sid string) error { 243 c := rp.poollist.Get() 244 defer c.Close() 245 246 c.Do("DEL", sid) 247 return nil 248 } 249 250 // SessionGC Impelment method, no used. 251 func (rp *Provider) SessionGC() { 252 } 253 254 // SessionAll return all activeSession 255 func (rp *Provider) SessionAll() int { 256 return 0 257 } 258 259 func init() { 260 session.Register("redis", redispder) 261 }