61 lines
1.9 KiB
Go
61 lines
1.9 KiB
Go
package rpc
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"telesrv/internal/domain"
|
||
"telesrv/internal/readmodelcache"
|
||
)
|
||
|
||
const (
|
||
stickerCatalogCacheMaxEntries = 8
|
||
// stickerCatalogCacheTTL 对齐客户端 trending/贴纸目录 ~5min 刷新率:TTL 内 getAllStickers/
|
||
// getFeaturedStickers/getStickers(emoji 索引重建) 复用同一份集目录,避免每请求 ListStickerSets。
|
||
stickerCatalogCacheTTL = 5 * time.Minute
|
||
)
|
||
|
||
// stickerCatalogCache 缓存 kind→贴纸集目录(全局、非 per-viewer:ListStickerSets 无用户维度)。
|
||
// 内建 TTL + singleflight,让"先查后判 hash"的目录类 RPC 在 hash 命中时不打 PG。
|
||
type stickerCatalogCache struct {
|
||
cache *readmodelcache.Cache[domain.StickerSetKind, []domain.StickerSet]
|
||
}
|
||
|
||
func newStickerCatalogCache(now func() time.Time) *stickerCatalogCache {
|
||
return &stickerCatalogCache{
|
||
cache: readmodelcache.New[domain.StickerSetKind, []domain.StickerSet](readmodelcache.Config[domain.StickerSetKind, []domain.StickerSet]{
|
||
MaxEntries: stickerCatalogCacheMaxEntries,
|
||
TTL: stickerCatalogCacheTTL,
|
||
Now: now,
|
||
}),
|
||
}
|
||
}
|
||
|
||
// stickerCatalogSets 返回某 kind 的(缓存的)贴纸集目录。Files 缺失或出错返回 nil。
|
||
// 返回的切片只读(调用方不得修改元素),需要派生时各自计算 hash/过滤。
|
||
func (r *Router) stickerCatalogSets(ctx context.Context, kind domain.StickerSetKind) []domain.StickerSet {
|
||
if r.deps.Files == nil {
|
||
return nil
|
||
}
|
||
if r.stickerCatalog == nil {
|
||
sets, err := r.deps.Files.ListStickerSets(ctx, kind)
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
return sets
|
||
}
|
||
sets, err := r.stickerCatalog.cache.GetOrLoad(ctx, kind, func() ([]domain.StickerSet, error) {
|
||
return r.deps.Files.ListStickerSets(ctx, kind)
|
||
})
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
return sets
|
||
}
|
||
|
||
func (r *Router) invalidateStickerCatalog(kind domain.StickerSetKind) {
|
||
if r.stickerCatalog == nil || r.stickerCatalog.cache == nil {
|
||
return
|
||
}
|
||
r.stickerCatalog.cache.Invalidate(kind)
|
||
}
|