package worker import ( "encoding/json" "log" "math" "os" "sync" "time" ) // MemoryCacheValue 缓存值结构,包含值和过期时间 type MemoryCacheValue struct { Value string `json:"value"` ExpireAt int64 `json:"expireAt"` // 过期时间戳,秒级 } var ( memoryCacheData = NewMemoryCache() ) // MemoryCache 线程安全的内存缓存 type MemoryCache struct { data map[string]MemoryCacheValue mu sync.RWMutex } // NewMemoryCache 创建新的内存缓存实例 func NewMemoryCache() *MemoryCache { return &MemoryCache{ data: make(map[string]MemoryCacheValue), } } // InitStaticMemoryCache 初始化全局缓存实例 func InitStaticMemoryCache() { // 先尝试从文件加载 ReadMemoryCacheFromJsonFile() } // SetWithExp 设置带过期时间的键值对 func (mc *MemoryCache) SetWithExp(key string, value string, expireAt int64) { mc.mu.Lock() defer mc.mu.Unlock() mc.data[key] = MemoryCacheValue{value, expireAt} } // Get 获取键值,如果已过期则返回空并删除 func (mc *MemoryCache) Get(key string) string { // 先加读锁检查 mc.mu.RLock() value, ok := mc.data[key] mc.mu.RUnlock() if !ok { return "" } // 检查是否过期 now := time.Now().Unix() if value.ExpireAt > now { return value.Value } // 已过期,删除该键 mc.mu.Lock() // 二次检查,防止并发情况下已被删除 if v, exists := mc.data[key]; exists && v.ExpireAt <= now { delete(mc.data, key) } mc.mu.Unlock() return "" } // Set 设置永不过期的键值对 func (mc *MemoryCache) Set(key string, value string) { mc.SetWithExp(key, value, math.MaxInt64) } // Del 删除指定键 func (mc *MemoryCache) Del(key string) { mc.mu.Lock() defer mc.mu.Unlock() delete(mc.data, key) } // Clear 清空所有缓存 func (mc *MemoryCache) Clear() { mc.mu.Lock() defer mc.mu.Unlock() mc.data = make(map[string]MemoryCacheValue) } const CRON_MAX_DEL_NUMBER = 100 // 每次清理的最大数量 // DeleteMemoryCacheCron 定时清理过期键 func DeleteMemoryCacheCron() { memoryCacheData.mu.Lock() defer memoryCacheData.mu.Unlock() now := time.Now().Unix() i := 0 for key, value := range memoryCacheData.data { if i >= CRON_MAX_DEL_NUMBER { break } if value.ExpireAt < now { delete(memoryCacheData.data, key) i++ } } } // GetMemoryCacheFilePath 获取缓存持久化文件路径 func GetMemoryCacheFilePath() string { if os.Getenv("OS") == "Windows_NT" { return "C:/Users/Administrator/vp_mc.json" } return "/etc/vp_mc.json" } // WriteMemoryCacheToFile 将缓存写入文件持久化 func WriteMemoryCacheToFile() { memoryCacheData.mu.RLock() defer memoryCacheData.mu.RUnlock() path := GetMemoryCacheFilePath() data, err := json.MarshalIndent(memoryCacheData.data, "", " ") if err != nil { log.Println("mc write file json err:", err) return } // 先写入临时文件,再原子替换,防止文件损坏 tempPath := path + ".tmp" if err := os.WriteFile(tempPath, data, 0644); err != nil { log.Println("mc write temp file err:", err) return } if err := os.Rename(tempPath, path); err != nil { log.Println("mc rename file err:", err) os.Remove(tempPath) // 清理临时文件 } } // ReadMemoryCacheFromJsonFile 从文件加载缓存 func ReadMemoryCacheFromJsonFile() { path := GetMemoryCacheFilePath() _, err := os.Stat(path) if err != nil { log.Println("mc file not exists:", err) return } file, err := os.Open(path) if err != nil { log.Println("mc open file err:", err) return } defer file.Close() var data map[string]MemoryCacheValue decoder := json.NewDecoder(file) if err := decoder.Decode(&data); err != nil { log.Println("mc decode file err:", err) return } // 过滤已过期的数据 now := time.Now().Unix() memoryCacheData.mu.Lock() for k, v := range data { if v.ExpireAt > now || v.ExpireAt == math.MaxInt64 { memoryCacheData.data[k] = v } } memoryCacheData.mu.Unlock() } // 提供全局缓存的访问方法 func GetGlobalCache() *MemoryCache { return memoryCacheData }