mirror of
https://gitee.com/johng/gf.git
synced 2024-11-29 18:57:44 +08:00
improve session Manager and default Storage implements for package gsession; fix issue #1781
This commit is contained in:
parent
99f1e69469
commit
48fddcd5e7
@ -186,7 +186,7 @@ func (s *Server) Start() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
s.config.SessionStorage = gsession.NewStorageFile(path)
|
||||
s.config.SessionStorage = gsession.NewStorageFile(path, s.config.SessionMaxAge)
|
||||
}
|
||||
// Initialize session manager when start running.
|
||||
s.sessionManager = gsession.New(
|
||||
|
@ -9,35 +9,24 @@ package gsession
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
)
|
||||
|
||||
// Manager for sessions.
|
||||
type Manager struct {
|
||||
ttl time.Duration // TTL for sessions.
|
||||
storage Storage // Storage interface for session storage.
|
||||
|
||||
// sessionData is the memory data cache for session TTL,
|
||||
// which is available only if the Storage does not store any session data in synchronizing.
|
||||
// Please refer to the implements of StorageFile, StorageMemory and StorageRedis.
|
||||
//
|
||||
// Its value is type of `*gmap.StrAnyMap`.
|
||||
sessionData *gcache.Cache
|
||||
}
|
||||
|
||||
// New creates and returns a new session manager.
|
||||
func New(ttl time.Duration, storage ...Storage) *Manager {
|
||||
m := &Manager{
|
||||
ttl: ttl,
|
||||
sessionData: gcache.New(),
|
||||
ttl: ttl,
|
||||
}
|
||||
if len(storage) > 0 && storage[0] != nil {
|
||||
m.storage = storage[0]
|
||||
} else {
|
||||
m.storage = NewStorageFile()
|
||||
// It uses StorageFile in default.
|
||||
m.storage = NewStorageFile(DefaultStorageFilePath, ttl)
|
||||
}
|
||||
return m
|
||||
}
|
||||
@ -72,16 +61,7 @@ func (m *Manager) SetTTL(ttl time.Duration) {
|
||||
m.ttl = ttl
|
||||
}
|
||||
|
||||
// TTL returns the TTL of the session manager.
|
||||
func (m *Manager) TTL() time.Duration {
|
||||
// GetTTL returns the TTL of the session manager.
|
||||
func (m *Manager) GetTTL() time.Duration {
|
||||
return m.ttl
|
||||
}
|
||||
|
||||
// UpdateSessionTTL updates the ttl for given session.
|
||||
func (m *Manager) UpdateSessionTTL(sessionId string, data *gmap.StrAnyMap) {
|
||||
ctx := context.Background()
|
||||
err := m.sessionData.Set(ctx, sessionId, data, m.ttl)
|
||||
if err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
}
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ import (
|
||||
// for functionality implements.
|
||||
type Session struct {
|
||||
id string // Session id. It retrieves the session if id is custom specified.
|
||||
ctx context.Context // Context for current session. Please note that, session live along with context.
|
||||
data *gmap.StrAnyMap // Session data.
|
||||
ctx context.Context // Context for current session. Please note that, session lives along with context.
|
||||
data *gmap.StrAnyMap // Current Session data, which is retrieved from Storage.
|
||||
dirty bool // Used to mark session is modified.
|
||||
start bool // Used to mark session is started.
|
||||
manager *Manager // Parent manager.
|
||||
manager *Manager // Parent session Manager.
|
||||
|
||||
// idFunc is a callback function used for creating custom session id.
|
||||
// This is called if session id is empty ever when session starts.
|
||||
@ -40,20 +40,11 @@ func (s *Session) init() error {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
// Session retrieving.
|
||||
if s.id != "" {
|
||||
// Retrieve memory session data from manager.
|
||||
var v *gvar.Var
|
||||
v, err = s.manager.sessionData.Get(s.ctx, s.id)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
return err
|
||||
}
|
||||
if v != nil {
|
||||
s.data = v.Val().(*gmap.StrAnyMap)
|
||||
intlog.Print(s.ctx, "session init data:", s.data)
|
||||
}
|
||||
// Retrieve stored session data from storage.
|
||||
if s.manager.storage != nil {
|
||||
s.data, err = s.manager.storage.GetSession(s.ctx, s.id, s.manager.ttl, s.data)
|
||||
s.data, err = s.manager.storage.GetSession(s.ctx, s.id, s.manager.GetTTL())
|
||||
if err != nil && err != ErrorDisabled {
|
||||
intlog.Errorf(s.ctx, `session restoring failed for id "%s": %+v`, s.id, err)
|
||||
return err
|
||||
@ -91,34 +82,32 @@ func (s *Session) init() error {
|
||||
//
|
||||
// NOTE that this function must be called ever after a session request done.
|
||||
func (s *Session) Close() error {
|
||||
if s.manager.storage == nil {
|
||||
return nil
|
||||
}
|
||||
if s.start && s.id != "" {
|
||||
size := s.data.Size()
|
||||
if s.manager.storage != nil {
|
||||
if s.dirty {
|
||||
err := s.manager.storage.SetSession(s.ctx, s.id, s.data, s.manager.ttl)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
return err
|
||||
}
|
||||
} else if size > 0 {
|
||||
err := s.manager.storage.UpdateTTL(s.ctx, s.id, s.manager.ttl)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
return err
|
||||
}
|
||||
if s.dirty {
|
||||
err := s.manager.storage.SetSession(s.ctx, s.id, s.data, s.manager.ttl)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
return err
|
||||
}
|
||||
} else if size > 0 {
|
||||
err := s.manager.storage.UpdateTTL(s.ctx, s.id, s.manager.ttl)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.dirty || size > 0 {
|
||||
s.manager.UpdateSessionTTL(s.id, s.data)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set sets sessionIdToRedisKey-value pair to this session.
|
||||
func (s *Session) Set(key string, value interface{}) error {
|
||||
if err := s.init(); err != nil {
|
||||
// Set sets key-value pair to this session.
|
||||
func (s *Session) Set(key string, value interface{}) (err error) {
|
||||
if err = s.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.manager.storage.Set(s.ctx, s.id, key, value, s.manager.ttl); err != nil {
|
||||
if err = s.manager.storage.Set(s.ctx, s.id, key, value, s.manager.ttl); err != nil {
|
||||
if err == ErrorDisabled {
|
||||
s.data.Set(key, value)
|
||||
} else {
|
||||
@ -130,11 +119,11 @@ func (s *Session) Set(key string, value interface{}) error {
|
||||
}
|
||||
|
||||
// SetMap batch sets the session using map.
|
||||
func (s *Session) SetMap(data map[string]interface{}) error {
|
||||
if err := s.init(); err != nil {
|
||||
func (s *Session) SetMap(data map[string]interface{}) (err error) {
|
||||
if err = s.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.manager.storage.SetMap(s.ctx, s.id, data, s.manager.ttl); err != nil {
|
||||
if err = s.manager.storage.SetMap(s.ctx, s.id, data, s.manager.ttl); err != nil {
|
||||
if err == ErrorDisabled {
|
||||
s.data.Sets(data)
|
||||
} else {
|
||||
@ -145,16 +134,16 @@ func (s *Session) SetMap(data map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes sessionIdToRedisKey along with its value from this session.
|
||||
func (s *Session) Remove(keys ...string) error {
|
||||
// Remove removes key along with its value from this session.
|
||||
func (s *Session) Remove(keys ...string) (err error) {
|
||||
if s.id == "" {
|
||||
return nil
|
||||
}
|
||||
if err := s.init(); err != nil {
|
||||
if err = s.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range keys {
|
||||
if err := s.manager.storage.Remove(s.ctx, s.id, key); err != nil {
|
||||
if err = s.manager.storage.Remove(s.ctx, s.id, key); err != nil {
|
||||
if err == ErrorDisabled {
|
||||
s.data.Remove(key)
|
||||
} else {
|
||||
@ -166,7 +155,7 @@ func (s *Session) Remove(keys ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveAll deletes all sessionIdToRedisKey-value pairs from this session.
|
||||
// RemoveAll deletes all key-value pairs from this session.
|
||||
func (s *Session) RemoveAll() (err error) {
|
||||
if s.id == "" {
|
||||
return nil
|
||||
@ -189,8 +178,8 @@ func (s *Session) RemoveAll() (err error) {
|
||||
|
||||
// Id returns the session id for this session.
|
||||
// It creates and returns a new session id if the session id is not passed in initialization.
|
||||
func (s *Session) Id() (string, error) {
|
||||
if err := s.init(); err != nil {
|
||||
func (s *Session) Id() (id string, err error) {
|
||||
if err = s.init(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s.id, nil
|
||||
@ -218,47 +207,47 @@ func (s *Session) SetIdFunc(f func(ttl time.Duration) string) error {
|
||||
|
||||
// Data returns all data as map.
|
||||
// Note that it's using value copy internally for concurrent-safe purpose.
|
||||
func (s *Session) Data() (map[string]interface{}, error) {
|
||||
func (s *Session) Data() (sessionData map[string]interface{}, err error) {
|
||||
if s.id == "" {
|
||||
return map[string]interface{}{}, nil
|
||||
}
|
||||
if err := s.init(); err != nil {
|
||||
if err = s.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := s.manager.storage.Data(s.ctx, s.id)
|
||||
sessionData, err = s.manager.storage.Data(s.ctx, s.id)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
intlog.Errorf(s.ctx, `%+v`, err)
|
||||
}
|
||||
if data != nil {
|
||||
return data, nil
|
||||
if sessionData != nil {
|
||||
return sessionData, nil
|
||||
}
|
||||
return s.data.Map(), nil
|
||||
}
|
||||
|
||||
// Size returns the size of the session.
|
||||
func (s *Session) Size() (int, error) {
|
||||
func (s *Session) Size() (size int, err error) {
|
||||
if s.id == "" {
|
||||
return 0, nil
|
||||
}
|
||||
if err := s.init(); err != nil {
|
||||
if err = s.init(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
size, err := s.manager.storage.GetSize(s.ctx, s.id)
|
||||
size, err = s.manager.storage.GetSize(s.ctx, s.id)
|
||||
if err != nil && err != ErrorDisabled {
|
||||
intlog.Errorf(s.ctx, `%+v`, err)
|
||||
}
|
||||
if size >= 0 {
|
||||
if size > 0 {
|
||||
return size, nil
|
||||
}
|
||||
return s.data.Size(), nil
|
||||
}
|
||||
|
||||
// Contains checks whether sessionIdToRedisKey exist in the session.
|
||||
func (s *Session) Contains(key string) (bool, error) {
|
||||
// Contains checks whether key exist in the session.
|
||||
func (s *Session) Contains(key string) (ok bool, err error) {
|
||||
if s.id == "" {
|
||||
return false, nil
|
||||
}
|
||||
if err := s.init(); err != nil {
|
||||
if err = s.init(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
v, err := s.Get(key)
|
||||
@ -273,14 +262,14 @@ func (s *Session) IsDirty() bool {
|
||||
return s.dirty
|
||||
}
|
||||
|
||||
// Get retrieves session value with given sessionIdToRedisKey.
|
||||
// It returns `def` if the sessionIdToRedisKey does not exist in the session if `def` is given,
|
||||
// Get retrieves session value with given key.
|
||||
// It returns `def` if the key does not exist in the session if `def` is given,
|
||||
// or else it returns nil.
|
||||
func (s *Session) Get(key string, def ...interface{}) (*gvar.Var, error) {
|
||||
func (s *Session) Get(key string, def ...interface{}) (value *gvar.Var, err error) {
|
||||
if s.id == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if err := s.init(); err != nil {
|
||||
if err = s.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := s.manager.storage.Get(s.ctx, s.id, key)
|
||||
@ -291,7 +280,7 @@ func (s *Session) Get(key string, def ...interface{}) (*gvar.Var, error) {
|
||||
if v != nil {
|
||||
return gvar.New(v), nil
|
||||
}
|
||||
if v := s.data.Get(key); v != nil {
|
||||
if v = s.data.Get(key); v != nil {
|
||||
return gvar.New(v), nil
|
||||
}
|
||||
if len(def) > 0 {
|
||||
|
@ -19,28 +19,28 @@ type Storage interface {
|
||||
// This function can be used for custom session creation.
|
||||
New(ctx context.Context, ttl time.Duration) (sessionId string, err error)
|
||||
|
||||
// Get retrieves and returns session value with given sessionIdToRedisKey.
|
||||
// It returns nil if the sessionIdToRedisKey does not exist in the session.
|
||||
// Get retrieves and returns certain session value with given key.
|
||||
// It returns nil if the key does not exist in the session.
|
||||
Get(ctx context.Context, sessionId string, key string) (value interface{}, err error)
|
||||
|
||||
// GetSize retrieves and returns the size of sessionIdToRedisKey-value pairs from storage.
|
||||
// GetSize retrieves and returns the size of key-value pairs from storage.
|
||||
GetSize(ctx context.Context, sessionId string) (size int, err error)
|
||||
|
||||
// Data retrieves all sessionIdToRedisKey-value pairs as map from storage.
|
||||
Data(ctx context.Context, sessionId string) (data map[string]interface{}, err error)
|
||||
// Data retrieves all key-value pairs as map from storage.
|
||||
Data(ctx context.Context, sessionId string) (sessionData map[string]interface{}, err error)
|
||||
|
||||
// Set sets one sessionIdToRedisKey-value session pair to the storage.
|
||||
// Set sets one key-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id.
|
||||
Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error
|
||||
|
||||
// SetMap batch sets sessionIdToRedisKey-value session pairs as map to the storage.
|
||||
// SetMap batch sets key-value session pairs as map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id.
|
||||
SetMap(ctx context.Context, sessionId string, data map[string]interface{}, ttl time.Duration) error
|
||||
SetMap(ctx context.Context, sessionId string, mapData map[string]interface{}, ttl time.Duration) error
|
||||
|
||||
// Remove deletes sessionIdToRedisKey with its value from storage.
|
||||
// Remove deletes key-value pair from specified session from storage.
|
||||
Remove(ctx context.Context, sessionId string, key string) error
|
||||
|
||||
// RemoveAll deletes all sessionIdToRedisKey-value pairs from storage.
|
||||
// RemoveAll deletes session from storage.
|
||||
RemoveAll(ctx context.Context, sessionId string) error
|
||||
|
||||
// GetSession returns the session data as `*gmap.StrAnyMap` for given session from storage.
|
||||
@ -49,13 +49,14 @@ type Storage interface {
|
||||
// The parameter `data` is the current old session data stored in memory,
|
||||
// and for some storage it might be nil if memory storage is disabled.
|
||||
//
|
||||
// This function is called ever when session starts. It returns nil if the TTL is exceeded.
|
||||
GetSession(ctx context.Context, sessionId string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error)
|
||||
// This function is called ever when session starts.
|
||||
// It returns nil if the session does not exist or its TTL is expired.
|
||||
GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error)
|
||||
|
||||
// SetSession updates the data for specified session id.
|
||||
// This function is called ever after session, which is changed dirty, is closed.
|
||||
// This copy all session data map from memory to storage.
|
||||
SetSession(ctx context.Context, sessionId string, data *gmap.StrAnyMap, ttl time.Duration) error
|
||||
SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error
|
||||
|
||||
// UpdateTTL updates the TTL for specified session id.
|
||||
// This function is called ever after session, which is not dirty, is closed.
|
||||
|
86
os/gsession/gsession_storage_base.go
Normal file
86
os/gsession/gsession_storage_base.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gsession
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
)
|
||||
|
||||
// StorageBase is a base implement for Session Storage.
|
||||
type StorageBase struct{}
|
||||
|
||||
// New creates a session id.
|
||||
// This function can be used for custom session creation.
|
||||
func (s *StorageBase) New(ctx context.Context, ttl time.Duration) (id string, err error) {
|
||||
return "", ErrorDisabled
|
||||
}
|
||||
|
||||
// Get retrieves certain session value with given key.
|
||||
// It returns nil if the key does not exist in the session.
|
||||
func (s *StorageBase) Get(ctx context.Context, sessionId string, key string) (value interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// Data retrieves all key-value pairs as map from storage.
|
||||
func (s *StorageBase) Data(ctx context.Context, sessionId string) (sessionData map[string]interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// GetSize retrieves the size of key-value pairs from storage.
|
||||
func (s *StorageBase) GetSize(ctx context.Context, sessionId string) (size int, err error) {
|
||||
return 0, ErrorDisabled
|
||||
}
|
||||
|
||||
// Set sets key-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).
|
||||
func (s *StorageBase) Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// SetMap batch sets key-value session pairs with map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).
|
||||
func (s *StorageBase) SetMap(ctx context.Context, sessionId string, mapData map[string]interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// Remove deletes key with its value from storage.
|
||||
func (s *StorageBase) Remove(ctx context.Context, sessionId string, key string) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// RemoveAll deletes session from storage.
|
||||
func (s *StorageBase) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.
|
||||
//
|
||||
// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.
|
||||
// The parameter `data` is the current old session data stored in memory,
|
||||
// and for some storage it might be nil if memory storage is disabled.
|
||||
//
|
||||
// This function is called ever when session starts.
|
||||
func (s *StorageBase) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// SetSession updates the data map for specified session id.
|
||||
// This function is called ever after session, which is changed dirty, is closed.
|
||||
// This copy all session data map from memory to storage.
|
||||
func (s *StorageBase) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// UpdateTTL updates the TTL for specified session id.
|
||||
// This function is called ever after session, which is not dirty, is closed.
|
||||
// It just adds the session id to the async handling queue.
|
||||
func (s *StorageBase) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
@ -8,6 +8,7 @@ package gsession
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@ -26,32 +27,38 @@ import (
|
||||
|
||||
// StorageFile implements the Session Storage interface with file system.
|
||||
type StorageFile struct {
|
||||
path string
|
||||
cryptoKey []byte
|
||||
cryptoEnabled bool
|
||||
updatingIdSet *gset.StrSet
|
||||
StorageBase
|
||||
path string // Session file storage folder path.
|
||||
ttl time.Duration // Session TTL.
|
||||
cryptoKey []byte // Used when enable crypto feature.
|
||||
cryptoEnabled bool // Used when enable crypto feature.
|
||||
updatingIdSet *gset.StrSet // To be batched updated session id set.
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultStorageFileCryptoEnabled = false
|
||||
DefaultStorageFileLoopInterval = 10 * time.Second
|
||||
DefaultStorageFileCryptoEnabled = false
|
||||
DefaultStorageFileUpdateTTLInterval = 10 * time.Second
|
||||
DefaultStorageFileClearExpiredInterval = time.Hour
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultStorageFilePath = gfile.Temp("gsessions")
|
||||
DefaultStorageFileCryptoKey = []byte("Session storage file crypto sessionIdToRedisKey!")
|
||||
DefaultStorageFileCryptoKey = []byte("Session storage file crypto key!")
|
||||
)
|
||||
|
||||
// NewStorageFile creates and returns a file storage object for session.
|
||||
func NewStorageFile(path ...string) *StorageFile {
|
||||
storagePath := DefaultStorageFilePath
|
||||
if len(path) > 0 && path[0] != "" {
|
||||
storagePath, _ = gfile.Search(path[0])
|
||||
func NewStorageFile(path string, ttl time.Duration) *StorageFile {
|
||||
var (
|
||||
ctx = context.TODO()
|
||||
storagePath = DefaultStorageFilePath
|
||||
)
|
||||
if path != "" {
|
||||
storagePath, _ = gfile.Search(path)
|
||||
if storagePath == "" {
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" does not exist`, path[0]))
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" does not exist`, path))
|
||||
}
|
||||
if !gfile.IsWritable(storagePath) {
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" is not writable`, path[0]))
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" is not writable`, path))
|
||||
}
|
||||
}
|
||||
if storagePath != "" {
|
||||
@ -61,17 +68,19 @@ func NewStorageFile(path ...string) *StorageFile {
|
||||
}
|
||||
s := &StorageFile{
|
||||
path: storagePath,
|
||||
ttl: ttl,
|
||||
cryptoKey: DefaultStorageFileCryptoKey,
|
||||
cryptoEnabled: DefaultStorageFileCryptoEnabled,
|
||||
updatingIdSet: gset.NewStrSet(true),
|
||||
}
|
||||
|
||||
gtimer.AddSingleton(context.Background(), DefaultStorageFileLoopInterval, s.updateSessionTimely)
|
||||
gtimer.AddSingleton(ctx, DefaultStorageFileUpdateTTLInterval, s.timelyUpdateSessionTTL)
|
||||
gtimer.AddSingleton(ctx, DefaultStorageFileClearExpiredInterval, s.timelyClearExpiredSessionFile)
|
||||
return s
|
||||
}
|
||||
|
||||
// updateSessionTimely batch updates the TTL for sessions timely.
|
||||
func (s *StorageFile) updateSessionTimely(ctx context.Context) {
|
||||
// timelyUpdateSessionTTL batch updates the TTL for sessions timely.
|
||||
func (s *StorageFile) timelyUpdateSessionTTL(ctx context.Context) {
|
||||
var (
|
||||
sessionId string
|
||||
err error
|
||||
@ -87,8 +96,22 @@ func (s *StorageFile) updateSessionTimely(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetCryptoKey sets the crypto sessionIdToRedisKey for session storage.
|
||||
// The crypto sessionIdToRedisKey is used when crypto feature is enabled.
|
||||
// timelyClearExpiredSessionFile deletes all expired files timely.
|
||||
func (s *StorageFile) timelyClearExpiredSessionFile(ctx context.Context) {
|
||||
files, err := gfile.ScanDirFile(s.path, "*.session", false)
|
||||
if err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
return
|
||||
}
|
||||
for _, file := range files {
|
||||
if err = s.checkAndClearSessionFile(ctx, file); err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetCryptoKey sets the crypto key for session storage.
|
||||
// The crypto key is used when crypto feature is enabled.
|
||||
func (s *StorageFile) SetCryptoKey(key []byte) {
|
||||
s.cryptoKey = key
|
||||
}
|
||||
@ -99,50 +122,11 @@ func (s *StorageFile) SetCryptoEnabled(enabled bool) {
|
||||
}
|
||||
|
||||
// sessionFilePath returns the storage file path for given session id.
|
||||
func (s *StorageFile) sessionFilePath(id string) string {
|
||||
return gfile.Join(s.path, id)
|
||||
func (s *StorageFile) sessionFilePath(sessionId string) string {
|
||||
return gfile.Join(s.path, sessionId) + ".session"
|
||||
}
|
||||
|
||||
// New creates a session id.
|
||||
// This function can be used for custom session creation.
|
||||
func (s *StorageFile) New(ctx context.Context, ttl time.Duration) (id string, err error) {
|
||||
return "", ErrorDisabled
|
||||
}
|
||||
|
||||
// Get retrieves session value with given sessionIdToRedisKey.
|
||||
// It returns nil if the sessionIdToRedisKey does not exist in the session.
|
||||
func (s *StorageFile) Get(ctx context.Context, sessionId string, key string) (value interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// Data retrieves all sessionIdToRedisKey-value pairs as map from storage.
|
||||
func (s *StorageFile) Data(ctx context.Context, sessionId string) (data map[string]interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// GetSize retrieves the size of sessionIdToRedisKey-value pairs from storage.
|
||||
func (s *StorageFile) GetSize(ctx context.Context, sessionId string) (size int, err error) {
|
||||
return -1, ErrorDisabled
|
||||
}
|
||||
|
||||
// Set sets sessionIdToRedisKey-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id (not for the sessionIdToRedisKey-value pair).
|
||||
func (s *StorageFile) Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// SetMap batch sets sessionIdToRedisKey-value session pairs with map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id(not for the sessionIdToRedisKey-value pair).
|
||||
func (s *StorageFile) SetMap(ctx context.Context, sessionId string, data map[string]interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// Remove deletes sessionIdToRedisKey with its value from storage.
|
||||
func (s *StorageFile) Remove(ctx context.Context, sessionId string, key string) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// RemoveAll deletes all sessionIdToRedisKey-value pairs from storage.
|
||||
// RemoveAll deletes all key-value pairs from storage.
|
||||
func (s *StorageFile) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
return gfile.Remove(s.sessionFilePath(sessionId))
|
||||
}
|
||||
@ -154,10 +138,7 @@ func (s *StorageFile) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
// and for some storage it might be nil if memory storage is disabled.
|
||||
//
|
||||
// This function is called ever when session starts.
|
||||
func (s *StorageFile) GetSession(ctx context.Context, sessionId string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
|
||||
if data != nil {
|
||||
return data, nil
|
||||
}
|
||||
func (s *StorageFile) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (sessionData *gmap.StrAnyMap, err error) {
|
||||
var (
|
||||
path = s.sessionFilePath(sessionId)
|
||||
content = gfile.GetBytes(path)
|
||||
@ -168,7 +149,6 @@ func (s *StorageFile) GetSession(ctx context.Context, sessionId string, ttl time
|
||||
if timestampMilli+ttl.Nanoseconds()/1e6 < gtime.TimestampMilli() {
|
||||
return nil, nil
|
||||
}
|
||||
var err error
|
||||
content = content[8:]
|
||||
// Decrypt with AES.
|
||||
if s.cryptoEnabled {
|
||||
@ -192,10 +172,10 @@ func (s *StorageFile) GetSession(ctx context.Context, sessionId string, ttl time
|
||||
// SetSession updates the data map for specified session id.
|
||||
// This function is called ever after session, which is changed dirty, is closed.
|
||||
// This copy all session data map from memory to storage.
|
||||
func (s *StorageFile) SetSession(ctx context.Context, sessionId string, data *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
intlog.Printf(ctx, "StorageFile.SetSession: %s, %v, %v", sessionId, data, ttl)
|
||||
func (s *StorageFile) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
intlog.Printf(ctx, "StorageFile.SetSession: %s, %v, %v", sessionId, sessionData, ttl)
|
||||
path := s.sessionFilePath(sessionId)
|
||||
content, err := json.Marshal(data)
|
||||
content, err := json.Marshal(sessionData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -229,7 +209,7 @@ func (s *StorageFile) SetSession(ctx context.Context, sessionId string, data *gm
|
||||
// It just adds the session id to the async handling queue.
|
||||
func (s *StorageFile) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {
|
||||
intlog.Printf(ctx, "StorageFile.UpdateTTL: %s, %v", sessionId, ttl)
|
||||
if ttl >= DefaultStorageFileLoopInterval {
|
||||
if ttl >= DefaultStorageFileUpdateTTLInterval {
|
||||
s.updatingIdSet.Add(sessionId)
|
||||
}
|
||||
return nil
|
||||
@ -249,3 +229,40 @@ func (s *StorageFile) updateSessionTTl(ctx context.Context, sessionId string) er
|
||||
}
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
func (s *StorageFile) checkAndClearSessionFile(ctx context.Context, path string) (err error) {
|
||||
var (
|
||||
file *os.File
|
||||
readBytesCount int
|
||||
timestampMilliBytes = make([]byte, 8)
|
||||
)
|
||||
file, err = gfile.OpenWithFlag(path, os.O_RDONLY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
// Read the session file updated timestamp in milliseconds.
|
||||
readBytesCount, err = file.Read(timestampMilliBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if readBytesCount != 8 {
|
||||
return gerror.Newf(`invalid read bytes count "%d", expect "8"`, readBytesCount)
|
||||
}
|
||||
// Remove expired session file.
|
||||
var (
|
||||
ttlInMilliseconds = s.ttl.Nanoseconds() / 1e6
|
||||
fileTimestampMilli = gbinary.DecodeToInt64(timestampMilliBytes)
|
||||
currentTimestampMilli = gtime.TimestampMilli()
|
||||
)
|
||||
if fileTimestampMilli+ttlInMilliseconds < currentTimestampMilli {
|
||||
intlog.PrintFunc(ctx, func() string {
|
||||
return fmt.Sprintf(
|
||||
`clear expired session file "%s": updated datetime "%s", ttl "%s"`,
|
||||
path, gtime.NewFromTimeStamp(fileTimestampMilli), s.ttl,
|
||||
)
|
||||
})
|
||||
return gfile.Remove(path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -11,58 +11,32 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
)
|
||||
|
||||
// StorageMemory implements the Session Storage interface with memory.
|
||||
type StorageMemory struct{}
|
||||
type StorageMemory struct {
|
||||
StorageBase
|
||||
// cache is the memory data cache for session TTL,
|
||||
// which is available only if the Storage does not store any session data in synchronizing.
|
||||
// Please refer to the implements of StorageFile, StorageMemory and StorageRedis.
|
||||
//
|
||||
// Its value is type of `*gmap.StrAnyMap`.
|
||||
cache *gcache.Cache
|
||||
}
|
||||
|
||||
// NewStorageMemory creates and returns a file storage object for session.
|
||||
func NewStorageMemory() *StorageMemory {
|
||||
return &StorageMemory{}
|
||||
return &StorageMemory{
|
||||
cache: gcache.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a session id.
|
||||
// This function can be used for custom session creation.
|
||||
func (s *StorageMemory) New(ctx context.Context, ttl time.Duration) (id string, err error) {
|
||||
return "", ErrorDisabled
|
||||
}
|
||||
|
||||
// Get retrieves session value with given sessionIdToRedisKey.
|
||||
// It returns nil if the sessionIdToRedisKey does not exist in the session.
|
||||
func (s *StorageMemory) Get(ctx context.Context, sessionId string, key string) (value interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// Data retrieves all sessionIdToRedisKey-value pairs as map from storage.
|
||||
func (s *StorageMemory) Data(ctx context.Context, sessionId string) (data map[string]interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// GetSize retrieves the size of sessionIdToRedisKey-value pairs from storage.
|
||||
func (s *StorageMemory) GetSize(ctx context.Context, sessionId string) (size int, err error) {
|
||||
return -1, ErrorDisabled
|
||||
}
|
||||
|
||||
// Set sets sessionIdToRedisKey-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id (not for the sessionIdToRedisKey-value pair).
|
||||
func (s *StorageMemory) Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// SetMap batch sets sessionIdToRedisKey-value session pairs with map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id(not for the sessionIdToRedisKey-value pair).
|
||||
func (s *StorageMemory) SetMap(ctx context.Context, sessionId string, data map[string]interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// Remove deletes sessionIdToRedisKey with its value from storage.
|
||||
func (s *StorageMemory) Remove(ctx context.Context, sessionId string, key string) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// RemoveAll deletes all sessionIdToRedisKey-value pairs from storage.
|
||||
// RemoveAll deletes session from storage.
|
||||
func (s *StorageMemory) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
return ErrorDisabled
|
||||
_, err := s.cache.Remove(ctx, sessionId)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.
|
||||
@ -72,20 +46,33 @@ func (s *StorageMemory) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
// and for some storage it might be nil if memory storage is disabled.
|
||||
//
|
||||
// This function is called ever when session starts.
|
||||
func (s *StorageMemory) GetSession(ctx context.Context, sessionId string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
|
||||
return data, nil
|
||||
func (s *StorageMemory) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {
|
||||
// Retrieve memory session data from manager.
|
||||
var (
|
||||
v *gvar.Var
|
||||
err error
|
||||
)
|
||||
v, err = s.cache.Get(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v != nil {
|
||||
return v.Val().(*gmap.StrAnyMap), nil
|
||||
}
|
||||
return gmap.NewStrAnyMap(true), nil
|
||||
}
|
||||
|
||||
// SetSession updates the data map for specified session id.
|
||||
// This function is called ever after session, which is changed dirty, is closed.
|
||||
// This copy all session data map from memory to storage.
|
||||
func (s *StorageMemory) SetSession(ctx context.Context, sessionId string, data *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
return nil
|
||||
func (s *StorageMemory) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
return s.cache.Set(ctx, sessionId, sessionData, ttl)
|
||||
}
|
||||
|
||||
// UpdateTTL updates the TTL for specified session id.
|
||||
// This function is called ever after session, which is not dirty, is closed.
|
||||
// It just adds the session id to the async handling queue.
|
||||
func (s *StorageMemory) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {
|
||||
return nil
|
||||
_, err := s.cache.UpdateExpire(ctx, sessionId, ttl)
|
||||
return err
|
||||
}
|
||||
|
@ -19,8 +19,9 @@ import (
|
||||
|
||||
// StorageRedis implements the Session Storage interface with redis.
|
||||
type StorageRedis struct {
|
||||
StorageBase
|
||||
redis *gredis.Redis // Redis client for session storage.
|
||||
prefix string // Redis sessionIdToRedisKey prefix for session id.
|
||||
prefix string // Redis key prefix for session id.
|
||||
updatingIdMap *gmap.StrIntMap // Updating TTL set for session id.
|
||||
}
|
||||
|
||||
@ -55,7 +56,7 @@ func NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis {
|
||||
if sessionId, ttlSeconds = s.updatingIdMap.Pop(); sessionId == "" {
|
||||
break
|
||||
} else {
|
||||
if err = s.doUpdateTTL(context.TODO(), sessionId, ttlSeconds); err != nil {
|
||||
if err = s.doUpdateExpireForSession(context.TODO(), sessionId, ttlSeconds); err != nil {
|
||||
intlog.Errorf(context.TODO(), `%+v`, err)
|
||||
}
|
||||
}
|
||||
@ -65,46 +66,7 @@ func NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis {
|
||||
return s
|
||||
}
|
||||
|
||||
// New creates a session id.
|
||||
// This function can be used for custom session creation.
|
||||
func (s *StorageRedis) New(ctx context.Context, ttl time.Duration) (id string, err error) {
|
||||
return "", ErrorDisabled
|
||||
}
|
||||
|
||||
// Get retrieves session value with given sessionIdToRedisKey.
|
||||
// It returns nil if the sessionIdToRedisKey does not exist in the session.
|
||||
func (s *StorageRedis) Get(ctx context.Context, sessionId string, key string) (value interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// Data retrieves all sessionIdToRedisKey-value pairs as map from storage.
|
||||
func (s *StorageRedis) Data(ctx context.Context, sessionId string) (data map[string]interface{}, err error) {
|
||||
return nil, ErrorDisabled
|
||||
}
|
||||
|
||||
// GetSize retrieves the size of sessionIdToRedisKey-value pairs from storage.
|
||||
func (s *StorageRedis) GetSize(ctx context.Context, sessionId string) (size int, err error) {
|
||||
return -1, ErrorDisabled
|
||||
}
|
||||
|
||||
// Set sets sessionIdToRedisKey-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id (not for the sessionIdToRedisKey-value pair).
|
||||
func (s *StorageRedis) Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// SetMap batch sets sessionIdToRedisKey-value session pairs with map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id(not for the sessionIdToRedisKey-value pair).
|
||||
func (s *StorageRedis) SetMap(ctx context.Context, sessionId string, data map[string]interface{}, ttl time.Duration) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// Remove deletes sessionIdToRedisKey with its value from storage.
|
||||
func (s *StorageRedis) Remove(ctx context.Context, sessionId string, key string) error {
|
||||
return ErrorDisabled
|
||||
}
|
||||
|
||||
// RemoveAll deletes all sessionIdToRedisKey-value pairs from storage.
|
||||
// RemoveAll deletes all key-value pairs from storage.
|
||||
func (s *StorageRedis) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
_, err := s.redis.Do(ctx, "DEL", s.sessionIdToRedisKey(sessionId))
|
||||
return err
|
||||
@ -117,7 +79,7 @@ func (s *StorageRedis) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
// and for some storage it might be nil if memory storage is disabled.
|
||||
//
|
||||
// This function is called ever when session starts.
|
||||
func (s *StorageRedis) GetSession(ctx context.Context, sessionId string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
|
||||
func (s *StorageRedis) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {
|
||||
intlog.Printf(ctx, "StorageRedis.GetSession: %s, %v", sessionId, ttl)
|
||||
r, err := s.redis.Do(ctx, "GET", s.sessionIdToRedisKey(sessionId))
|
||||
if err != nil {
|
||||
@ -134,19 +96,15 @@ func (s *StorageRedis) GetSession(ctx context.Context, sessionId string, ttl tim
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data == nil {
|
||||
return gmap.NewStrAnyMapFrom(m, true), nil
|
||||
}
|
||||
data.Replace(m)
|
||||
return data, nil
|
||||
return gmap.NewStrAnyMapFrom(m, true), nil
|
||||
}
|
||||
|
||||
// SetSession updates the data map for specified session id.
|
||||
// This function is called ever after session, which is changed dirty, is closed.
|
||||
// This copy all session data map from memory to storage.
|
||||
func (s *StorageRedis) SetSession(ctx context.Context, sessionId string, data *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
intlog.Printf(ctx, "StorageRedis.SetSession: %s, %v, %v", sessionId, data, ttl)
|
||||
content, err := json.Marshal(data)
|
||||
func (s *StorageRedis) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
intlog.Printf(ctx, "StorageRedis.SetSession: %s, %v, %v", sessionId, sessionData, ttl)
|
||||
content, err := json.Marshal(sessionData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -166,12 +124,13 @@ func (s *StorageRedis) UpdateTTL(ctx context.Context, sessionId string, ttl time
|
||||
}
|
||||
|
||||
// doUpdateTTL updates the TTL for session id.
|
||||
func (s *StorageRedis) doUpdateTTL(ctx context.Context, sessionId string, ttlSeconds int) error {
|
||||
func (s *StorageRedis) doUpdateExpireForSession(ctx context.Context, sessionId string, ttlSeconds int) error {
|
||||
intlog.Printf(ctx, "StorageRedis.doUpdateTTL: %s, %d", sessionId, ttlSeconds)
|
||||
_, err := s.redis.Do(ctx, "EXPIRE", s.sessionIdToRedisKey(sessionId), ttlSeconds)
|
||||
return err
|
||||
}
|
||||
|
||||
// sessionIdToRedisKey converts and returns the redis key for given session id.
|
||||
func (s *StorageRedis) sessionIdToRedisKey(sessionId string) string {
|
||||
return s.prefix + sessionId
|
||||
}
|
||||
|
@ -18,8 +18,9 @@ import (
|
||||
|
||||
// StorageRedisHashTable implements the Session Storage interface with redis hash table.
|
||||
type StorageRedisHashTable struct {
|
||||
StorageBase
|
||||
redis *gredis.Redis // Redis client for session storage.
|
||||
prefix string // Redis sessionIdToRedisKey prefix for session id.
|
||||
prefix string // Redis key prefix for session id.
|
||||
}
|
||||
|
||||
// NewStorageRedisHashTable creates and returns a redis hash table storage object for session.
|
||||
@ -37,14 +38,8 @@ func NewStorageRedisHashTable(redis *gredis.Redis, prefix ...string) *StorageRed
|
||||
return s
|
||||
}
|
||||
|
||||
// New creates a session id.
|
||||
// This function can be used for custom session creation.
|
||||
func (s *StorageRedisHashTable) New(ctx context.Context, ttl time.Duration) (id string, err error) {
|
||||
return "", ErrorDisabled
|
||||
}
|
||||
|
||||
// Get retrieves session value with given sessionIdToRedisKey.
|
||||
// It returns nil if the sessionIdToRedisKey does not exist in the session.
|
||||
// Get retrieves session value with given key.
|
||||
// It returns nil if the key does not exist in the session.
|
||||
func (s *StorageRedisHashTable) Get(ctx context.Context, sessionId string, key string) (value interface{}, err error) {
|
||||
v, err := s.redis.Do(ctx, "HGET", s.sessionIdToRedisKey(sessionId), key)
|
||||
if err != nil {
|
||||
@ -56,7 +51,7 @@ func (s *StorageRedisHashTable) Get(ctx context.Context, sessionId string, key s
|
||||
return v.String(), nil
|
||||
}
|
||||
|
||||
// Data retrieves all sessionIdToRedisKey-value pairs as map from storage.
|
||||
// Data retrieves all key-value pairs as map from storage.
|
||||
func (s *StorageRedisHashTable) Data(ctx context.Context, sessionId string) (data map[string]interface{}, err error) {
|
||||
v, err := s.redis.Do(ctx, "HGETALL", s.sessionIdToRedisKey(sessionId))
|
||||
if err != nil {
|
||||
@ -74,24 +69,24 @@ func (s *StorageRedisHashTable) Data(ctx context.Context, sessionId string) (dat
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// GetSize retrieves the size of sessionIdToRedisKey-value pairs from storage.
|
||||
// GetSize retrieves the size of key-value pairs from storage.
|
||||
func (s *StorageRedisHashTable) GetSize(ctx context.Context, sessionId string) (size int, err error) {
|
||||
r, err := s.redis.Do(ctx, "HLEN", s.sessionIdToRedisKey(sessionId))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
return 0, err
|
||||
}
|
||||
return r.Int(), nil
|
||||
}
|
||||
|
||||
// Set sets sessionIdToRedisKey-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id (not for the sessionIdToRedisKey-value pair).
|
||||
// Set sets key-value session pair to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).
|
||||
func (s *StorageRedisHashTable) Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error {
|
||||
_, err := s.redis.Do(ctx, "HSET", s.sessionIdToRedisKey(sessionId), key, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetMap batch sets sessionIdToRedisKey-value session pairs with map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id(not for the sessionIdToRedisKey-value pair).
|
||||
// SetMap batch sets key-value session pairs with map to the storage.
|
||||
// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).
|
||||
func (s *StorageRedisHashTable) SetMap(ctx context.Context, sessionId string, data map[string]interface{}, ttl time.Duration) error {
|
||||
array := make([]interface{}, len(data)*2+1)
|
||||
array[0] = s.sessionIdToRedisKey(sessionId)
|
||||
@ -106,13 +101,13 @@ func (s *StorageRedisHashTable) SetMap(ctx context.Context, sessionId string, da
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove deletes sessionIdToRedisKey with its value from storage.
|
||||
// Remove deletes key with its value from storage.
|
||||
func (s *StorageRedisHashTable) Remove(ctx context.Context, sessionId string, key string) error {
|
||||
_, err := s.redis.Do(ctx, "HDEL", s.sessionIdToRedisKey(sessionId), key)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveAll deletes all sessionIdToRedisKey-value pairs from storage.
|
||||
// RemoveAll deletes all key-value pairs from storage.
|
||||
func (s *StorageRedisHashTable) RemoveAll(ctx context.Context, sessionId string) error {
|
||||
_, err := s.redis.Do(ctx, "DEL", s.sessionIdToRedisKey(sessionId))
|
||||
return err
|
||||
@ -125,7 +120,7 @@ func (s *StorageRedisHashTable) RemoveAll(ctx context.Context, sessionId string)
|
||||
// and for some storage it might be nil if memory storage is disabled.
|
||||
//
|
||||
// This function is called ever when session starts.
|
||||
func (s *StorageRedisHashTable) GetSession(ctx context.Context, sessionId string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
|
||||
func (s *StorageRedisHashTable) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {
|
||||
intlog.Printf(ctx, "StorageRedisHashTable.GetSession: %s, %v", sessionId, ttl)
|
||||
r, err := s.redis.Do(ctx, "EXISTS", s.sessionIdToRedisKey(sessionId))
|
||||
if err != nil {
|
||||
@ -140,7 +135,7 @@ func (s *StorageRedisHashTable) GetSession(ctx context.Context, sessionId string
|
||||
// SetSession updates the data map for specified session id.
|
||||
// This function is called ever after session, which is changed dirty, is closed.
|
||||
// This copy all session data map from memory to storage.
|
||||
func (s *StorageRedisHashTable) SetSession(ctx context.Context, sessionId string, data *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
func (s *StorageRedisHashTable) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {
|
||||
intlog.Printf(ctx, "StorageRedisHashTable.SetSession: %s, %v", sessionId, ttl)
|
||||
_, err := s.redis.Do(ctx, "EXPIRE", s.sessionIdToRedisKey(sessionId), int64(ttl.Seconds()))
|
||||
return err
|
||||
@ -155,6 +150,7 @@ func (s *StorageRedisHashTable) UpdateTTL(ctx context.Context, sessionId string,
|
||||
return err
|
||||
}
|
||||
|
||||
// sessionIdToRedisKey converts and returns the redis key for given session id.
|
||||
func (s *StorageRedisHashTable) sessionIdToRedisKey(sessionId string) string {
|
||||
return s.prefix + sessionId
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
|
||||
func ExampleNew() {
|
||||
manager := gsession.New(time.Second)
|
||||
fmt.Println(manager.TTL())
|
||||
fmt.Println(manager.GetTTL())
|
||||
|
||||
// Output:
|
||||
// 1s
|
||||
@ -27,7 +27,7 @@ func ExampleNew() {
|
||||
func ExampleManager_SetStorage() {
|
||||
manager := gsession.New(time.Second)
|
||||
manager.SetStorage(gsession.NewStorageMemory())
|
||||
fmt.Println(manager.TTL())
|
||||
fmt.Println(manager.GetTTL())
|
||||
|
||||
// Output:
|
||||
// 1s
|
||||
@ -39,29 +39,31 @@ func ExampleManager_GetStorage() {
|
||||
fmt.Println(size)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleManager_SetTTL() {
|
||||
manager := gsession.New(time.Second)
|
||||
manager.SetTTL(time.Minute)
|
||||
fmt.Println(manager.TTL())
|
||||
fmt.Println(manager.GetTTL())
|
||||
|
||||
// Output:
|
||||
// 1m0s
|
||||
}
|
||||
|
||||
func ExampleSession_Set() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s := manager.New(gctx.New())
|
||||
fmt.Println(s.Set("sessionIdToRedisKey", "val") == nil)
|
||||
fmt.Println(s.Set("key", "val") == nil)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleSession_SetMap() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s := manager.New(gctx.New())
|
||||
fmt.Println(s.SetMap(map[string]interface{}{}) == nil)
|
||||
|
||||
@ -70,12 +72,13 @@ func ExampleSession_SetMap() {
|
||||
}
|
||||
|
||||
func ExampleSession_Remove() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s1 := manager.New(gctx.New())
|
||||
fmt.Println(s1.Remove("sessionIdToRedisKey"))
|
||||
fmt.Println(s1.Remove("key"))
|
||||
|
||||
s2 := manager.New(gctx.New(), "Remove")
|
||||
fmt.Println(s2.Remove("sessionIdToRedisKey"))
|
||||
fmt.Println(s2.Remove("key"))
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
@ -83,7 +86,8 @@ func ExampleSession_Remove() {
|
||||
}
|
||||
|
||||
func ExampleSession_RemoveAll() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s1 := manager.New(gctx.New())
|
||||
fmt.Println(s1.RemoveAll())
|
||||
|
||||
@ -96,7 +100,8 @@ func ExampleSession_RemoveAll() {
|
||||
}
|
||||
|
||||
func ExampleSession_Id() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s := manager.New(gctx.New(), "Id")
|
||||
id, _ := s.Id()
|
||||
fmt.Println(id)
|
||||
@ -109,7 +114,8 @@ func ExampleSession_SetId() {
|
||||
nilSession := &gsession.Session{}
|
||||
fmt.Println(nilSession.SetId("id"))
|
||||
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s := manager.New(gctx.New())
|
||||
s.Id()
|
||||
fmt.Println(s.SetId("id"))
|
||||
@ -125,7 +131,8 @@ func ExampleSession_SetIdFunc() {
|
||||
return "id"
|
||||
}))
|
||||
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
s := manager.New(gctx.New())
|
||||
s.Id()
|
||||
fmt.Println(s.SetIdFunc(func(ttl time.Duration) string {
|
||||
@ -138,7 +145,8 @@ func ExampleSession_SetIdFunc() {
|
||||
}
|
||||
|
||||
func ExampleSession_Data() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
|
||||
s1 := manager.New(gctx.New())
|
||||
data1, _ := s1.Data()
|
||||
@ -154,7 +162,8 @@ func ExampleSession_Data() {
|
||||
}
|
||||
|
||||
func ExampleSession_Size() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
|
||||
s1 := manager.New(gctx.New())
|
||||
size1, _ := s1.Size()
|
||||
@ -170,7 +179,8 @@ func ExampleSession_Size() {
|
||||
}
|
||||
|
||||
func ExampleSession_Contains() {
|
||||
manager := gsession.New(time.Second, gsession.NewStorageFile())
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
|
||||
s1 := manager.New(gctx.New())
|
||||
notContains, _ := s1.Contains("Contains")
|
||||
@ -186,25 +196,25 @@ func ExampleSession_Contains() {
|
||||
}
|
||||
|
||||
func ExampleStorageFile_SetCryptoKey() {
|
||||
storage := gsession.NewStorageFile()
|
||||
storage.SetCryptoKey([]byte("sessionIdToRedisKey"))
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
storage.SetCryptoKey([]byte("key"))
|
||||
|
||||
size, _ := storage.GetSize(gctx.New(), "id")
|
||||
fmt.Println(size)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStorageFile_SetCryptoEnabled() {
|
||||
storage := gsession.NewStorageFile()
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
storage.SetCryptoEnabled(true)
|
||||
|
||||
size, _ := storage.GetSize(gctx.New(), "id")
|
||||
fmt.Println(size)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStorageFile_UpdateTTL() {
|
||||
@ -212,7 +222,7 @@ func ExampleStorageFile_UpdateTTL() {
|
||||
ctx = gctx.New()
|
||||
)
|
||||
|
||||
storage := gsession.NewStorageFile()
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
fmt.Println(storage.UpdateTTL(ctx, "id", time.Second*15))
|
||||
|
||||
time.Sleep(time.Second * 11)
|
||||
@ -223,7 +233,7 @@ func ExampleStorageFile_UpdateTTL() {
|
||||
|
||||
func ExampleStorageRedis_Get() {
|
||||
storage := gsession.NewStorageRedis(&gredis.Redis{})
|
||||
val, _ := storage.Get(gctx.New(), "id", "sessionIdToRedisKey")
|
||||
val, _ := storage.Get(gctx.New(), "id", "key")
|
||||
fmt.Println(val)
|
||||
|
||||
// Output:
|
||||
@ -245,12 +255,12 @@ func ExampleStorageRedis_GetSize() {
|
||||
fmt.Println(val)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStorageRedis_Remove() {
|
||||
storage := gsession.NewStorageRedis(&gredis.Redis{})
|
||||
err := storage.Remove(gctx.New(), "id", "sessionIdToRedisKey")
|
||||
err := storage.Remove(gctx.New(), "id", "key")
|
||||
fmt.Println(err != nil)
|
||||
|
||||
// Output:
|
||||
@ -280,7 +290,7 @@ func ExampleStorageRedis_UpdateTTL() {
|
||||
func ExampleStorageRedisHashTable_Get() {
|
||||
storage := gsession.NewStorageRedisHashTable(&gredis.Redis{})
|
||||
|
||||
v, err := storage.Get(gctx.New(), "id", "sessionIdToRedisKey")
|
||||
v, err := storage.Get(gctx.New(), "id", "key")
|
||||
|
||||
fmt.Println(v)
|
||||
fmt.Println(err)
|
||||
@ -312,14 +322,14 @@ func ExampleStorageRedisHashTable_GetSize() {
|
||||
fmt.Println(err)
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
// 0
|
||||
// redis adapter not initialized, missing configuration or adapter register?
|
||||
}
|
||||
|
||||
func ExampleStorageRedisHashTable_Remove() {
|
||||
storage := gsession.NewStorageRedisHashTable(&gredis.Redis{})
|
||||
|
||||
err := storage.Remove(gctx.New(), "id", "sessionIdToRedisKey")
|
||||
err := storage.Remove(gctx.New(), "id", "key")
|
||||
|
||||
fmt.Println(err)
|
||||
|
||||
@ -340,10 +350,7 @@ func ExampleStorageRedisHashTable_RemoveAll() {
|
||||
|
||||
func ExampleStorageRedisHashTable_GetSession() {
|
||||
storage := gsession.NewStorageRedisHashTable(&gredis.Redis{})
|
||||
|
||||
strAnyMap := gmap.StrAnyMap{}
|
||||
|
||||
data, err := storage.GetSession(gctx.New(), "id", time.Second, &strAnyMap)
|
||||
data, err := storage.GetSession(gctx.New(), "id", time.Second)
|
||||
|
||||
fmt.Println(data)
|
||||
fmt.Println(err)
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_StorageFile(t *testing.T) {
|
||||
storage := gsession.NewStorageFile()
|
||||
storage := gsession.NewStorageFile("", time.Second)
|
||||
manager := gsession.New(time.Second, storage)
|
||||
sessionId := ""
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user