187 lines
4.0 KiB
Go
187 lines
4.0 KiB
Go
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
|
|
}
|