package sessions import ( "container/list" "sync" "time" "github.com/kataras/iris/sessions/store" ) // IProvider the type which Provider must implement type IProvider interface { Name() string Init(string) (store.IStore, error) Read(string) (store.IStore, error) Destroy(string) error Update(string) error GC(time.Duration) } type ( // Provider implements the IProvider // contains the temp sessions memory, the store and some options for the cookies Provider struct { name string mu sync.Mutex sessions map[string]*list.Element // underline TEMPORARY memory store list *list.List // for GC NewStore func(sessionId string, cookieLifeDuration time.Duration) store.IStore OnDestroy func(store store.IStore) // this is called when .Destroy cookieLifeDuration time.Duration } ) var _ IProvider = &Provider{} // NewProvider returns a new empty Provider func NewProvider(name string) *Provider { provider := &Provider{name: name, list: list.New()} provider.sessions = make(map[string]*list.Element, 0) return provider } // Init creates the store for the first time for this session and returns it func (p *Provider) Init(sid string) (store.IStore, error) { p.mu.Lock() newSessionStore := p.NewStore(sid, p.cookieLifeDuration) elem := p.list.PushBack(newSessionStore) p.sessions[sid] = elem p.mu.Unlock() return newSessionStore, nil } // Read returns the store which sid parameter is belongs func (p *Provider) Read(sid string) (store.IStore, error) { if elem, found := p.sessions[sid]; found { return elem.Value.(store.IStore), nil } // if not found sessionStore, err := p.Init(sid) return sessionStore, err } // Destroy always returns a nil error, for now. func (p *Provider) Destroy(sid string) error { if elem, found := p.sessions[sid]; found { elem.Value.(store.IStore).Destroy() delete(p.sessions, sid) p.list.Remove(elem) } return nil } // Update updates the lastAccessedTime, and moves the memory place element to the front // always returns a nil error, for now func (p *Provider) Update(sid string) error { p.mu.Lock() if elem, found := p.sessions[sid]; found { elem.Value.(store.IStore).SetLastAccessedTime(time.Now()) p.list.MoveToFront(elem) } p.mu.Unlock() return nil } // GC clears the memory func (p *Provider) GC(duration time.Duration) { p.mu.Lock() p.cookieLifeDuration = duration defer p.mu.Unlock() //let's defer it and trust the go for { elem := p.list.Back() if elem == nil { break } // if the time has passed. session was expired, then delete the session and its memory place if (elem.Value.(store.IStore).LastAccessedTime().Unix() + duration.Nanoseconds()) < time.Now().Unix() { p.list.Remove(elem) delete(p.sessions, elem.Value.(store.IStore).ID()) } else { break } } } // Name the provider's name, example: 'memory' or 'redis' func (p *Provider) Name() string { return p.name }