| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- package repository
- import (
- "context"
- "encoding/json"
- "log"
- "sync"
- "time"
- "github.com/Wei-Shaw/sub2api/internal/model"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/redis/go-redis/v9"
- )
- const (
- errorPassthroughCacheKey = "error_passthrough_rules"
- errorPassthroughPubSubKey = "error_passthrough_rules_updated"
- errorPassthroughCacheTTL = 24 * time.Hour
- )
- type errorPassthroughCache struct {
- rdb *redis.Client
- localCache []*model.ErrorPassthroughRule
- localMu sync.RWMutex
- }
- // NewErrorPassthroughCache 创建错误透传规则缓存
- func NewErrorPassthroughCache(rdb *redis.Client) service.ErrorPassthroughCache {
- return &errorPassthroughCache{
- rdb: rdb,
- }
- }
- // Get 从缓存获取规则列表
- func (c *errorPassthroughCache) Get(ctx context.Context) ([]*model.ErrorPassthroughRule, bool) {
- // 先检查本地缓存
- c.localMu.RLock()
- if c.localCache != nil {
- rules := c.localCache
- c.localMu.RUnlock()
- return rules, true
- }
- c.localMu.RUnlock()
- // 从 Redis 获取
- data, err := c.rdb.Get(ctx, errorPassthroughCacheKey).Bytes()
- if err != nil {
- if err != redis.Nil {
- log.Printf("[ErrorPassthroughCache] Failed to get from Redis: %v", err)
- }
- return nil, false
- }
- var rules []*model.ErrorPassthroughRule
- if err := json.Unmarshal(data, &rules); err != nil {
- log.Printf("[ErrorPassthroughCache] Failed to unmarshal rules: %v", err)
- return nil, false
- }
- // 更新本地缓存
- c.localMu.Lock()
- c.localCache = rules
- c.localMu.Unlock()
- return rules, true
- }
- // Set 设置缓存
- func (c *errorPassthroughCache) Set(ctx context.Context, rules []*model.ErrorPassthroughRule) error {
- data, err := json.Marshal(rules)
- if err != nil {
- return err
- }
- if err := c.rdb.Set(ctx, errorPassthroughCacheKey, data, errorPassthroughCacheTTL).Err(); err != nil {
- return err
- }
- // 更新本地缓存
- c.localMu.Lock()
- c.localCache = rules
- c.localMu.Unlock()
- return nil
- }
- // Invalidate 使缓存失效
- func (c *errorPassthroughCache) Invalidate(ctx context.Context) error {
- // 清除本地缓存
- c.localMu.Lock()
- c.localCache = nil
- c.localMu.Unlock()
- // 清除 Redis 缓存
- return c.rdb.Del(ctx, errorPassthroughCacheKey).Err()
- }
- // NotifyUpdate 通知其他实例刷新缓存
- func (c *errorPassthroughCache) NotifyUpdate(ctx context.Context) error {
- return c.rdb.Publish(ctx, errorPassthroughPubSubKey, "refresh").Err()
- }
- // SubscribeUpdates 订阅缓存更新通知
- func (c *errorPassthroughCache) SubscribeUpdates(ctx context.Context, handler func()) {
- go func() {
- sub := c.rdb.Subscribe(ctx, errorPassthroughPubSubKey)
- defer func() { _ = sub.Close() }()
- ch := sub.Channel()
- for {
- select {
- case <-ctx.Done():
- return
- case msg := <-ch:
- if msg == nil {
- return
- }
- // 清除本地缓存,下次访问时会从 Redis 或数据库重新加载
- c.localMu.Lock()
- c.localCache = nil
- c.localMu.Unlock()
- // 调用处理函数
- handler()
- }
- }
- }()
- }
|