owpengram-server/internal/store/redisstore/session.go

76 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package redisstore
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/redis/go-redis/v9"
"telesrv/internal/store"
)
// DefaultSessionTTL 是 session 记录的默认过期时间。
// session 是连接态:过期或丢失后,客户端重连会触发 new_session_created / bad_server_salt 重建,
// 因此 TTL 不必很长。每个随机 session_id 都落一条记录且断连不删,过长的 TTL
// 只会堆积死 session移动端每次重连一条。7 天足够覆盖常规离线窗口。
const DefaultSessionTTL = 7 * 24 * time.Hour
// SessionStore 用 Redis 实现 store.SessionStore。
type SessionStore struct {
c *redis.Client
ttl time.Duration
}
// NewSessionStore 创建 Redis SessionStore。ttl<=0 表示永不过期。
func NewSessionStore(c *redis.Client, ttl time.Duration) *SessionStore {
return &SessionStore{c: c, ttl: ttl}
}
func sessionKey(id int64) string {
return fmt.Sprintf("session:%d", id)
}
// sessionValue 是 SessionData 在 Redis 中的序列化形态(不含 IDID 即 key
type sessionValue struct {
AuthKeyID [8]byte `json:"auth_key_id"`
Salt int64 `json:"salt"`
LastSeen int64 `json:"last_seen"`
}
// Save 实现 store.SessionStore。
func (s *SessionStore) Save(ctx context.Context, d store.SessionData) error {
v, err := json.Marshal(sessionValue{AuthKeyID: d.AuthKeyID, Salt: d.Salt, LastSeen: d.LastSeen})
if err != nil {
return fmt.Errorf("marshal session: %w", err)
}
if err := s.c.Set(ctx, sessionKey(d.ID), v, s.ttl).Err(); err != nil {
return fmt.Errorf("redis set session: %w", err)
}
return nil
}
// Get 实现 store.SessionStore。不存在时 found=false。
func (s *SessionStore) Get(ctx context.Context, id int64) (store.SessionData, bool, error) {
raw, err := s.c.Get(ctx, sessionKey(id)).Bytes()
if err != nil {
if errors.Is(err, redis.Nil) {
return store.SessionData{}, false, nil
}
return store.SessionData{}, false, fmt.Errorf("redis get session: %w", err)
}
var v sessionValue
if err := json.Unmarshal(raw, &v); err != nil {
return store.SessionData{}, false, fmt.Errorf("unmarshal session: %w", err)
}
return store.SessionData{ID: id, AuthKeyID: v.AuthKeyID, Salt: v.Salt, LastSeen: v.LastSeen}, true, nil
}
func (s *SessionStore) Delete(ctx context.Context, id int64) error {
if err := s.c.Del(ctx, sessionKey(id)).Err(); err != nil {
return fmt.Errorf("redis delete session: %w", err)
}
return nil
}