session/storage/memory/memory.go
2025-06-19 19:17:11 +02:00

144 lines
3.4 KiB
Go

// Package memory implements sessions saved into memory is gone when stop the server
package memory
import (
"container/list"
"sync"
"time"
"git.mtux.eu/darkgopher/session"
"git.mtux.eu/darkgopher/session/util"
)
var pder = &ProviderMemory{list: list.New()}
func init() {
pder.sessions = make(map[string]*list.Element, 0)
session.Register("memory", pder)
}
// ProviderMemory implement memory session provider
type ProviderMemory struct {
lock sync.Mutex
sessions map[string]*list.Element //save to RAM
list *list.List //for GC
}
func (pder *ProviderMemory) updateAtime(sid string) {
pder.lock.Lock()
defer pder.lock.Unlock()
if ssel, ok := pder.sessions[sid]; ok {
ssel.Value.(*SessionMemory).atime = time.Now()
pder.list.MoveToFront(ssel)
}
}
// SetParams for memory provider not possible
func (pder *ProviderMemory) SetParams(pr any) error {
return nil
}
// Init create new session store for sid
func (pder *ProviderMemory) Init(sid string) (ses session.Session, err error) {
pder.lock.Lock()
defer pder.lock.Unlock()
data := make(map[any]any, 0)
sess := &SessionMemory{sid, time.Now(), data}
sessel := pder.list.PushBack(sess)
pder.sessions[sid] = sessel
return sess, nil
}
// Exists return true if session with sid exists
func (pder *ProviderMemory) Exists(sid string) (ex bool) {
if _, ex := pder.sessions[sid]; ex {
return ex
}
return
}
// Load return existing unexpired session or create new
func (pder *ProviderMemory) Load(sid string) (ses session.Session, err error) {
pder.lock.Lock()
defer pder.lock.Unlock()
if ssel, ok := pder.sessions[sid]; ok {
return ssel.Value.(*SessionMemory), nil
}
return pder.Init(sid)
}
// Destroy delete session storage with sid
func (pder *ProviderMemory) Destroy(sid string) (err error) {
pder.lock.Lock()
defer pder.lock.Unlock()
if ssel, ok := pder.sessions[sid]; ok {
pder.list.Remove(ssel)
delete(pder.sessions, sid)
return nil
}
return
}
// ChangeID replace session ID to new one and preserve all data
func (pder *ProviderMemory) ChangeID(oldsid, newsid string) (err error) {
pder.lock.Lock()
defer pder.lock.Unlock()
if ssel, ok := pder.sessions[oldsid]; ok {
ssel.Value.(*SessionMemory).sid = newsid //set internal sid to new
delete(pder.sessions, oldsid) //remove old sid in map
pder.sessions[newsid] = ssel //add new sid into map
}
return
}
// GC iterate all sessions and delete expired
func (pder *ProviderMemory) GC(maxlifetime int64) {
pder.lock.Lock()
defer pder.lock.Unlock()
for {
ssel := pder.list.Back()
if ssel == nil {
break
}
if ssel.Value.(*SessionMemory).atime.UnixMilli()+(maxlifetime*session.MilisPerSec()) < time.Now().UnixMilli() {
pder.list.Remove(ssel)
delete(pder.sessions, ssel.Value.(*SessionMemory).sid)
} else {
break
}
}
}
// SessionMemory implement sessionma.Session interface only in memory
type SessionMemory struct {
sid string
atime time.Time
data map[any]any
}
// Set -
func (sm *SessionMemory) Set(k, v any) (err error) {
defer pder.updateAtime(sm.sid)
defer util.ResolvePanic(&err)
sm.data[k] = v
return
}
// Get -
func (sm *SessionMemory) Get(k any) (v any, err error) {
defer pder.updateAtime(sm.sid)
defer util.ResolvePanic(&err)
return sm.data[k], err
}
// Delete -
func (sm *SessionMemory) Delete(k any) (err error) {
defer pder.updateAtime(sm.sid)
delete(sm.data, k)
return
}
// SessionID -
func (sm *SessionMemory) SessionID() string {
return sm.sid
}