This commit is contained in:
DarkGopher 2025-05-31 17:12:11 +02:00
parent 09632be46c
commit 1c3000e532
7 changed files with 569 additions and 0 deletions

137
storage/memory/memory.go Normal file
View file

@ -0,0 +1,137 @@
// 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"
)
var pder = &ProviderMemory{list: list.New()}
func init() {
pder.sessions = make(map[string]*list.Element, 0)
session.Register("memory", pder)
}
// SessionMemory implement sessionma.Session interface only in memory
type SessionMemory struct {
sid string
atime time.Time
data map[any]any
}
func (sm *SessionMemory) resolvepanic(err *error) {
if r := recover(); r != nil {
*err = r.(error)
}
}
// Set -
func (sm *SessionMemory) Set(k any, v any) (err error) {
defer pder.updateAtime(sm.sid)
defer sm.resolvepanic(&err)
sm.data[k] = v
return
}
// Get -
func (sm *SessionMemory) Get(k any) (v any, err error) {
defer pder.updateAtime(sm.sid)
defer sm.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
}
// 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)
}
}
// 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
}
// read return existing unexpired session or create new
func (pder *ProviderMemory) Read(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 {
delete(pder.sessions, sid)
pder.list.Remove(ssel)
return nil
}
return
}
// RegenerateID replace session ID to new one and preserve all data
func (pder *ProviderMemory) RegenerateID(oldsid, newsid string) (err error) {
pder.lock.Lock()
defer pder.lock.Unlock()
if ssel, ok := pder.sessions[oldsid]; ok {
ssel.Value.(*SessionMemory).sid = newsid
delete(pder.sessions, oldsid)
pder.sessions[newsid] = ssel
}
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
}
}
}