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