76 lines
1.7 KiB
Go
76 lines
1.7 KiB
Go
package services
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// SessionService 인메모리 세션 스토어
|
|
type SessionService struct {
|
|
sessions sync.Map // sessionID → time.Time(만료시각)
|
|
ttl time.Duration // 세션 유효 기간
|
|
}
|
|
|
|
var sessionServiceInstance *SessionService
|
|
var sessionServiceOnce sync.Once
|
|
|
|
// GetSessionService 세션 서비스 싱글톤 반환
|
|
func GetSessionService() *SessionService {
|
|
sessionServiceOnce.Do(func() {
|
|
sessionServiceInstance = NewSessionService()
|
|
})
|
|
return sessionServiceInstance
|
|
}
|
|
|
|
// NewSessionService 세션 서비스 초기화 (TTL 24시간)
|
|
func NewSessionService() *SessionService {
|
|
svc := &SessionService{ttl: 24 * time.Hour}
|
|
go svc.cleanup()
|
|
return svc
|
|
}
|
|
|
|
// Create 새 세션 생성 → sessionID(UUID) 반환
|
|
func (s *SessionService) Create() string {
|
|
b := make([]byte, 16)
|
|
_, _ = rand.Read(b)
|
|
id := hex.EncodeToString(b)
|
|
s.sessions.Store(id, time.Now().Add(s.ttl))
|
|
return id
|
|
}
|
|
|
|
// Validate 세션 유효성 검사 (만료 시 자동 삭제)
|
|
func (s *SessionService) Validate(id string) bool {
|
|
val, ok := s.sessions.Load(id)
|
|
if !ok {
|
|
return false
|
|
}
|
|
expiry, ok := val.(time.Time)
|
|
if !ok || time.Now().After(expiry) {
|
|
s.sessions.Delete(id)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Delete 세션 삭제 (로그아웃)
|
|
func (s *SessionService) Delete(id string) {
|
|
s.sessions.Delete(id)
|
|
}
|
|
|
|
// cleanup 만료된 세션을 주기적으로 정리 (1시간 주기)
|
|
func (s *SessionService) cleanup() {
|
|
ticker := time.NewTicker(time.Hour)
|
|
defer ticker.Stop()
|
|
for range ticker.C {
|
|
now := time.Now()
|
|
s.sessions.Range(func(key, val any) bool {
|
|
if expiry, ok := val.(time.Time); ok && now.After(expiry) {
|
|
s.sessions.Delete(key)
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
}
|