/
session.go
130 lines (111 loc) · 3.31 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package base
import (
"fmt"
"strings"
utils "github.com/azhai/gozzo-utils/common"
"github.com/azhai/gozzo-utils/redisw"
"github.com/gomodule/redigo/redis"
)
const (
SESS_FOR_EVER = -1 // 无限
SESS_NOT_EXISTS = -2 // 不存在
SESS_ERR_REDIS = -3 // redis错误
SESS_PREFIX = "sess" // 会话缓存前缀
SESS_LIST_SEP = ";" // 角色名之间的分隔符
SESS_TOKEN_KEY = "_token_"
SESS_ONLINE_KEY = "onlines" // 在线用户
MAX_TIMEOUT = 86400 * 30 // 接近无限时间
)
func SessListJoin(data []string) string {
return strings.Join(data, SESS_LIST_SEP)
}
func SessListSplit(data string) []string {
return strings.Split(data, SESS_LIST_SEP)
}
type SessionRegistry struct {
sessions map[string]*Session
Onlines *redisw.RedisHash
*redisw.RedisWrapper
}
func NewRegistry(w *redisw.RedisWrapper) *SessionRegistry {
return &SessionRegistry{
sessions: make(map[string]*Session),
Onlines: redisw.NewRedisHash(w, SESS_ONLINE_KEY, MAX_TIMEOUT),
RedisWrapper: w,
}
}
func (sr SessionRegistry) GetKey(token string) string {
return fmt.Sprintf("%s:%s", SESS_PREFIX, token)
}
func (sr *SessionRegistry) GetSession(token string, timeout int) *Session {
key := sr.GetKey(token)
if sess, ok := sr.sessions[key]; ok && sess != nil {
return sess
}
sess := NewSession(sr, key, timeout)
if _, err := sess.SetVal(SESS_TOKEN_KEY, token); err == nil {
sr.sessions[key] = sess
}
return sess
}
func (sr *SessionRegistry) DelSession(token string) bool {
key := sr.GetKey(token)
if sess, ok := sr.sessions[key]; ok {
succ, err := sess.DeleteAll()
if succ && err == nil {
delete(sr.sessions, key)
return true
}
}
return false
}
type Session struct {
reg *SessionRegistry
*redisw.RedisHash
}
func NewSession(reg *SessionRegistry, key string, timeout int) *Session {
hash := redisw.NewRedisHash(reg.RedisWrapper, key, timeout)
return &Session{reg: reg, RedisHash: hash}
}
func (sess *Session) GetKey() string {
token, err := sess.GetString(SESS_TOKEN_KEY)
if err == nil && token != "" {
return sess.reg.GetKey(token)
}
return ""
}
func (sess *Session) WrapExec(cmd string, args ...interface{}) (interface{}, error) {
// pp.Println(cmd, args)
return sess.reg.Exec(cmd, args...)
}
// 添加临时消息
func (sess *Session) AddFlash(messages ...string) (int, error) {
key := fmt.Sprintf("flash:%s", sess.GetKey())
args := append([]interface{}{key}, utils.StrToList(messages)...)
return redis.Int(sess.WrapExec("RPUSH", args...))
}
// 数量n为最大取出多少条消息,-1表示所有消息
func (sess *Session) GetFlashes(n int) ([]string, error) {
end := -1
if n > 0 {
end = n - 1
}
key := fmt.Sprintf("flash:%s", sess.GetKey())
return redis.Strings(sess.WrapExec("LRANGE", key, 0, end))
}
// 绑定用户角色,返回旧的sid
func (sess *Session) BindRoles(uid string, roles []string, kick bool) (string, error) {
newSid := sess.GetKey()
oldSid, _ := sess.reg.Onlines.GetString(uid) // 用于踢掉重复登录
if oldSid == newSid { // 同一个token
oldSid = ""
}
_, err := sess.reg.Onlines.SetVal(uid, newSid)
_, err = sess.SetVal("uid", uid)
_, err = sess.SetVal("roles", SessListJoin(roles))
if kick && oldSid != "" { // 清空旧的session
flashKey := fmt.Sprintf("flash:%s", oldSid)
sess.reg.Delete(oldSid, flashKey)
}
return oldSid, err
}