auth/internal/session/repository/memory/memory_session.go

95 lines
1.8 KiB
Go

package memory
import (
"context"
"fmt"
"sync"
"time"
"source.toby3d.me/toby3d/auth/internal/domain"
"source.toby3d.me/toby3d/auth/internal/session"
)
type (
Session struct {
CreatedAt time.Time
domain.Session
}
memorySessionRepository struct {
mutex *sync.RWMutex
sessions map[string]Session
config domain.Config
}
)
func NewMemorySessionRepository(config domain.Config) session.Repository {
return &memorySessionRepository{
config: config,
mutex: new(sync.RWMutex),
sessions: make(map[string]Session),
}
}
func (repo *memorySessionRepository) Create(_ context.Context, s domain.Session) error {
repo.mutex.Lock()
defer repo.mutex.Unlock()
repo.sessions[s.Code] = Session{
CreatedAt: time.Now().UTC(),
Session: s,
}
return nil
}
func (repo *memorySessionRepository) Get(_ context.Context, code string) (*domain.Session, error) {
repo.mutex.Lock()
defer repo.mutex.Unlock()
if s, ok := repo.sessions[code]; ok {
return &s.Session, nil
}
return nil, session.ErrNotExist
}
func (repo *memorySessionRepository) GetAndDelete(ctx context.Context, code string) (*domain.Session, error) {
s, err := repo.Get(ctx, code)
if err != nil {
return nil, fmt.Errorf("cannot get and delete session: %w", err)
}
repo.mutex.Lock()
defer repo.mutex.Unlock()
delete(repo.sessions, s.Code)
return s, nil
}
func (repo *memorySessionRepository) GC() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for ts := range ticker.C {
ts := ts
repo.mutex.RLock()
for code, s := range repo.sessions {
if s.CreatedAt.Add(repo.config.Code.Expiry).After(ts) {
continue
}
repo.mutex.RUnlock()
repo.mutex.Lock()
delete(repo.sessions, code)
repo.mutex.Unlock()
repo.mutex.RLock()
}
repo.mutex.RUnlock()
}
}