iris/sessions/provider.go

119 lines
2.9 KiB
Go
Raw Normal View History

2016-05-30 16:08:09 +02:00
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
}