1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-18 02:17:05 +00:00

SetImmutable for sessions and context's values. https://github.com/iris-contrib/community-board/issues/5

New package "memstore" created, read it to see how I made it.


Former-commit-id: 9edc344b938786b2ef68defec03c44259a2d539c
This commit is contained in:
kataras
2017-06-08 03:39:15 +03:00
parent 5e00c50c37
commit 14e7751d21
14 changed files with 455 additions and 268 deletions

View File

@@ -7,6 +7,8 @@ package sessions
import (
"sync"
"time"
"github.com/kataras/iris/core/memstore"
)
type (
@@ -44,7 +46,7 @@ func (p *provider) newSession(sid string, expires time.Duration) *session {
sess := &session{
sid: sid,
provider: p,
values: p.loadSessionValues(sid),
values: p.loadSessionValuesFromDB(sid),
flashes: make(map[string]*flashMessage),
}
@@ -60,20 +62,32 @@ func (p *provider) newSession(sid string, expires time.Duration) *session {
return sess
}
func (p *provider) loadSessionValues(sid string) map[string]interface{} {
// can return nil
func (p *provider) loadSessionValuesFromDB(sid string) memstore.Store {
var store memstore.Store
for i, n := 0, len(p.databases); i < n; i++ {
if dbValues := p.databases[i].Load(sid); dbValues != nil && len(dbValues) > 0 {
return dbValues // return the first non-empty from the registered stores.
for k, v := range dbValues {
store.Set(k, v)
}
}
}
values := make(map[string]interface{})
return values
return store
}
func (p *provider) updateDatabases(sid string, newValues map[string]interface{}) {
for i, n := 0, len(p.databases); i < n; i++ {
p.databases[i].Update(sid, newValues)
func (p *provider) updateDatabases(sid string, store memstore.Store) {
if l := store.Len(); l > 0 {
mapValues := make(map[string]interface{}, l)
store.Visit(func(k string, v interface{}) {
mapValues[k] = v
})
for i, n := 0, len(p.databases); i < n; i++ {
p.databases[i].Update(sid, mapValues)
}
}
}

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/kataras/iris/core/errors"
"github.com/kataras/iris/core/memstore"
)
type (
@@ -18,7 +19,7 @@ type (
// implements the context.Session interface
session struct {
sid string
values map[string]interface{} // here are the real values
values memstore.Store // here are the real values
// we could set the flash messages inside values but this will bring us more problems
// because of session databases and because of
// users may want to get all sessions and save them or display them
@@ -45,10 +46,10 @@ func (s *session) ID() string {
return s.sid
}
// Get returns the value of an entry by its key
// Get returns a value based on its "key".
func (s *session) Get(key string) interface{} {
s.mu.RLock()
value := s.values[key]
value := s.values.Get(key)
s.mu.RUnlock()
return value
@@ -215,8 +216,8 @@ func (s *session) GetBoolean(key string) (bool, error) {
func (s *session) GetAll() map[string]interface{} {
items := make(map[string]interface{}, len(s.values))
s.mu.RLock()
for key, v := range s.values {
items[key] = v
for _, kv := range s.values {
items[kv.Key] = kv.Value()
}
s.mu.RUnlock()
return items
@@ -237,21 +238,36 @@ func (s *session) GetFlashes() map[string]interface{} {
// VisitAll loop each one entry and calls the callback function func(key,value)
func (s *session) VisitAll(cb func(k string, v interface{})) {
for key := range s.values {
cb(key, s.values[key])
}
s.values.Visit(cb)
}
// Set fills the session with an entry, it receives a key and a value
// returns an error, which is always nil
func (s *session) Set(key string, value interface{}) {
func (s *session) set(key string, value interface{}, immutable bool) {
s.mu.Lock()
s.values[key] = value
if immutable {
s.values.Set(key, value)
} else {
s.values.SetImmutable(key, value)
}
s.mu.Unlock()
s.updateDatabases()
}
// Set fills the session with an entry"value", based on its "key".
func (s *session) Set(key string, value interface{}) {
s.set(key, value, false)
}
// SetImmutable fills the session with an entry "value", based on its "key".
// Unlike `Set`, the output value cannot be changed by the caller later on (when .Get)
// An Immutable entry should be only changed with a `SetImmutable`, simple `Set` will not work
// if the entry was immutable, for your own safety.
// Use it consistently, it's far slower than `Set`.
// Read more about muttable and immutable go types: https://stackoverflow.com/a/8021081
func (s *session) SetImmutable(key string, value interface{}) {
s.set(key, value, true)
}
// SetFlash sets a flash message by its key.
//
// A flash message is used in order to keep a message in session through one or several requests of the same user.
@@ -278,13 +294,15 @@ func (s *session) SetFlash(key string, value interface{}) {
s.mu.Unlock()
}
// Delete removes an entry by its key
func (s *session) Delete(key string) {
// Delete removes an entry by its key,
// returns true if actually something was removed.
func (s *session) Delete(key string) bool {
s.mu.Lock()
delete(s.values, key)
removed := s.values.Remove(key)
s.mu.Unlock()
s.updateDatabases()
return removed
}
func (s *session) updateDatabases() {
@@ -301,9 +319,7 @@ func (s *session) DeleteFlash(key string) {
// Clear removes all entries
func (s *session) Clear() {
s.mu.Lock()
for key := range s.values {
delete(s.values, key)
}
s.values.Reset()
s.mu.Unlock()
s.updateDatabases()

View File

@@ -47,8 +47,9 @@ type (
GetFlashes() map[string]interface{}
VisitAll(cb func(k string, v interface{}))
Set(string, interface{})
SetImmutable(key string, value interface{})
SetFlash(string, interface{})
Delete(string)
Delete(string) bool
DeleteFlash(string)
Clear()
ClearFlashes()