# 6.3 Session storage We introduced session manager work principle in previous section, we defined a session storage interface. In this section, I'm going to show you an example of memory-based session storage engine that implements the interface. You can change this to others forms of session storage as well. package memory import ( "container/list" "github.com/astaxie/session" "sync" "time" ) var pder = &Provider{list: list.New()} type SessionStore struct { sid string // unique session id timeAccessed time.Time // last access time value map[interface{}]interface{} // session value stored inside } func (st *SessionStore) Set(key, value interface{}) error { st.value[key] = value pder.SessionUpdate(st.sid) return nil } func (st *SessionStore) Get(key interface{}) interface{} { pder.SessionUpdate(st.sid) if v, ok := st.value[key]; ok { return v } else { return nil } return nil } func (st *SessionStore) Delete(key interface{}) error { delete(st.value, key) pder.SessionUpdate(st.sid) return nil } func (st *SessionStore) SessionID() string { return st.sid } type Provider struct { lock sync.Mutex // lock sessions map[string]*list.Element // save in memory list *list.List // gc } func (pder *Provider) SessionInit(sid string) (session.Session, error) { pder.lock.Lock() defer pder.lock.Unlock() v := make(map[interface{}]interface{}, 0) newsess := &SessionStore{sid: sid, timeAccessed: time.Now(), value: v} element := pder.list.PushBack(newsess) pder.sessions[sid] = element return newsess, nil } func (pder *Provider) SessionRead(sid string) (session.Session, error) { if element, ok := pder.sessions[sid]; ok { return element.Value.(*SessionStore), nil } else { sess, err := pder.SessionInit(sid) return sess, err } return nil, nil } func (pder *Provider) SessionDestroy(sid string) error { if element, ok := pder.sessions[sid]; ok { delete(pder.sessions, sid) pder.list.Remove(element) return nil } return nil } func (pder *Provider) SessionGC(maxlifetime int64) { pder.lock.Lock() defer pder.lock.Unlock() for { element := pder.list.Back() if element == nil { break } if (element.Value.(*SessionStore).timeAccessed.Unix() + maxlifetime) < time.Now().Unix() { pder.list.Remove(element) delete(pder.sessions, element.Value.(*SessionStore).sid) } else { break } } } func (pder *Provider) SessionUpdate(sid string) error { pder.lock.Lock() defer pder.lock.Unlock() if element, ok := pder.sessions[sid]; ok { element.Value.(*SessionStore).timeAccessed = time.Now() pder.list.MoveToFront(element) return nil } return nil } func init() { pder.sessions = make(map[string]*list.Element, 0) session.Register("memory", pder) } The above example implemented a memory-based session storage mechanism, then use init() function to register this storage engine to session manager. So how to register this engine? import ( "github.com/astaxie/session" _ "github.com/astaxie/session/providers/memory" ) Use import mechanism to register this engine in init() function automatically to session manager, then we use following code to initialize a session manager: var globalSessions *session.Manager // initialize in init() function func init() { globalSessions, _ = session.NewManager("memory", "gosessionid", 3600) go globalSessions.GC() } ## Links - [Directory](preface.md) - Previous section: [How to use session in Go](06.2.md) - Next section: [Prevent hijack of session](06.4.md)