improve session Manager and default Storage implements for package gsession; fix issue #1781

This commit is contained in:
John Guo 2022-04-27 15:05:34 +08:00
parent 99f1e69469
commit 48fddcd5e7
11 changed files with 343 additions and 321 deletions

View File

@ -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(

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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.

View 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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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) {