some-automoderation/sessions/sessions_manager.go

107 lines
3.0 KiB
Go

package sessions
import (
"context"
"fmt"
"log"
"math/rand"
"time"
"sunshine.industries/some-automoderation/rooms"
"github.com/redis/go-redis/v9"
)
type SessionData struct {
SessionId int `redis:"session_id"`
RoomId string `redis:"room_id"`
PersonId rooms.PersonId `redis:"person_id"`
ExpireIn time.Duration `redis:"-"`
}
type SessionManagement interface {
Get(ctx context.Context, sessionId int) SessionData
Save(ctx context.Context, roomName string, personId rooms.PersonId) (SessionData, error)
Remove(ctx context.Context, sessionId int) error
}
const sessionPrefix = "session"
const SessionTtl = 3 * time.Hour
const SessionProlongationWindow = time.Hour
func sessionIdToKey(sessionId int) string {
return fmt.Sprintf("%s:%d", sessionPrefix, sessionId)
}
type RedisSM struct {
Rdb *redis.Client
}
func (redisSM RedisSM) Get(ctx context.Context, sessionId int) SessionData {
var foundSession SessionData
redisKey := sessionIdToKey(sessionId)
err := redisSM.Rdb.HGetAll(ctx, redisKey).Scan(&foundSession)
if err != nil {
log.Printf("> error reading %s : %s", redisKey, err)
return SessionData{}
}
log.Printf("> successfully found %d %+v", sessionId, foundSession)
ttl, err := redisSM.Rdb.TTL(ctx, redisKey).Result()
if err != nil {
log.Printf("> error getting ttl for session %+v", foundSession)
return foundSession
}
if ttl == -2 {
log.Printf("> ttl indicates session doesn't exist for session %+v", foundSession)
return SessionData{}
}
if ttl < SessionProlongationWindow {
err = redisSM.Rdb.Expire(ctx, redisKey, SessionTtl).Err()
if err != nil {
log.Printf("> error updating ttl for session %+v", foundSession)
return foundSession
} else {
ttl = SessionTtl
}
}
foundSession.ExpireIn = ttl
return foundSession
}
func (redisSM RedisSM) Save(ctx context.Context, roomName string, personId rooms.PersonId) (SessionData, error) {
randId := rand.Int()
newSession := SessionData{
SessionId: randId,
RoomId: roomName,
PersonId: personId,
ExpireIn: SessionTtl,
}
err := redisSM.Rdb.HSet(ctx, sessionIdToKey(randId), newSession).Err()
redisSM.Rdb.Expire(ctx, sessionIdToKey(randId), SessionTtl)
if err != nil {
log.Printf("> error! saving session %+v %s", newSession, err)
return SessionData{}, fmt.Errorf("error saving new session: %+v with %s", newSession, err)
}
return newSession, nil
}
func (redisSM RedisSM) Remove(ctx context.Context, sessionId int) error {
err := redisSM.Rdb.Del(ctx, sessionIdToKey(sessionId)).Err()
return err
}
type DummySM struct{}
func (d DummySM) Get(ctx context.Context, sessionId int) SessionData {
log.Printf("get dummy session by %d", sessionId)
return SessionData{}
}
func (d DummySM) Save(ctx context.Context, roomName string, personId rooms.PersonId) (SessionData, error) {
log.Printf("save dummy session with %s %d", roomName, personId)
return SessionData{}, nil
}
func (d DummySM) Remove(ctx context.Context, sessionId int) error {
log.Printf("deleting session %d", sessionId)
return nil
}