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:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user