Files
pansou/util/cache/cache_key.go
www.xueximeng.com 5a3917c999 异步插件缓存
2025-07-15 00:03:02 +08:00

294 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cache
import (
"crypto/md5"
"encoding/hex"
"fmt"
"sort"
"strings"
"sync"
"pansou/plugin"
)
// 预计算的哈希值映射
var (
channelHashCache sync.Map // 存储频道列表哈希
pluginHashCache sync.Map // 存储插件列表哈希
// 预先计算的常用列表哈希值
precomputedHashes sync.Map
// 所有插件名称的哈希值
allPluginsHash string
// 所有频道名称的哈希值
allChannelsHash string
)
// 初始化预计算的哈希值
func init() {
// 预计算空列表的哈希值
precomputedHashes.Store("empty_channels", "all")
// 预计算常用的频道组合哈希值
commonChannels := [][]string{
{"dongman", "anime"},
{"movie", "film"},
{"music", "audio"},
{"book", "ebook"},
}
for _, channels := range commonChannels {
key := strings.Join(channels, ",")
hash := calculateListHash(channels)
precomputedHashes.Store("channels:"+key, hash)
}
// 预计算常用的插件组合哈希值
commonPlugins := [][]string{
{"pan666", "panta"},
{"aliyun", "baidu"},
}
for _, plugins := range commonPlugins {
key := strings.Join(plugins, ",")
hash := calculateListHash(plugins)
precomputedHashes.Store("plugins:"+key, hash)
}
// 预计算所有插件的哈希值
allPlugins := plugin.GetRegisteredPlugins()
allPluginNames := make([]string, 0, len(allPlugins))
for _, p := range allPlugins {
allPluginNames = append(allPluginNames, p.Name())
}
sort.Strings(allPluginNames)
allPluginsHash = calculateListHash(allPluginNames)
precomputedHashes.Store("all_plugins", allPluginsHash)
// 预计算所有频道的哈希值(这里假设有一个全局频道列表)
// 注意:如果没有全局频道列表,可以使用一个默认值
allChannelsHash = "all"
precomputedHashes.Store("all_channels", allChannelsHash)
}
// GenerateCacheKey 根据所有影响搜索结果的参数生成缓存键
func GenerateCacheKey(keyword string, channels []string, sourceType string, plugins []string) string {
// 关键词标准化
normalizedKeyword := strings.ToLower(strings.TrimSpace(keyword))
// 获取频道列表哈希
channelsHash := getChannelsHash(channels)
// 源类型处理
if sourceType == "" {
sourceType = "all"
}
// 插件参数规范化处理
var pluginsHash string
if sourceType == "tg" {
// 对于只搜索Telegram的请求忽略插件参数
pluginsHash = "none"
} else {
// 获取插件列表哈希
pluginsHash = getPluginsHash(plugins)
}
// 生成最终缓存键
keyStr := fmt.Sprintf("%s:%s:%s:%s", normalizedKeyword, channelsHash, sourceType, pluginsHash)
hash := md5.Sum([]byte(keyStr))
return hex.EncodeToString(hash[:])
}
// 获取或计算频道哈希
func getChannelsHash(channels []string) string {
if channels == nil || len(channels) == 0 {
// 使用预计算的所有频道哈希
if hash, ok := precomputedHashes.Load("all_channels"); ok {
return hash.(string)
}
return allChannelsHash
}
// 对于小型列表,直接使用字符串连接
if len(channels) < 5 {
channelsCopy := make([]string, len(channels))
copy(channelsCopy, channels)
sort.Strings(channelsCopy)
// 检查是否有预计算的哈希
key := strings.Join(channelsCopy, ",")
if hash, ok := precomputedHashes.Load("channels:"+key); ok {
return hash.(string)
}
return strings.Join(channelsCopy, ",")
}
// 生成排序后的字符串用作键
channelsCopy := make([]string, len(channels))
copy(channelsCopy, channels)
sort.Strings(channelsCopy)
key := strings.Join(channelsCopy, ",")
// 尝试从缓存获取
if hash, ok := channelHashCache.Load(key); ok {
return hash.(string)
}
// 计算哈希
hash := calculateListHash(channelsCopy)
// 存入缓存
channelHashCache.Store(key, hash)
return hash
}
// 获取或计算插件哈希
func getPluginsHash(plugins []string) string {
// 检查是否为空列表
if plugins == nil || len(plugins) == 0 {
// 使用预计算的所有插件哈希
if hash, ok := precomputedHashes.Load("all_plugins"); ok {
return hash.(string)
}
return allPluginsHash
}
// 检查是否有空字符串元素
hasNonEmptyPlugin := false
for _, p := range plugins {
if p != "" {
hasNonEmptyPlugin = true
break
}
}
// 如果全是空字符串,也视为空列表
if !hasNonEmptyPlugin {
if hash, ok := precomputedHashes.Load("all_plugins"); ok {
return hash.(string)
}
return allPluginsHash
}
// 对于小型列表,直接使用字符串连接
if len(plugins) < 5 {
pluginsCopy := make([]string, 0, len(plugins))
for _, p := range plugins {
if p != "" { // 忽略空字符串
pluginsCopy = append(pluginsCopy, p)
}
}
sort.Strings(pluginsCopy)
// 检查是否有预计算的哈希
key := strings.Join(pluginsCopy, ",")
if hash, ok := precomputedHashes.Load("plugins:"+key); ok {
return hash.(string)
}
return strings.Join(pluginsCopy, ",")
}
// 生成排序后的字符串用作键,忽略空字符串
pluginsCopy := make([]string, 0, len(plugins))
for _, p := range plugins {
if p != "" { // 忽略空字符串
pluginsCopy = append(pluginsCopy, p)
}
}
sort.Strings(pluginsCopy)
key := strings.Join(pluginsCopy, ",")
// 尝试从缓存获取
if hash, ok := pluginHashCache.Load(key); ok {
return hash.(string)
}
// 计算哈希
hash := calculateListHash(pluginsCopy)
// 存入缓存
pluginHashCache.Store(key, hash)
return hash
}
// 计算列表的哈希值
func calculateListHash(items []string) string {
h := md5.New()
for _, item := range items {
h.Write([]byte(item))
}
return hex.EncodeToString(h.Sum(nil))
}
// GenerateCacheKeyV2 根据所有影响搜索结果的参数生成缓存键
// 为保持向后兼容,保留原函数,但标记为已弃用
func GenerateCacheKeyV2(keyword string, channels []string, sourceType string, plugins []string) string {
// 关键词标准化:去除首尾空格,转为小写
normalizedKeyword := strings.ToLower(strings.TrimSpace(keyword))
// 频道处理
var channelsStr string
if channels != nil && len(channels) > 0 {
channelsCopy := make([]string, len(channels))
copy(channelsCopy, channels)
sort.Strings(channelsCopy)
channelsStr = strings.Join(channelsCopy, ",")
} else {
channelsStr = "all"
}
// 插件处理
var pluginsStr string
if plugins != nil && len(plugins) > 0 {
pluginsCopy := make([]string, len(plugins))
copy(pluginsCopy, plugins)
sort.Strings(pluginsCopy)
pluginsStr = strings.Join(pluginsCopy, ",")
} else {
pluginsStr = "all"
}
// 源类型处理
if sourceType == "" {
sourceType = "all"
}
// 生成缓存键字符串
keyStr := fmt.Sprintf("v2:%s:%s:%s:%s", normalizedKeyword, channelsStr, sourceType, pluginsStr)
// 计算MD5哈希
hash := md5.Sum([]byte(keyStr))
return hex.EncodeToString(hash[:])
}
// GenerateCacheKeyLegacy 根据查询和过滤器生成缓存键
// 为保持向后兼容,保留原函数,但重命名为更清晰的名称
func GenerateCacheKeyLegacy(query string, filters map[string]string) string {
// 如果只需要基于关键词的缓存,不考虑过滤器,调用新函数
if filters == nil || len(filters) == 0 {
return GenerateCacheKey(query, nil, "", nil)
}
// 创建包含查询和所有过滤器的字符串
keyStr := query
// 按字母顺序排序过滤器键,确保相同的过滤器集合总是产生相同的键
var keys []string
for k := range filters {
keys = append(keys, k)
}
sort.Strings(keys)
// 添加过滤器到键字符串
for _, k := range keys {
keyStr += "|" + k + "=" + filters[k]
}
// 计算MD5哈希
hash := md5.Sum([]byte(keyStr))
return hex.EncodeToString(hash[:])
}