1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-10 05:25:58 +00:00

Sessions are now in full sync with the registered database, on acquire(init), set, get, delete, clear, visit, len, release(destroy) as requested by almost everyone. https://github.com/kataras/iris/issues/969

Former-commit-id: 49fcdb93106a78f0a24ad3fb4d8725e35e98451a
This commit is contained in:
Gerasimos Maropoulos
2018-04-22 13:52:36 +03:00
parent f113872b7d
commit b62080c4bb
28 changed files with 496 additions and 1358 deletions

View File

@@ -3,8 +3,6 @@ package sessions
import (
"sync"
"time"
"github.com/kataras/iris/core/memstore"
)
type (
@@ -14,25 +12,24 @@ type (
// we don't use RWMutex because all actions have read and write at the same action function.
// (or write to a *Session's value which is race if we don't lock)
// narrow locks are fasters but are useless here.
mu sync.Mutex
sessions map[string]*Session
databases []Database
mu sync.Mutex
sessions map[string]*Session
db Database
}
)
// newProvider returns a new sessions provider
func newProvider() *provider {
return &provider{
sessions: make(map[string]*Session, 0),
databases: make([]Database, 0),
sessions: make(map[string]*Session, 0),
db: newMemDB(),
}
}
// RegisterDatabase adds a session database
// a session db doesn't have write access
// RegisterDatabase sets a session database.
func (p *provider) RegisterDatabase(db Database) {
p.mu.Lock() // for any case
p.databases = append(p.databases, db)
p.db = db
p.mu.Unlock()
}
@@ -42,7 +39,8 @@ func (p *provider) newSession(sid string, expires time.Duration) *Session {
p.Destroy(sid)
}
values, lifetime := p.loadSessionFromDB(sid)
lifetime := p.db.Acquire(sid, expires)
// simple and straight:
if !lifetime.IsZero() {
// if stored time is not zero
@@ -58,89 +56,16 @@ func (p *provider) newSession(sid string, expires time.Duration) *Session {
lifetime.Begin(expires, onExpire)
}
// I ended up without the need of a duration field on lifetime,
// but these are some of my previous comments, they will be required for any future change.
//
// OK I think go has a bug when gob on embedded time.Time
// even if we `gob.Register(LifeTime)`
// the OriginalDuration is not saved to the gob file and it cannot be retrieved, it's always 0.
// But if we do not embed the `time.Time` inside the `LifeTime` then
// it's working.
// i.e type LifeTime struct { time.Time; OriginalDuration time.Duration} -> this doesn't
// type LifeTime struct {Time time.Time; OriginalDuration time.Duration} -> this works
// So we have two options:
// 1. don't embed the time.Time -> we will have to use lifetime.Time to get its functions, which doesn't seems right to me
// 2. embed the time.Time and compare their times with `lifetime.After(time.Now().Add(expires))`, it seems right but it
// should be slower.
//
// I'll use the 1. and put some common time.Time functions, like After, IsZero on the `LifeTime` type too.
//
// if db exists but its lifetime is bigger than the expires (very raire,
// the source code should be compatible with the databases,
// should we print a warning to the user? it is his/her fault
// use the database's lifetime or the configurated?
// if values.Len() > 0 && lifetime.OriginalDuration != expires {
// golog.Warnf(`session database: stored expire time(dur=%d) is differnet than the configuration(dur=%d)
// application will use the configurated one`, lifetime.OriginalDuration, expires)
// lifetime.Reset(expires)
// }
sess := &Session{
sid: sid,
provider: p,
values: values,
flashes: make(map[string]*flashMessage),
lifetime: lifetime,
Lifetime: lifetime,
}
return sess
}
func (p *provider) loadSessionFromDB(sid string) (memstore.Store, LifeTime) {
var (
store memstore.Store
lifetime LifeTime
firstValidIdx = 1
)
for i, n := 0, len(p.databases); i < n; i++ {
storeDB := p.databases[i].Load(sid)
if storeDB.Lifetime.HasExpired() { // if expired then skip this db
firstValidIdx++
continue
}
if lifetime.IsZero() {
// update the lifetime to the most valid
lifetime = storeDB.Lifetime
}
if n == firstValidIdx {
// if one database then set the store as it is
store = storeDB.Values
} else {
// else append this database's key-value pairs
// to the store
storeDB.Values.Visit(func(key string, value interface{}) {
store.Save(key, value, false)
})
}
}
// default to memstore if no other store given.
// if store == nil {
// store = &memstore.Store{}
// }
// Note: if one database and it's being expired then the lifetime will be zero(unlimited)
// this by itself is wrong but on the `newSession` we make check of this case too and update the lifetime
// if the configuration has expiration registered.
/// TODO: bug on destroy doesn't being remove the file
// we will have to see it, it's not db's problem it's here on provider destroy or lifetime onExpire.
return store, lifetime
}
// Init creates the session and returns it
func (p *provider) Init(sid string, expires time.Duration) *Session {
newSession := p.newSession(sid, expires)
@@ -165,7 +90,7 @@ func (p *provider) UpdateExpiration(sid string, expires time.Duration) bool {
return false
}
sess.lifetime.Shift(expires)
sess.Lifetime.Shift(expires)
return true
}
@@ -207,7 +132,5 @@ func (p *provider) DestroyAll() {
func (p *provider) deleteSession(sess *Session) {
delete(p.sessions, sess.sid)
if len(p.databases) > 0 {
syncDatabases(p.databases, newSyncPayload(sess, ActionDestroy))
}
p.db.Release(sess.sid)
}