68 lines
1.7 KiB
Go
68 lines
1.7 KiB
Go
package reward
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
type tgConfig struct {
|
|
botUser, channel, botToken, webhookSecret string
|
|
}
|
|
|
|
// SetTelegram 注入 TG 配置(经 Service.tg)。
|
|
func (s *Service) SetTelegram(botUser, channel, botToken, webhookSecret string) {
|
|
s.tg = tgConfig{botUser: botUser, channel: channel, botToken: botToken, webhookSecret: webhookSecret}
|
|
}
|
|
|
|
// SetRedis 注入 redis 客户端(经 Service.rdb);为 nil 时 token 走内存兜底(测试/未配 redis)。
|
|
func (s *Service) SetRedis(rdb *redis.Client) { s.rdb = rdb }
|
|
|
|
func randToken() string {
|
|
b := make([]byte, 16)
|
|
_, _ = rand.Read(b)
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
// IssueTelegramToken 生成随机 token,Redis SETEX tg_bind:<token> 600 <userID>;
|
|
// Redis 为 nil 时用内存 map 兜底(测试/未配 redis)。
|
|
func (s *Service) IssueTelegramToken(ctx context.Context, userID int64) (string, error) {
|
|
tok := randToken()
|
|
if s.rdb != nil {
|
|
return tok, s.rdb.Set(ctx, "tg_bind:"+tok, userID, 10*time.Minute).Err()
|
|
}
|
|
s.memMu.Lock()
|
|
if s.memTok == nil {
|
|
s.memTok = map[string]int64{}
|
|
}
|
|
s.memTok[tok] = userID
|
|
s.memMu.Unlock()
|
|
return tok, nil
|
|
}
|
|
|
|
// ConsumeTelegramToken 一次性消费(GETDEL 语义)。
|
|
func (s *Service) ConsumeTelegramToken(ctx context.Context, token string) (int64, bool, error) {
|
|
if s.rdb != nil {
|
|
v, err := s.rdb.GetDel(ctx, "tg_bind:"+token).Result()
|
|
if err == redis.Nil {
|
|
return 0, false, nil
|
|
}
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
id, _ := strconv.ParseInt(v, 10, 64)
|
|
return id, true, nil
|
|
}
|
|
s.memMu.Lock()
|
|
defer s.memMu.Unlock()
|
|
id, ok := s.memTok[token]
|
|
if ok {
|
|
delete(s.memTok, token)
|
|
}
|
|
return id, ok, nil
|
|
}
|