sess_memcache.go 5.5 KB

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