123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- package permit
- import (
- "context"
- "crypto/rand"
- "encoding/hex"
- "net/http"
- "net/url"
- "sync"
- "time"
- "go-common/library/cache/memcache"
- "go-common/library/log"
- bm "go-common/library/net/http/blademaster"
- )
- // Session http session.
- type Session struct {
- Sid string
- lock sync.RWMutex
- Values map[string]interface{}
- }
- // SessionConfig config of Session.
- type SessionConfig struct {
- SessionIDLength int
- CookieLifeTime int
- CookieName string
- Domain string
- Memcache *memcache.Config
- }
- // SessionManager .
- type SessionManager struct {
- mc *memcache.Pool // Session cache
- c *SessionConfig
- }
- // newSessionManager .
- func newSessionManager(c *SessionConfig) (s *SessionManager) {
- s = &SessionManager{
- mc: memcache.NewPool(c.Memcache),
- c: c,
- }
- return
- }
- // SessionStart start session.
- func (s *SessionManager) SessionStart(ctx *bm.Context) (si *Session) {
- // check manager Session id, if err or no exist need new one.
- if si, _ = s.cache(ctx); si == nil {
- si = s.newSession(ctx)
- }
- return
- }
- // SessionRelease flush session into store.
- func (s *SessionManager) SessionRelease(ctx *bm.Context, sv *Session) {
- // set http cookie
- s.setHTTPCookie(ctx, s.c.CookieName, sv.Sid)
- // set mc
- conn := s.mc.Get(ctx)
- defer conn.Close()
- key := sv.Sid
- item := &memcache.Item{
- Key: key,
- Object: sv,
- Flags: memcache.FlagJSON,
- Expiration: int32(s.c.CookieLifeTime),
- }
- if err := conn.Set(item); err != nil {
- log.Error("SessionManager set error(%s,%v)", key, err)
- }
- }
- // SessionDestroy destroy session.
- func (s *SessionManager) SessionDestroy(ctx *bm.Context, sv *Session) {
- conn := s.mc.Get(ctx)
- defer conn.Close()
- if err := conn.Delete(sv.Sid); err != nil {
- log.Error("SessionManager delete error(%s,%v)", sv.Sid, err)
- }
- }
- func (s *SessionManager) cache(ctx *bm.Context) (res *Session, err error) {
- ck, err := ctx.Request.Cookie(s.c.CookieName)
- if err != nil || ck == nil {
- return
- }
- sid := ck.Value
- // get from cache
- conn := s.mc.Get(ctx)
- defer conn.Close()
- r, err := conn.Get(sid)
- if err != nil {
- if err == memcache.ErrNotFound {
- err = nil
- return
- }
- log.Error("conn.Get(%s) error(%v)", sid, err)
- return
- }
- res = &Session{}
- if err = conn.Scan(r, res); err != nil {
- log.Error("conn.Scan(%v) error(%v)", string(r.Value), err)
- }
- return
- }
- func (s *SessionManager) newSession(ctx context.Context) (res *Session) {
- b := make([]byte, s.c.SessionIDLength)
- n, err := rand.Read(b)
- if n != len(b) || err != nil {
- return nil
- }
- res = &Session{
- Sid: hex.EncodeToString(b),
- Values: make(map[string]interface{}),
- }
- return
- }
- func (s *SessionManager) setHTTPCookie(ctx *bm.Context, name, value string) {
- cookie := &http.Cookie{
- Name: name,
- Value: url.QueryEscape(value),
- Path: "/",
- HttpOnly: true,
- Domain: _defaultDomain,
- }
- cookie.MaxAge = _defaultCookieLifeTime
- cookie.Expires = time.Now().Add(time.Duration(_defaultCookieLifeTime) * time.Second)
- http.SetCookie(ctx.Writer, cookie)
- }
- // Get get value by key.
- func (s *Session) Get(key string) (value interface{}) {
- s.lock.RLock()
- defer s.lock.RUnlock()
- value = s.Values[key]
- return
- }
- // Set set value into session.
- func (s *Session) Set(key string, value interface{}) (err error) {
- s.lock.Lock()
- defer s.lock.Unlock()
- s.Values[key] = value
- return
- }
|