79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
// Package session 提供会话存储能力。
|
|
// 当前默认实现为进程内内存存储(无 Redis 环境),后续可替换为 Redis 实现。
|
|
package session
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"portal-mini-go/internal/pkg/errors"
|
|
)
|
|
|
|
// Store 会话存储接口,便于后续切换为 Redis 等实现。
|
|
type Store interface {
|
|
Set(ctx context.Context, key string, userID uint64, ttl time.Duration) error
|
|
Get(ctx context.Context, key string) (uint64, error)
|
|
Delete(ctx context.Context, key string) error
|
|
}
|
|
|
|
// MaSessionPrefix 是小程序用户会话键前缀。
|
|
const MaSessionPrefix = "ma:session:"
|
|
|
|
// MaSessionKey 拼接小程序用户会话键(token 为 Login 签发的会话凭证)。
|
|
func MaSessionKey(token string) string { return MaSessionPrefix + token }
|
|
|
|
// MemoryStore 进程内会话存储,适用于无 Redis 的本地/测试环境。
|
|
// 注意:多实例部署时各进程不共享,仅供单实例使用。
|
|
type MemoryStore struct {
|
|
mu sync.RWMutex
|
|
data map[string]memoryEntry
|
|
now func() time.Time
|
|
}
|
|
|
|
type memoryEntry struct {
|
|
userID uint64
|
|
expireAt time.Time
|
|
}
|
|
|
|
// NewMemoryStore 创建内存会话存储。
|
|
func NewMemoryStore() *MemoryStore {
|
|
return &MemoryStore{
|
|
data: make(map[string]memoryEntry),
|
|
now: time.Now,
|
|
}
|
|
}
|
|
|
|
// Set 写入会话,key 映射到 userID,ttl 后过期。
|
|
func (m *MemoryStore) Set(_ context.Context, key string, userID uint64, ttl time.Duration) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.data[key] = memoryEntry{userID: userID, expireAt: m.now().Add(ttl)}
|
|
return nil
|
|
}
|
|
|
|
// Get 读取会话对应的 userID;不存在或已过期返回 ErrUnauthorized。
|
|
func (m *MemoryStore) Get(_ context.Context, key string) (uint64, error) {
|
|
m.mu.RLock()
|
|
e, ok := m.data[key]
|
|
m.mu.RUnlock()
|
|
if !ok {
|
|
return 0, errors.ErrUnauthorized
|
|
}
|
|
if m.now().After(e.expireAt) {
|
|
m.mu.Lock()
|
|
delete(m.data, key)
|
|
m.mu.Unlock()
|
|
return 0, errors.ErrUnauthorized
|
|
}
|
|
return e.userID, nil
|
|
}
|
|
|
|
// Delete 删除会话。
|
|
func (m *MemoryStore) Delete(_ context.Context, key string) error {
|
|
m.mu.Lock()
|
|
delete(m.data, key)
|
|
m.mu.Unlock()
|
|
return nil
|
|
}
|