// 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{li: 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 li *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.li.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.li.PushBack(sess) pder.sessions[sid] = sessel return sess, nil } // 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 pder.Exists(sid) { return pder.sessions[sid].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.li.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 } // 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 } // GC iterate all sessions and delete expired func (pder *ProviderMemory) GC(maxlifetime int64) { pder.lock.Lock() defer pder.lock.Unlock() for { ssel := pder.li.Back() if ssel == nil { break } if ssel.Value.(*SessionMemory).atime.UnixMilli()+(maxlifetime*int64(session.MilisPerSecDuration())) < time.Now().UnixMilli() { pder.li.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 }