diff --git a/5-session-cleaner/6-session-cleaner b/5-session-cleaner/6-session-cleaner deleted file mode 100755 index cef31f0..0000000 Binary files a/5-session-cleaner/6-session-cleaner and /dev/null differ diff --git a/5-session-cleaner/main.go b/5-session-cleaner/main.go index 352ecc3..0eea526 100644 --- a/5-session-cleaner/main.go +++ b/5-session-cleaner/main.go @@ -20,17 +20,22 @@ package main import ( "errors" "log" + "sync" + "time" ) // SessionManager keeps track of all sessions from creation, updating // to destroying. type SessionManager struct { sessions map[string]Session + rwmu sync.RWMutex } // Session stores the session's data type Session struct { - Data map[string]interface{} + Data map[string]interface{} + timer *time.Timer + mu sync.Mutex } // NewSessionManager creates a new sessionManager @@ -42,6 +47,12 @@ func NewSessionManager() *SessionManager { return m } +func (m *SessionManager) CleanSession(sessionID string) { + m.rwmu.Lock() + delete(m.sessions, sessionID) + m.rwmu.Unlock() +} + // CreateSession creates a new session and returns the sessionID func (m *SessionManager) CreateSession() (string, error) { sessionID, err := MakeSessionID() @@ -49,9 +60,14 @@ func (m *SessionManager) CreateSession() (string, error) { return "", err } + m.rwmu.Lock() m.sessions[sessionID] = Session{ Data: make(map[string]interface{}), + timer: time.AfterFunc(5*time.Second, func() { + m.CleanSession(sessionID) + }), } + m.rwmu.Unlock() return sessionID, nil } @@ -63,7 +79,9 @@ var ErrSessionNotFound = errors.New("SessionID does not exists") // GetSessionData returns data related to session if sessionID is // found, errors otherwise func (m *SessionManager) GetSessionData(sessionID string) (map[string]interface{}, error) { + m.rwmu.RLock() session, ok := m.sessions[sessionID] + m.rwmu.RUnlock() if !ok { return nil, ErrSessionNotFound } @@ -72,15 +90,22 @@ func (m *SessionManager) GetSessionData(sessionID string) (map[string]interface{ // UpdateSessionData overwrites the old session data with the new one func (m *SessionManager) UpdateSessionData(sessionID string, data map[string]interface{}) error { - _, ok := m.sessions[sessionID] + m.rwmu.RLock() + s, ok := m.sessions[sessionID] + m.rwmu.RUnlock() + if !ok { return ErrSessionNotFound } - // Hint: you should renew expiry of the session here - m.sessions[sessionID] = Session{ - Data: data, + // Lock the session data to handle concurrent access to the same session + s.mu.Lock() + s.Data = data + if !s.timer.Stop() { + <-s.timer.C } + s.timer.Reset(5 * time.Second) + s.mu.Unlock() return nil }