feat: add redis huohanhan auth cache
This commit is contained in:
@@ -35,6 +35,9 @@ func (e ShopeeProduct) newHuohanhanClient() (*huohanhan.Client, error) {
|
||||
}
|
||||
cfg := config.HuohanhanConfig{BaseURL: ext.ExtConfig.Huohanhan.BaseURL, Account: ext.ExtConfig.Huohanhan.Account, Password: ext.ExtConfig.Huohanhan.Password, OCRURL: ext.ExtConfig.Huohanhan.OCRURL}
|
||||
logger := logx.New(1000)
|
||||
if redisState, _ := huohanhan.NewRedisStateStore(ext.ExtConfig.Redis.Addr, ext.ExtConfig.Redis.Password, ext.ExtConfig.Redis.DB, time.Duration(ext.ExtConfig.Redis.AuthTTLSeconds)*time.Second); redisState != nil {
|
||||
state = huohanhan.NewCachedStateStore(redisState, state)
|
||||
}
|
||||
auth := huohanhan.NewAuthManager(cfg, state, logger, huohanhan.AuthOptions{})
|
||||
return huohanhan.NewClient(cfg, auth, logger, nil)
|
||||
}
|
||||
|
||||
+6
-1
@@ -47,11 +47,16 @@ settings:
|
||||
# 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径
|
||||
frontpath: ../go-admin-ui/src
|
||||
extend: # 扩展项使用说明
|
||||
huohanhan:
|
||||
huohanhan:
|
||||
base_url: https://www.huohanhan.com
|
||||
account: ""
|
||||
password: ""
|
||||
ocr_url: https://ocr.ilapage.cn/ocr
|
||||
redis:
|
||||
addr: 127.0.0.1:6379
|
||||
password: ""
|
||||
db: 0
|
||||
auth_ttl_seconds: 86400
|
||||
demo:
|
||||
name: data
|
||||
cache:
|
||||
|
||||
@@ -5,6 +5,13 @@ var ExtConfig Extend
|
||||
type Extend struct {
|
||||
AMap AMap `yaml:"demo" json:"demo"`
|
||||
Huohanhan HuohanhanConfig `yaml:"huohanhan" json:"huohanhan"`
|
||||
Redis RedisConfig `yaml:"redis" json:"redis"`
|
||||
}
|
||||
type RedisConfig struct {
|
||||
Addr string `yaml:"addr" json:"addr"`
|
||||
Password string `yaml:"password" json:"password"`
|
||||
DB int `yaml:"db" json:"db"`
|
||||
AuthTTLSeconds int `yaml:"auth_ttl_seconds" json:"auth_ttl_seconds"`
|
||||
}
|
||||
type AMap struct {
|
||||
Key string `yaml:"key" json:"key"`
|
||||
|
||||
@@ -112,6 +112,7 @@ require (
|
||||
github.com/prometheus/procfs v0.21.1 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/quic-go/quic-go v0.61.0 // indirect
|
||||
github.com/redis/go-redis/v9 v9.22.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/shamsher31/goimgext v1.0.0 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
@@ -124,6 +125,7 @@ require (
|
||||
github.com/ugorji/go/codec v1.3.2 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
|
||||
@@ -476,6 +476,8 @@ github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9q
|
||||
github.com/quic-go/quic-go v0.61.0 h1:ui88A53s8MSVYLC56en0KQ17HARk+9986Dn0SBfKNvA=
|
||||
github.com/quic-go/quic-go v0.61.0/go.mod h1:9So2anK4Tp22URSQq00k+Vo2PNkle96ycDPDHL4s9vs=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.22.0 h1:laDvpYXTJtZLloinw1fA5Kqd6HAEH2XKxOkG/PDq2F0=
|
||||
github.com/redis/go-redis/v9 v9.22.0/go.mod h1:y2g0Wj8rQvuK0ELM+oxSudcLtC09JScs98I/X9gRWY4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
@@ -583,6 +585,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package huohanhan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RedisStateStore struct {
|
||||
client *redis.Client
|
||||
prefix string
|
||||
ttl time.Duration
|
||||
}
|
||||
type CachedStateStore struct {
|
||||
cache *RedisStateStore
|
||||
durable StateStore
|
||||
}
|
||||
|
||||
func NewCachedStateStore(cache *RedisStateStore, durable StateStore) StateStore {
|
||||
return &CachedStateStore{cache: cache, durable: durable}
|
||||
}
|
||||
|
||||
func NewRedisStateStore(addr, password string, db int, ttl time.Duration) (*RedisStateStore, error) {
|
||||
if addr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if ttl <= 0 {
|
||||
ttl = 24 * time.Hour
|
||||
}
|
||||
return &RedisStateStore{client: redis.NewClient(&redis.Options{Addr: addr, Password: password, DB: db}), prefix: "erpgo:huohanhan:", ttl: ttl}, nil
|
||||
}
|
||||
func (s *RedisStateStore) SetKV(key, value, _ string) error {
|
||||
return s.client.Set(context.Background(), s.prefix+key, value, s.ttl).Err()
|
||||
}
|
||||
func (s *RedisStateStore) GetKV(key string) (string, bool, error) {
|
||||
v, err := s.client.Get(context.Background(), s.prefix+key).Result()
|
||||
if err == redis.Nil {
|
||||
return "", false, nil
|
||||
}
|
||||
return v, err == nil, err
|
||||
}
|
||||
func (s *RedisStateStore) Delete(key string) error {
|
||||
return s.client.Del(context.Background(), s.prefix+key).Err()
|
||||
}
|
||||
func (s *RedisStateStore) Close() error { return s.client.Close() }
|
||||
func (s *CachedStateStore) SetKV(key, value, now string) error {
|
||||
if err := s.durable.SetKV(key, value, now); err != nil {
|
||||
return err
|
||||
}
|
||||
if value == "" {
|
||||
_ = s.cache.Delete(key)
|
||||
} else {
|
||||
_ = s.cache.SetKV(key, value, now)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *CachedStateStore) GetKV(key string) (string, bool, error) {
|
||||
if v, ok, err := s.cache.GetKV(key); err == nil && ok && v != "" {
|
||||
return v, true, nil
|
||||
}
|
||||
v, ok, err := s.durable.GetKV(key)
|
||||
if err == nil && ok && v != "" {
|
||||
_ = s.cache.SetKV(key, v, "")
|
||||
}
|
||||
return v, ok && v != "", err
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# LOCAL-010:Redis 缓存货憨憨认证状态
|
||||
|
||||
- 状态:进行中
|
||||
- 来源:用户需求(2026-09-14)
|
||||
- 前置:LOCAL-009
|
||||
|
||||
## 目标
|
||||
|
||||
使用 Redis 缓存货憨憨 token 和 Cookie,减少每次商品请求的在线校验;MySQL 保留持久化状态和恢复来源。
|
||||
|
||||
## 规则
|
||||
|
||||
- Redis 认证状态默认 TTL 24 小时;
|
||||
- Redis 没有状态时从 MySQL 恢复,仍无状态才登录;
|
||||
- 货憨憨请求返回认证失效时删除 Redis 状态,重新登录并重试一次;
|
||||
- Redis 不可用时自动回退 MySQL;
|
||||
- 不记录 token、Cookie 或 Redis 内容到日志。
|
||||
|
||||
## 验收
|
||||
|
||||
- Redis 命中时不再额外调用货憨憨在线校验;
|
||||
- Redis 过期或清空后可以从 MySQL 恢复;
|
||||
- 认证失效会清除缓存并重新登录;
|
||||
- Redis 不可用不影响现有 MySQL 流程;
|
||||
- 相关测试通过。
|
||||
Reference in New Issue
Block a user