package store import ( "context" "sync" "time" "github.com/google/uuid" ) // MemUserRepository 基于内存的 UserRepository 实现(测试用)。 type MemUserRepository struct { mu sync.RWMutex users map[string]*User // id -> user byUsername map[string]string // username -> id refreshTokens map[string]string // tokenHash -> userID tokenExpiry map[string]time.Time // tokenHash -> expiresAt } // NewMemUserRepository 创建 MemUserRepository。 func NewMemUserRepository() *MemUserRepository { return &MemUserRepository{ users: make(map[string]*User), byUsername: make(map[string]string), refreshTokens: make(map[string]string), tokenExpiry: make(map[string]time.Time), } } func (r *MemUserRepository) Create(_ context.Context, username, passwordHash string) (string, error) { r.mu.Lock() defer r.mu.Unlock() if _, exists := r.byUsername[username]; exists { return "", ErrUsernameTaken } id := uuid.New().String() now := time.Now() user := &User{ ID: id, Username: username, PasswordHash: passwordHash, CreatedAt: now, UpdatedAt: now, } r.users[id] = user r.byUsername[username] = id return id, nil } func (r *MemUserRepository) FindByUsername(_ context.Context, username string) (*User, error) { r.mu.RLock() defer r.mu.RUnlock() id, ok := r.byUsername[username] if !ok { return nil, ErrUserNotFound } u := r.users[id] copy := *u return ©, nil } func (r *MemUserRepository) FindByID(_ context.Context, id string) (*User, error) { r.mu.RLock() defer r.mu.RUnlock() u, ok := r.users[id] if !ok { return nil, ErrUserNotFound } copy := *u return ©, nil } func (r *MemUserRepository) SaveRefreshToken(_ context.Context, userID, tokenHash string, expiresAt time.Time) error { r.mu.Lock() defer r.mu.Unlock() r.refreshTokens[tokenHash] = userID r.tokenExpiry[tokenHash] = expiresAt return nil } func (r *MemUserRepository) FindRefreshToken(_ context.Context, tokenHash string) (string, error) { r.mu.RLock() defer r.mu.RUnlock() userID, ok := r.refreshTokens[tokenHash] if !ok { return "", ErrRefreshTokenNotFound } if time.Now().After(r.tokenExpiry[tokenHash]) { return "", ErrRefreshTokenNotFound } return userID, nil } func (r *MemUserRepository) DeleteRefreshToken(_ context.Context, tokenHash string) error { r.mu.Lock() defer r.mu.Unlock() delete(r.refreshTokens, tokenHash) delete(r.tokenExpiry, tokenHash) return nil } func (r *MemUserRepository) DeleteUserRefreshTokens(_ context.Context, userID string) error { r.mu.Lock() defer r.mu.Unlock() for hash, uid := range r.refreshTokens { if uid == userID { delete(r.refreshTokens, hash) delete(r.tokenExpiry, hash) } } return nil }