修复(#1): 服务器用户列表缓存按 protocol 隔离 + 兜底不写缓存
服务器用户列表缓存跨协议污染修复(HIF-1 / 详见 PR #5 四件套): 1. 缓存 key 加 protocol 维度(`server:user:{server_id}:{protocol}`),对齐 ServerConfig 已有约定 2. 显式枚举协议清除用户列表缓存(AllProtocols + ServerUserListCacheKeysForServer),不用 SCAN 3. 三个兜底分支不写缓存 + Errorw 日志(带 server_id + protocol 字段) 4. hysteria2 → hysteria 兼容归一化 + 6 个新单测 Closes HIF-1
This commit is contained in:
@@ -37,7 +37,9 @@ func NewGetServerUserListLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *Ge
|
||||
}
|
||||
|
||||
func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListRequest) (resp *types.GetServerUserListResponse, err error) {
|
||||
cacheKey := fmt.Sprintf("%s%d", node.ServerUserListCacheKey, req.ServerId)
|
||||
protocolRequest := normalizeServerUserListProtocol(req.Protocol)
|
||||
|
||||
cacheKey := fmt.Sprintf("%s%d:%s", node.ServerUserListCacheKey, req.ServerId, protocolRequest)
|
||||
cache, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result()
|
||||
if cache != "" {
|
||||
etag := tool.GenerateETag([]byte(cache))
|
||||
@@ -64,7 +66,7 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR
|
||||
Page: 1,
|
||||
Size: 1000,
|
||||
ServerId: []int64{server.Id},
|
||||
Protocol: req.Protocol,
|
||||
Protocol: protocolRequest,
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("FilterNodeList error", logger.Field("error", err.Error()))
|
||||
@@ -72,6 +74,10 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR
|
||||
}
|
||||
|
||||
if len(nodes) == 0 {
|
||||
l.Errorw("[ServerUserList] fallback: no nodes matched server+protocol, returning placeholder without cache",
|
||||
logger.Field("server_id", req.ServerId),
|
||||
logger.Field("protocol", req.Protocol),
|
||||
)
|
||||
return &types.GetServerUserListResponse{
|
||||
Users: []types.ServerUser{
|
||||
{
|
||||
@@ -139,6 +145,10 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR
|
||||
}
|
||||
|
||||
if len(subs) == 0 {
|
||||
l.Errorw("[ServerUserList] fallback: no subscriptions matched node group/tags, returning placeholder without cache",
|
||||
logger.Field("server_id", req.ServerId),
|
||||
logger.Field("protocol", req.Protocol),
|
||||
)
|
||||
return &types.GetServerUserListResponse{
|
||||
Users: []types.ServerUser{
|
||||
{
|
||||
@@ -183,10 +193,18 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR
|
||||
}
|
||||
|
||||
if len(users) == 0 {
|
||||
users = append(users, types.ServerUser{
|
||||
Id: 1,
|
||||
UUID: uuidx.NewUUID().String(),
|
||||
})
|
||||
l.Errorw("[ServerUserList] fallback: matched subs returned zero eligible users, returning placeholder without cache",
|
||||
logger.Field("server_id", req.ServerId),
|
||||
logger.Field("protocol", req.Protocol),
|
||||
)
|
||||
return &types.GetServerUserListResponse{
|
||||
Users: []types.ServerUser{
|
||||
{
|
||||
Id: 1,
|
||||
UUID: uuidx.NewUUID().String(),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
resp = &types.GetServerUserListResponse{
|
||||
Users: users,
|
||||
@@ -205,6 +223,17 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// normalizeServerUserListProtocol 将客户端可能携带的 hysteria2 兼容字段映射回
|
||||
// DB 中存储的规范名 "hysteria"。其它协议原样返回。
|
||||
// 缓存 key 与 FilterNodeList 查询都必须用归一化后的值,
|
||||
// 否则 hysteria2 永远查不到节点,永远走兜底。
|
||||
func normalizeServerUserListProtocol(protocol string) string {
|
||||
if protocol == Hysteria2 {
|
||||
return Hysteria
|
||||
}
|
||||
return protocol
|
||||
}
|
||||
|
||||
func (l *GetServerUserListLogic) serverUserListCacheTTL() time.Duration {
|
||||
pullInterval := l.svcCtx.Config.Node.NodePullInterval
|
||||
if pullInterval <= 0 {
|
||||
|
||||
Reference in New Issue
Block a user