package session import ( "encoding/json" "os" "sync" ) // SessionManager handles session storage and persistence type SessionManager struct { mu sync.RWMutex sessions map[string]*Session filePath string } var Manager *SessionManager // Init initializes the global session manager func Init(filePath string) { if Manager != nil { panic("session manager already initialized") } Manager = &SessionManager{ sessions: make(map[string]*Session), filePath: filePath, } Manager.load() } // GetManager returns the global session manager func GetManager() *SessionManager { if Manager == nil { panic("session manager not initialized") } return Manager } // Create creates and stores a new session func (sm *SessionManager) Create(userID int) *Session { sess := New(userID) sm.mu.Lock() sm.sessions[sess.ID] = sess sm.mu.Unlock() return sess } // Get retrieves a session by ID func (sm *SessionManager) Get(sessionID string) (*Session, bool) { sm.mu.RLock() sess, exists := sm.sessions[sessionID] sm.mu.RUnlock() if !exists || sess.IsExpired() { if exists { sm.Delete(sessionID) } return nil, false } return sess, true } // Store saves a session in memory (updates existing or creates new) func (sm *SessionManager) Store(sess *Session) { sm.mu.Lock() sm.sessions[sess.ID] = sess sm.mu.Unlock() } // Delete removes a session func (sm *SessionManager) Delete(sessionID string) { sm.mu.Lock() delete(sm.sessions, sessionID) sm.mu.Unlock() } // Cleanup removes expired sessions func (sm *SessionManager) Cleanup() { sm.mu.Lock() for id, sess := range sm.sessions { if sess.IsExpired() { delete(sm.sessions, id) } } sm.mu.Unlock() } // Stats returns session statistics func (sm *SessionManager) Stats() (total, active int) { sm.mu.RLock() defer sm.mu.RUnlock() total = len(sm.sessions) for _, sess := range sm.sessions { if !sess.IsExpired() { active++ } } return } // load reads sessions from the JSON file func (sm *SessionManager) load() { if sm.filePath == "" { return } data, err := os.ReadFile(sm.filePath) if err != nil { return // File doesn't exist or can't be read } var sessions map[string]*Session if err := json.Unmarshal(data, &sessions); err != nil { return // Invalid JSON } sm.mu.Lock() for id, sess := range sessions { if sess != nil && !sess.IsExpired() { sess.ID = id // Ensure ID consistency sm.sessions[id] = sess } } sm.mu.Unlock() } // Save writes sessions to the JSON file func (sm *SessionManager) Save() error { if sm.filePath == "" { return nil } sm.Cleanup() // Remove expired sessions before saving sm.mu.RLock() data, err := json.MarshalIndent(sm.sessions, "", "\t") sm.mu.RUnlock() if err != nil { return err } return os.WriteFile(sm.filePath, data, 0600) } // Close saves sessions and cleans up func (sm *SessionManager) Close() error { return sm.Save() }