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()
    }

results matching ""

    No results matching ""