Skip to content

Latest commit

 

History

History
139 lines (120 loc) · 4.07 KB

File metadata and controls

139 lines (120 loc) · 4.07 KB

6.3 Session storage

We introduced a simple session manager's working principles in the previous section, and among other things, we defined a session storage interface. In this section, I'm going to show you an example of a memory based session storage engine that implements this interface. You can tailor this to other 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 implements a memory based session storage mechanism. It uses its init() function to register this storage engine to the session manager. So how do we register this engine from our main program?

	import (
	    "github.com/astaxie/session"
	    _ "github.com/astaxie/session/providers/memory"
	)

We use the blank import mechanism (which will invoke the package's init() function automatically) to register this engine to a session manager. We then use the following code to initialize the session manager:

	var globalSessions *session.Manager
	
	// initialize in init() function
	func init() {
	    globalSessions, _ = session.NewManager("memory", "gosessionid", 3600)
	    go globalSessions.GC()
	}

Links