sess_redis.go 6.1 KB

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