From ea9ad0db90cd2742c19c98780eb3391ef2983b3f Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 24 Sep 2024 21:18:05 +0800 Subject: [PATCH] sesssion middleware --- go.mod | 1 + go.sum | 2 + session/init.go | 23 ++++++++ session/memorysession_mgr.go | 18 +++++- session/redissession.go | 109 +++++++++++++++++++++++++++++++++++ session/redissession_mgr.go | 92 +++++++++++++++++++++++++++++ 6 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 session/init.go create mode 100644 session/redissession.go create mode 100644 session/redissession_mgr.go diff --git a/go.mod b/go.mod index 7e6bf86..7c474da 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/garyburd/redigo v1.6.4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.10.0 // indirect github.com/go-playground/locales v0.14.1 // indirect diff --git a/go.sum b/go.sum index 0a17442..f3106d0 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/garyburd/redigo v1.6.4 h1:LFu2R3+ZOPgSMWMOL+saa/zXRjw0ID2G8FepO53BGlg= +github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= diff --git a/session/init.go b/session/init.go new file mode 100644 index 0000000..dbdf95e --- /dev/null +++ b/session/init.go @@ -0,0 +1,23 @@ +package session + +import "fmt" + +var ( + sessionMgr SessionMgr +) + +//中间件让用户选择使用哪个版本 + +func Init(provider string, addr string, options ...string) (err error) { + switch provider { + case "memory": + sessionMgr = NewMemorySessionMgr() + case "redis": + sessionMgr = NewRedisSessionMgr() + default: + fmt.Errorf("不支持") + return + } + err = sessionMgr.Init(addr, options...) + return +} diff --git a/session/memorysession_mgr.go b/session/memorysession_mgr.go index 3748d97..80fc021 100644 --- a/session/memorysession_mgr.go +++ b/session/memorysession_mgr.go @@ -1,6 +1,7 @@ package session import ( + "errors" uuid "github.com/satori/go.uuid" "sync" ) @@ -25,6 +26,8 @@ func (s *MemorySessionMgr) Init(addr string, options ...string) (err error) { return } +//mgr创建一个session + func (s *MemorySessionMgr) CreateSession() (session Session, err error) { s.rwLock.Lock() defer s.rwLock.Unlock() @@ -33,7 +36,16 @@ func (s *MemorySessionMgr) CreateSession() (session Session, err error) { //创建一个session memorySession := NewMemorySession(sessionId) s.sessionMap[sessionId] = memorySession - - return memorySession, nil - + return +} + +func (s *MemorySessionMgr) GetSession(sessionId string) (session Session, err error) { + s.rwLock.Lock() + defer s.rwLock.Unlock() + session, ok := s.sessionMap[sessionId] + if !ok { + err = errors.New("session not found") + return + } + return } diff --git a/session/redissession.go b/session/redissession.go new file mode 100644 index 0000000..6feec12 --- /dev/null +++ b/session/redissession.go @@ -0,0 +1,109 @@ +package session + +import ( + "encoding/json" + "errors" + "github.com/garyburd/redigo/redis" + "sync" +) + +type RedisSession struct { + sessionId string + pool *redis.Pool + //设置session key value + sessionMap map[string]interface{} + rwLock sync.RWMutex + flag int +} + +//用常量定义状态 + +const ( + //内存数据没变化 + SessionFlagNone = iota + + SessionFlagModify +) + +//构造函数 + +func NewRedisSession(pool *redis.Pool, id string) *RedisSession { + s := &RedisSession{ + sessionId: id, + pool: pool, + sessionMap: make(map[string]interface{}, 16), + flag: SessionFlagNone, + } + return s +} + +func (r *RedisSession) Set(key string, value interface{}) (err error) { + r.rwLock.Lock() + defer r.rwLock.Unlock() + r.sessionMap[key] = value + //flag + r.flag = SessionFlagModify + return +} + +func (r *RedisSession) Save() (err error) { + r.rwLock.RLock() + defer r.rwLock.RUnlock() + //如果数据没变,不需要存 + if r.flag != SessionFlagModify { + return + } + //内存中的sessionMap进行序列化 + data, err := json.Marshal(r.sessionMap) + if err != nil { + return + } + //获取redis链接 + _, err = r.pool.Get().Do("SET", r.sessionId, string(data)) + r.flag = SessionFlagNone + if err != nil { + return + } + return +} + +func (r *RedisSession) Get(key string) (result interface{}, err error) { + r.rwLock.RLock() + defer r.rwLock.RUnlock() + + //判断内存有没有数据 + result, ok := r.sessionMap[key] + if !ok { + err = errors.New("key not found") + return + } + return +} + +//从redis里再次加载 + +func (r *RedisSession) LoadFormRedis() (err error) { + reply, err := r.pool.Get().Do("GET", r.sessionId) + if err != nil { + return + } + //转字符串 + data, err := redis.String(reply, err) + if err != nil { + return + } + //取到的东西反序列化到内存的map中 + err = json.Unmarshal([]byte(data), &r.sessionMap) + if err != nil { + return + } + return +} + +func (r *RedisSession) Del(key string) (err error) { + r.rwLock.Lock() + defer r.rwLock.Unlock() + r.flag = SessionFlagModify + delete(r.sessionMap, key) + return +} diff --git a/session/redissession_mgr.go b/session/redissession_mgr.go new file mode 100644 index 0000000..722f264 --- /dev/null +++ b/session/redissession_mgr.go @@ -0,0 +1,92 @@ +package session + +import ( + "errors" + "github.com/garyburd/redigo/redis" + uuid "github.com/satori/go.uuid" + "sync" + "time" +) + +type RedisSessionMgr struct { + //redis 地址 + addr string + //密码 + password string + //链接池 + pool *redis.Pool + //锁 + rwLock sync.RWMutex + //大map + sessionMap map[string]Session +} + +//构造 + +func NewRedisSessionMgr() SessionMgr { + sr := &RedisSessionMgr{ + sessionMap: make(map[string]Session, 32), + } + return sr +} + +func (r *RedisSessionMgr) Init(addr string, options ...string) (err error) { + //若有其他参数 + if len(options) > 0 { + r.password = options[0] + } + //创建链接池 + r.pool = myPool(addr, r.password) + r.addr = addr + return +} + +func myPool(addr, password string) *redis.Pool { + return &redis.Pool{ + MaxIdle: 64, + IdleTimeout: 240 * time.Second, + MaxActive: 1000, + Dial: func() (redis.Conn, error) { + conn, err := redis.Dial("tcp", addr) + if err != nil { + return nil, err + } + //如果有密码,判断 + if _, err = conn.Do("AUTH", password); err != nil { + conn.Close() + return nil, err + } + return conn, nil + + }, + //链接测试,开发时写 + TestOnBorrow: func(c redis.Conn, t time.Time) error { + _, err := c.Do("PING") + return err + }, + } +} + +//mgr创建一个session + +func (r *RedisSessionMgr) CreateSession() (session Session, err error) { + r.rwLock.Lock() + defer r.rwLock.Unlock() + //用uuid作为session id + sessionId := uuid.NewV4().String() + //创建一个session + redisSession := NewRedisSession(r.pool, sessionId) + r.sessionMap[sessionId] = redisSession + return +} + +func (r *RedisSessionMgr) GetSession(sessionId string) (session Session, err error) { + r.rwLock.Lock() + defer r.rwLock.Unlock() + session, ok := r.sessionMap[sessionId] + if !ok { + err = errors.New("session not found") + return + } + return +}