sess_redis.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. // Package redis for session provider
  15. //
  16. // depend on github.com/garyburd/redigo/redis
  17. //
  18. // go install github.com/garyburd/redigo/redis
  19. //
  20. // Usage:
  21. // import(
  22. // _ "github.com/astaxie/beego/session/redis"
  23. // "github.com/astaxie/beego/session"
  24. // )
  25. //
  26. // func init() {
  27. // globalSessions, _ = session.NewManager("redis", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070"}``)
  28. // go globalSessions.GC()
  29. // }
  30. //
  31. // more docs: http://beego.me/docs/module/session.md
  32. package redis
  33. import (
  34. "net/http"
  35. "strconv"
  36. "strings"
  37. "sync"
  38. "github.com/astaxie/beego/session"
  39. "github.com/garyburd/redigo/redis"
  40. )
  41. var redispder = &Provider{}
  42. // MaxPoolSize redis max pool size
  43. var MaxPoolSize = 100
  44. // SessionStore redis session store
  45. type SessionStore struct {
  46. p *redis.Pool
  47. sid string
  48. lock sync.RWMutex
  49. values map[interface{}]interface{}
  50. maxlifetime int64
  51. }
  52. // Set value in redis session
  53. func (rs *SessionStore) Set(key, value interface{}) error {
  54. rs.lock.Lock()
  55. defer rs.lock.Unlock()
  56. rs.values[key] = value
  57. return nil
  58. }
  59. // Get value in redis session
  60. func (rs *SessionStore) Get(key interface{}) interface{} {
  61. rs.lock.RLock()
  62. defer rs.lock.RUnlock()
  63. if v, ok := rs.values[key]; ok {
  64. return v
  65. }
  66. return nil
  67. }
  68. // Delete value in redis session
  69. func (rs *SessionStore) Delete(key interface{}) error {
  70. rs.lock.Lock()
  71. defer rs.lock.Unlock()
  72. delete(rs.values, key)
  73. return nil
  74. }
  75. // Flush clear all values in redis session
  76. func (rs *SessionStore) Flush() error {
  77. rs.lock.Lock()
  78. defer rs.lock.Unlock()
  79. rs.values = make(map[interface{}]interface{})
  80. return nil
  81. }
  82. // SessionID get redis session id
  83. func (rs *SessionStore) SessionID() string {
  84. return rs.sid
  85. }
  86. // SessionRelease save session values to redis
  87. func (rs *SessionStore) SessionRelease(w http.ResponseWriter) {
  88. b, err := session.EncodeGob(rs.values)
  89. if err != nil {
  90. return
  91. }
  92. c := rs.p.Get()
  93. defer c.Close()
  94. c.Do("SETEX", rs.sid, rs.maxlifetime, string(b))
  95. }
  96. // Provider redis session provider
  97. type Provider struct {
  98. maxlifetime int64
  99. savePath string
  100. poolsize int
  101. password string
  102. dbNum int
  103. poollist *redis.Pool
  104. }
  105. // SessionInit init redis session
  106. // savepath like redis server addr,pool size,password,dbnum
  107. // e.g. 127.0.0.1:6379,100,astaxie,0
  108. func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error {
  109. rp.maxlifetime = maxlifetime
  110. configs := strings.Split(savePath, ",")
  111. if len(configs) > 0 {
  112. rp.savePath = configs[0]
  113. }
  114. if len(configs) > 1 {
  115. poolsize, err := strconv.Atoi(configs[1])
  116. if err != nil || poolsize <= 0 {
  117. rp.poolsize = MaxPoolSize
  118. } else {
  119. rp.poolsize = poolsize
  120. }
  121. } else {
  122. rp.poolsize = MaxPoolSize
  123. }
  124. if len(configs) > 2 {
  125. rp.password = configs[2]
  126. }
  127. if len(configs) > 3 {
  128. dbnum, err := strconv.Atoi(configs[3])
  129. if err != nil || dbnum < 0 {
  130. rp.dbNum = 0
  131. } else {
  132. rp.dbNum = dbnum
  133. }
  134. } else {
  135. rp.dbNum = 0
  136. }
  137. rp.poollist = redis.NewPool(func() (redis.Conn, error) {
  138. c, err := redis.Dial("tcp", rp.savePath)
  139. if err != nil {
  140. return nil, err
  141. }
  142. if rp.password != "" {
  143. if _, err := c.Do("AUTH", rp.password); err != nil {
  144. c.Close()
  145. return nil, err
  146. }
  147. }
  148. _, err = c.Do("SELECT", rp.dbNum)
  149. if err != nil {
  150. c.Close()
  151. return nil, err
  152. }
  153. return c, err
  154. }, rp.poolsize)
  155. return rp.poollist.Get().Err()
  156. }
  157. // SessionRead read redis session by sid
  158. func (rp *Provider) SessionRead(sid string) (session.Store, error) {
  159. c := rp.poollist.Get()
  160. defer c.Close()
  161. kvs, err := redis.String(c.Do("GET", sid))
  162. var kv map[interface{}]interface{}
  163. if len(kvs) == 0 {
  164. kv = make(map[interface{}]interface{})
  165. } else {
  166. kv, err = session.DecodeGob([]byte(kvs))
  167. if err != nil {
  168. return nil, err
  169. }
  170. }
  171. rs := &SessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime}
  172. return rs, nil
  173. }
  174. // SessionExist check redis session exist by sid
  175. func (rp *Provider) SessionExist(sid string) bool {
  176. c := rp.poollist.Get()
  177. defer c.Close()
  178. if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 {
  179. return false
  180. }
  181. return true
  182. }
  183. // SessionRegenerate generate new sid for redis session
  184. func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
  185. c := rp.poollist.Get()
  186. defer c.Close()
  187. if existed, _ := redis.Int(c.Do("EXISTS", oldsid)); existed == 0 {
  188. // oldsid doesn't exists, set the new sid directly
  189. // ignore error here, since if it return error
  190. // the existed value will be 0
  191. c.Do("SET", sid, "", "EX", rp.maxlifetime)
  192. } else {
  193. c.Do("RENAME", oldsid, sid)
  194. c.Do("EXPIRE", sid, rp.maxlifetime)
  195. }
  196. kvs, err := redis.String(c.Do("GET", sid))
  197. var kv map[interface{}]interface{}
  198. if len(kvs) == 0 {
  199. kv = make(map[interface{}]interface{})
  200. } else {
  201. kv, err = session.DecodeGob([]byte(kvs))
  202. if err != nil {
  203. return nil, err
  204. }
  205. }
  206. rs := &SessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime}
  207. return rs, nil
  208. }
  209. // SessionDestroy delete redis session by id
  210. func (rp *Provider) SessionDestroy(sid string) error {
  211. c := rp.poollist.Get()
  212. defer c.Close()
  213. c.Do("DEL", sid)
  214. return nil
  215. }
  216. // SessionGC Impelment method, no used.
  217. func (rp *Provider) SessionGC() {
  218. return
  219. }
  220. // SessionAll return all activeSession
  221. func (rp *Provider) SessionAll() int {
  222. return 0
  223. }
  224. func init() {
  225. session.Register("redis", redispder)
  226. }