//session存放在redis中 //多节点部署时,可以session不受内存存放的影响 package httpsession import ( "encoding/json" "sync" "time" "app.yhyue.com/moapp/jybase/redis" ) var locks = make([]*sync.Mutex, RedisSessionLockSize) type redisStore struct { last time.Time maxAge time.Duration GcInterval time.Duration } func NewRedisStore(maxAge time.Duration) *redisStore { for i := 0; i < RedisSessionLockSize; i++ { locks[i] = &sync.Mutex{} } return &redisStore{maxAge: maxAge, GcInterval: 10 * time.Second} } //设置超时 func (store *redisStore) SetMaxAge(maxAge time.Duration) { store.maxAge = maxAge } //取数据,使用redis的超时,来控制session超时 func (store *redisStore) Get(id Id, key string) interface{} { return store.GetMultiple(id)[key] } //同时获取多个值 func (store *redisStore) GetMultiple(id Id) map[string]interface{} { lock(id).Lock() bs, err := redis.GetBytes("session", string(id)) m := make(map[string]interface{}) if err != nil || bs == nil { lock(id).Unlock() return m } json.Unmarshal(*bs, &m) timeout := int(store.maxAge.Seconds()) if RedisNotLoginKey != "" && m[RedisNotLoginKey] == nil { timeout = RedisNotLoginExpire } redis.SetExpire("session", string(id), timeout) store.last = time.Now() lock(id).Unlock() return m } //设置数据 func (store *redisStore) Set(id Id, key string, value interface{}) { store.SetMultiple(id, map[string]interface{}{key: value}) } //同时设置多个值 func (store *redisStore) SetMultiple(id Id, m map[string]interface{}) error { lock(id).Lock() defer lock(id).Unlock() var userdata map[string]interface{} bs, err := redis.GetBytes("session", string(id)) if err != nil { userdata = make(map[string]interface{}) } else { if err = json.Unmarshal(*bs, &userdata); err != nil { return err } } for k, v := range m { userdata[k] = v } timeout := int(store.maxAge.Seconds()) if RedisNotLoginKey != "" && userdata[RedisNotLoginKey] == nil { timeout = RedisNotLoginExpire } putdata, err := json.Marshal(userdata) if err != nil { return err } return redis.PutBytes("session", string(id), &putdata, timeout) } func (store *redisStore) Add(id Id) { } func (store *redisStore) Del(id Id, keys ...string) bool { lock(id).Lock() defer lock(id).Unlock() bs, err := redis.GetBytes("session", string(id)) if err != nil { return false } var userdata map[string]interface{} if json.Unmarshal(*bs, &userdata) != nil { return false } for _, key := range keys { delete(userdata, key) } timeout := int(store.maxAge.Seconds()) if RedisNotLoginKey != "" && userdata[RedisNotLoginKey] == nil { timeout = RedisNotLoginExpire } putdata, _ := json.Marshal(userdata) if redis.PutBytes("session", string(id), &putdata, timeout) == nil { return true } return false } //根据自定义字段,更新 func (store *redisStore) UpdateByCustomField(findkey string, findvalue interface{}, setkey string, setvalue interface{}) bool { lock(Id(findkey)).Lock() defer lock(Id(findkey)).Unlock() bs, err := redis.GetBytes("session", findkey) if err != nil { return false } var data map[string]interface{} if json.Unmarshal(*bs, &data) != nil { return false } timeout := int(store.maxAge.Seconds()) if RedisNotLoginKey != "" && data[RedisNotLoginKey] == nil { timeout = RedisNotLoginExpire } data[setkey] = setvalue putdata, _ := json.Marshal(data) if redis.PutBytes("session", findkey, &putdata, timeout) == nil { return true } return false } func (store *redisStore) Exist(id Id) bool { lock(id).Lock() defer lock(id).Unlock() ret, err := redis.Exists("session", string(id)) return err == nil && ret } func (store *redisStore) Clear(id Id) bool { lock(id).Lock() defer lock(id).Unlock() return redis.Del("session", string(id)) } func (store *redisStore) Run() error { return nil } //TODO 加缓冲 func (store *redisStore) GC() { //log.Println("Gc") } // func lock(id Id) *sync.Mutex { n := 0 for _, v := range id { n += int(v) } return locks[n%RedisSessionLockSize] }