sess_mysql.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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 mysql for session provider
  15. //
  16. // depends on github.com/go-sql-driver/mysql:
  17. //
  18. // go install github.com/go-sql-driver/mysql
  19. //
  20. // mysql session support need create table as sql:
  21. // CREATE TABLE `session` (
  22. // `session_key` char(64) NOT NULL,
  23. // `session_data` blob,
  24. // `session_expiry` int(11) unsigned NOT NULL,
  25. // PRIMARY KEY (`session_key`)
  26. // ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  27. //
  28. // Usage:
  29. // import(
  30. // _ "github.com/astaxie/beego/session/mysql"
  31. // "github.com/astaxie/beego/session"
  32. // )
  33. //
  34. // func init() {
  35. // globalSessions, _ = session.NewManager("mysql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]"}``)
  36. // go globalSessions.GC()
  37. // }
  38. //
  39. // more docs: http://beego.me/docs/module/session.md
  40. package mysql
  41. import (
  42. "database/sql"
  43. "net/http"
  44. "sync"
  45. "time"
  46. "github.com/astaxie/beego/session"
  47. // import mysql driver
  48. _ "github.com/go-sql-driver/mysql"
  49. )
  50. var (
  51. // TableName store the session in MySQL
  52. TableName = "session"
  53. mysqlpder = &Provider{}
  54. )
  55. // SessionStore mysql session store
  56. type SessionStore struct {
  57. c *sql.DB
  58. sid string
  59. lock sync.RWMutex
  60. values map[interface{}]interface{}
  61. }
  62. // Set value in mysql session.
  63. // it is temp value in map.
  64. func (st *SessionStore) Set(key, value interface{}) error {
  65. st.lock.Lock()
  66. defer st.lock.Unlock()
  67. st.values[key] = value
  68. return nil
  69. }
  70. // Get value from mysql session
  71. func (st *SessionStore) Get(key interface{}) interface{} {
  72. st.lock.RLock()
  73. defer st.lock.RUnlock()
  74. if v, ok := st.values[key]; ok {
  75. return v
  76. }
  77. return nil
  78. }
  79. // Delete value in mysql session
  80. func (st *SessionStore) Delete(key interface{}) error {
  81. st.lock.Lock()
  82. defer st.lock.Unlock()
  83. delete(st.values, key)
  84. return nil
  85. }
  86. // Flush clear all values in mysql session
  87. func (st *SessionStore) Flush() error {
  88. st.lock.Lock()
  89. defer st.lock.Unlock()
  90. st.values = make(map[interface{}]interface{})
  91. return nil
  92. }
  93. // SessionID get session id of this mysql session store
  94. func (st *SessionStore) SessionID() string {
  95. return st.sid
  96. }
  97. // SessionRelease save mysql session values to database.
  98. // must call this method to save values to database.
  99. func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
  100. defer st.c.Close()
  101. b, err := session.EncodeGob(st.values)
  102. if err != nil {
  103. return
  104. }
  105. st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
  106. b, time.Now().Unix(), st.sid)
  107. }
  108. // Provider mysql session provider
  109. type Provider struct {
  110. maxlifetime int64
  111. savePath string
  112. }
  113. // connect to mysql
  114. func (mp *Provider) connectInit() *sql.DB {
  115. db, e := sql.Open("mysql", mp.savePath)
  116. if e != nil {
  117. return nil
  118. }
  119. return db
  120. }
  121. // SessionInit init mysql session.
  122. // savepath is the connection string of mysql.
  123. func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
  124. mp.maxlifetime = maxlifetime
  125. mp.savePath = savePath
  126. return nil
  127. }
  128. // SessionRead get mysql session by sid
  129. func (mp *Provider) SessionRead(sid string) (session.Store, error) {
  130. c := mp.connectInit()
  131. defer c.Close()
  132. row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
  133. var sessiondata []byte
  134. err := row.Scan(&sessiondata)
  135. if err == sql.ErrNoRows {
  136. c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
  137. sid, "", time.Now().Unix())
  138. }
  139. var kv map[interface{}]interface{}
  140. if len(sessiondata) == 0 {
  141. kv = make(map[interface{}]interface{})
  142. } else {
  143. kv, err = session.DecodeGob(sessiondata)
  144. if err != nil {
  145. return nil, err
  146. }
  147. }
  148. rs := &SessionStore{c: c, sid: sid, values: kv}
  149. return rs, nil
  150. }
  151. // SessionExist check mysql session exist
  152. func (mp *Provider) SessionExist(sid string) bool {
  153. c := mp.connectInit()
  154. defer c.Close()
  155. row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
  156. var sessiondata []byte
  157. err := row.Scan(&sessiondata)
  158. if err == sql.ErrNoRows {
  159. return false
  160. }
  161. return true
  162. }
  163. // SessionRegenerate generate new sid for mysql session
  164. func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
  165. c := mp.connectInit()
  166. defer c.Close()
  167. row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
  168. var sessiondata []byte
  169. err := row.Scan(&sessiondata)
  170. if err == sql.ErrNoRows {
  171. c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
  172. }
  173. c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
  174. var kv map[interface{}]interface{}
  175. if len(sessiondata) == 0 {
  176. kv = make(map[interface{}]interface{})
  177. } else {
  178. kv, err = session.DecodeGob(sessiondata)
  179. if err != nil {
  180. return nil, err
  181. }
  182. }
  183. rs := &SessionStore{c: c, sid: sid, values: kv}
  184. return rs, nil
  185. }
  186. // SessionDestroy delete mysql session by sid
  187. func (mp *Provider) SessionDestroy(sid string) error {
  188. c := mp.connectInit()
  189. c.Exec("DELETE FROM "+TableName+" where session_key=?", sid)
  190. c.Close()
  191. return nil
  192. }
  193. // SessionGC delete expired values in mysql session
  194. func (mp *Provider) SessionGC() {
  195. c := mp.connectInit()
  196. c.Exec("DELETE from "+TableName+" where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
  197. c.Close()
  198. return
  199. }
  200. // SessionAll count values in mysql session
  201. func (mp *Provider) SessionAll() int {
  202. c := mp.connectInit()
  203. defer c.Close()
  204. var total int
  205. err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total)
  206. if err != nil {
  207. return 0
  208. }
  209. return total
  210. }
  211. func init() {
  212. session.Register("mysql", mysqlpder)
  213. }