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