diff --git a/controller/admin.go b/controller/admin.go index c7527cd..688db37 100644 --- a/controller/admin.go +++ b/controller/admin.go @@ -42,6 +42,42 @@ func AdminAdd(c *gin.Context) { success(c, result) } +func AdminEdit(c *gin.Context) { + var admin model.Admin + if err := c.ShouldBindJSON(&admin); err != nil { + failed(c, "Invalid input: "+err.Error()) + return + } + if admin.ID == 0 { + failed(c, "id is required") + return + } + if err := admin.Edit(); err != nil { + failed(c, "Failed to edit admin: "+err.Error()) + return + } + util.AddAdminLog(c, "编辑管理员", admin) + success(c, "success") +} + +func AdminDelete(c *gin.Context) { + type param struct { + ID int `json:"id"` + } + var p param + if err := c.ShouldBindJSON(&p); err != nil { + failed(c, "Invalid input: "+err.Error()) + return + } + admin := model.Admin{ID: p.ID} + if err := admin.Delete(); err != nil { + failed(c, "Failed to delete admin: "+err.Error()) + return + } + util.AddAdminLog(c, "删除管理员", p) + success(c, "success") +} + func AdminLogList(c *gin.Context) { // 处理管理员日志列表请求 type param struct { diff --git a/controller/apk.go b/controller/apk.go new file mode 100644 index 0000000..2b6b5d6 --- /dev/null +++ b/controller/apk.go @@ -0,0 +1,229 @@ +package controller + +import ( + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + "strings" + "time" + + "backend/util" + + "github.com/gin-gonic/gin" +) + +const ( + apkStorageRoot = "./runtime/apk" + apkManifestName = "manifest.json" + defaultApkUploadToken = "apk-upload-token" + apkUploadTokenHeader = "X-Apk-Upload-Token" + apkUploadTokenEnvName = "APK_UPLOAD_TOKEN" + uploadedAtTimeFormat = time.RFC3339 + defaultApkStorageName = "current.apk" +) + +var apkEnvironments = []string{"dev", "stable", "prod"} + +type apkPackageMeta struct { + DownloadPath string `json:"downloadPath"` + Env string `json:"env"` + Exists bool `json:"exists"` + FileName string `json:"fileName"` + Size int64 `json:"size"` + UploadedAt string `json:"uploadedAt"` + Version string `json:"version"` +} + +type apkManifest struct { + Packages map[string]apkPackageMeta `json:"packages"` +} + +func UploadApkPackage(c *gin.Context) { + if !validateApkUploadToken(c.GetHeader(apkUploadTokenHeader)) { + failed(c, "上传令牌无效") + return + } + + env := strings.TrimSpace(c.PostForm("env")) + if !isValidApkEnv(env) { + failed(c, "无效的 apk 环境,必须是 dev、stable 或 prod") + return + } + + fileHeader, err := c.FormFile("file") + if err != nil { + failed(c, "获取 apk 文件失败: "+err.Error()) + return + } + + if strings.ToLower(filepath.Ext(fileHeader.Filename)) != ".apk" { + failed(c, "仅支持上传 .apk 文件") + return + } + + if err := os.MkdirAll(apkEnvDir(env), 0755); err != nil { + failed(c, "创建 apk 目录失败: "+err.Error()) + return + } + + targetPath := apkFilePath(env) + if err := c.SaveUploadedFile(fileHeader, targetPath); err != nil { + failed(c, "保存 apk 文件失败: "+err.Error()) + return + } + + version := strings.TrimSpace(c.PostForm("version")) + if version == "" { + version = strings.TrimSuffix(fileHeader.Filename, filepath.Ext(fileHeader.Filename)) + } + + meta := apkPackageMeta{ + DownloadPath: apkDownloadPath(env), + Env: env, + Exists: true, + FileName: fileHeader.Filename, + Size: fileHeader.Size, + UploadedAt: time.Now().Format(uploadedAtTimeFormat), + Version: version, + } + + manifest, err := loadApkManifest() + if err != nil { + failed(c, "读取 apk 清单失败: "+err.Error()) + return + } + manifest.Packages[env] = meta + + if err := saveApkManifest(manifest); err != nil { + failed(c, "保存 apk 清单失败: "+err.Error()) + return + } + + log.Printf("apk uploaded env=%s file=%s size=%d", env, fileHeader.Filename, fileHeader.Size) + success(c, meta) +} + +func GetApkPackages(c *gin.Context) { + manifest, err := loadApkManifest() + if err != nil { + failed(c, "读取 apk 清单失败: "+err.Error()) + return + } + + packages := make([]apkPackageMeta, 0, len(apkEnvironments)) + for _, env := range apkEnvironments { + meta := manifest.Packages[env] + if meta.Env == "" { + meta = apkPackageMeta{Env: env} + } + meta.Exists = fileExists(apkFilePath(env)) + meta.DownloadPath = apkDownloadPath(env) + packages = append(packages, meta) + } + + success(c, packages) +} + +func DownloadApkPackage(c *gin.Context) { + env := c.Param("env") + if !isValidApkEnv(env) { + failed(c, "无效的 apk 环境") + return + } + + manifest, err := loadApkManifest() + if err != nil { + failed(c, "读取 apk 清单失败: "+err.Error()) + return + } + + targetPath := apkFilePath(env) + if !fileExists(targetPath) { + failed(c, fmt.Sprintf("%s 环境暂无可下载的 apk 包", env)) + return + } + + meta := manifest.Packages[env] + downloadName := meta.FileName + if strings.TrimSpace(downloadName) == "" { + downloadName = fmt.Sprintf("%s.apk", env) + } + + util.AddAdminLog(c, "下载客户端APK", gin.H{"env": env, "file": downloadName}) + c.FileAttachment(targetPath, downloadName) +} + +func validateApkUploadToken(token string) bool { + expectedToken := strings.TrimSpace(os.Getenv(apkUploadTokenEnvName)) + if expectedToken == "" { + expectedToken = defaultApkUploadToken + } + return strings.TrimSpace(token) != "" && token == expectedToken +} + +func apkEnvDir(env string) string { + return filepath.Join(apkStorageRoot, env) +} + +func apkFilePath(env string) string { + return filepath.Join(apkEnvDir(env), defaultApkStorageName) +} + +func apkManifestPath() string { + return filepath.Join(apkStorageRoot, apkManifestName) +} + +func apkDownloadPath(env string) string { + return fmt.Sprintf("/api/apk/download/%s", env) +} + +func isValidApkEnv(env string) bool { + for _, item := range apkEnvironments { + if item == env { + return true + } + } + return false +} + +func loadApkManifest() (*apkManifest, error) { + manifest := &apkManifest{Packages: map[string]apkPackageMeta{}} + if err := os.MkdirAll(apkStorageRoot, 0755); err != nil { + return nil, err + } + + data, err := os.ReadFile(apkManifestPath()) + if err != nil { + if os.IsNotExist(err) { + return manifest, nil + } + return nil, err + } + + if len(data) == 0 { + return manifest, nil + } + + if err := json.Unmarshal(data, manifest); err != nil { + return nil, err + } + if manifest.Packages == nil { + manifest.Packages = map[string]apkPackageMeta{} + } + return manifest, nil +} + +func saveApkManifest(manifest *apkManifest) error { + data, err := json.MarshalIndent(manifest, "", " ") + if err != nil { + return err + } + return os.WriteFile(apkManifestPath(), data, 0644) +} + +func fileExists(path string) bool { + info, err := os.Stat(path) + return err == nil && !info.IsDir() +} diff --git a/controller/permission.go b/controller/permission.go index 963131e..3c357bc 100644 --- a/controller/permission.go +++ b/controller/permission.go @@ -47,6 +47,10 @@ type userAdminIDRequest struct { AdminID int `json:"admin_id" binding:"required"` } +type userAdminIDsRequest struct { + AdminIDs []int `json:"admin_ids" binding:"required"` +} + func PermissionUserGroupList(c *gin.Context) { var req model.PermissionUserGroupListParams if err := c.ShouldBindJSON(&req); err != nil { @@ -364,3 +368,17 @@ func PermissionUserRoleList(c *gin.Context) { } success(c, roles) } + +func PermissionUserRoleBatchList(c *gin.Context) { + var req userAdminIDsRequest + if err := c.ShouldBindJSON(&req); err != nil { + failed(c, "Invalid input: "+err.Error()) + return + } + roles, err := model.ListUserRolesByAdminIDs(req.AdminIDs) + if err != nil { + failed(c, "Failed to list user roles: "+err.Error()) + return + } + success(c, roles) +} diff --git a/controller/user.go b/controller/user.go index f874c13..304229d 100644 --- a/controller/user.go +++ b/controller/user.go @@ -5,27 +5,81 @@ import ( "backend/store" "backend/util" "fmt" + "log" + "slices" "github.com/gin-gonic/gin" ) func UserInfo(c *gin.Context) { Token := util.GetToken(c) - Info, _ := store.GetTokenInfo(Token) + info, _ := store.GetTokenInfo(Token) + if info == nil { + c.JSON(401, gin.H{"code": 401, "message": "Unauthorized"}) + return + } + homePath := "/dashboard" - if Info.Role == "wb_transfer" { + + // 从 DB 查询用户 ID 及是否 super + db := util.MPool.GetGameDB() + if db == nil { + c.JSON(500, gin.H{"code": 500, "message": "db unavailable"}) + return + } + var adminRow struct { + ID int `db:"id"` + Role int `db:"role"` + } + if err := db.Get(&adminRow, "SELECT id, role FROM admin WHERE username = ?", info.UserName); err != nil { + db.Close() + log.Printf("UserInfo: query admin failed: %v", err) + c.JSON(500, gin.H{"code": 500, "message": "query failed"}) + return + } + db.Close() + + isSuperAdmin := util.GetRole(adminRow.Role) == util.RoleSuper + + // 更新最后登录 IP 和时间 + clientIP := c.ClientIP() + now := int(util.Now()) + db2 := util.MPool.GetGameDB() + if db2 != nil { + db2.Exec("UPDATE admin SET lastLoginIp=?, lastLoginTime=? WHERE id=?", clientIP, now, adminRow.ID) + db2.Close() + } + + effectiveInfo, err := model.GetUserEffectiveInfo(adminRow.ID, isSuperAdmin) + if err != nil { + log.Printf("UserInfo: GetUserEffectiveInfo failed: %v", err) + // 降级:只返回 token 里的静态角色 + effectiveInfo = &model.UserEffectiveInfo{ + Roles: []string{info.Role}, + Permissions: []string{}, + } + } + + // super 在 roles 中补充标记,供前端路由守卫识别 + roles := effectiveInfo.Roles + if isSuperAdmin || slices.Contains(roles, "R_SUPER") { + roles = []string{util.RoleSuper} + } + if len(roles) == 1 && slices.Contains(roles, "R_LANGUAGE") { homePath = "/language" } c.JSON(200, gin.H{ "code": 0, "data": map[string]interface{}{ - "id": 0, - "realName": Info.UserName, - "roles": []string{Info.Role}, - "username": Info.UserName, - "homePath": homePath, + "userId": fmt.Sprintf("%d", adminRow.ID), + "username": info.UserName, + "realName": info.UserName, + "avatar": "", + "homePath": homePath, + "roles": roles, + "permissions": effectiveInfo.Permissions, }, - "message": "Hello, world!", + "message": "ok", }) } diff --git a/db/admin_permission_rbac.sql b/db/admin_permission_rbac.sql index 9c41073..2e4732d 100644 --- a/db/admin_permission_rbac.sql +++ b/db/admin_permission_rbac.sql @@ -168,20 +168,112 @@ ON DUPLICATE KEY UPDATE INSERT INTO `admin_permission` (`permission_code`, `permission_name`, `permission_group`, `api_path`, `http_method`, `status`, `remark`, `create_admin`, `update_admin`, `createTime`, `updateTime`) VALUES - ('AC0001', '管理员列表查询', 'admin', '/api/admin/list', 'POST', 1, '查看管理员列表', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), - ('AC0002', '管理员新增', 'admin', '/api/admin/add', 'POST', 1, '新增后台管理员', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), - ('AC0003', '客户端通知查询', 'notification', '/api/client/notification', 'GET', 1, '查看客户端 notification 配置', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), - ('AC0004', '客户端通知修改', 'notification', '/api/client/notification', 'PUT', 1, '单点权限标签示例:AC0004', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), - ('AC0005', '活动编辑', 'activity', '/api/activity/edit', 'POST', 1, '编辑活动配置', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()) + -- ── 管理员管理 ────────────────────────────────────────────── + ('AC1001', '管理员列表', 'admin', '/api/admin/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1002', '管理员新增', 'admin', '/api/admin/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1003', '管理员操作日志', 'admin', '/api/admin/log/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1004', '管理员配置列表', 'admin', '/api/admin/config/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1005', '管理员配置新增', 'admin', '/api/admin/config/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1006', '管理员配置编辑', 'admin', '/api/admin/config/edit', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 权限管理 ──────────────────────────────────────────────── + ('AC1101', '用户组列表', 'permission', '/api/admin/usergroup/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1102', '用户组新增', 'permission', '/api/admin/usergroup/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1103', '用户组编辑', 'permission', '/api/admin/usergroup/edit', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1104', '用户组删除', 'permission', '/api/admin/usergroup/delete', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1105', '用户组绑定角色', 'permission', '/api/admin/usergroup/role/set', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1106', '用户组角色查询', 'permission', '/api/admin/usergroup/role/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1107', '角色列表', 'permission', '/api/admin/role/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1108', '角色新增', 'permission', '/api/admin/role/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1109', '角色编辑', 'permission', '/api/admin/role/edit', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1110', '角色删除', 'permission', '/api/admin/role/delete', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1111', '角色绑定权限', 'permission', '/api/admin/role/permission/set', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1112', '角色权限查询', 'permission', '/api/admin/role/permission/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1113', '单点权限列表', 'permission', '/api/admin/permission/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1114', '单点权限新增', 'permission', '/api/admin/permission/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1115', '单点权限编辑', 'permission', '/api/admin/permission/edit', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1116', '单点权限删除', 'permission', '/api/admin/permission/delete', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1117', '用户组分配查询', 'permission', '/api/admin/user/group/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1118', '用户组分配设置', 'permission', '/api/admin/user/group/set', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1119', '用户单点权限查询', 'permission', '/api/admin/user/permission/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1120', '用户单点权限设置', 'permission', '/api/admin/user/permission/set', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC1121', '用户角色查询', 'permission', '/api/admin/user/role/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 玩家日志 ──────────────────────────────────────────────── + ('AC2001', '玩家日志查询', 'log', '/api/log/user', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC2002', '资产日志查询', 'log', '/api/log/asset', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC2003', '事件日志查询', 'log', '/api/log/event', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC2004', '月登录次数统计', 'log', '/api/log/loginCountByMonth', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC2005', '订单日志查询', 'log', '/api/log/order', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 玩家数据 ──────────────────────────────────────────────── + ('AC3001', '玩家列表', 'user', '/api/user/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC3002', '当前用户信息', 'user', '/api/user/info', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC3003', 'GM操作', 'user', '/api/user/gm', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC3004', '封禁玩家', 'user', '/api/user/ban', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 服务器管理 ────────────────────────────────────────────── + ('AC4001', '应用列表', 'server', '/api/server/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4002', '服务器列表', 'server', '/api/server/serverList', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4003', '新增服务器', 'server', '/api/server/addServer', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4004', '节点列表', 'server', '/api/server/nodeList', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4005', '新增节点', 'server', '/api/server/addNode', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4006', '编辑服务器', 'server', '/api/server/editServer', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4007', '更新应用', 'server', '/api/server/updateApp', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4008', '更新应用(审核)', 'server', '/api/server/updateAppReview', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4009', '更新应用(飞书)', 'server', '/api/server/updateAppFeishu', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4010', '重启服务器', 'server', '/api/server/restart', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC4011', '重载服务器', 'server', '/api/server/reload', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 统计 ──────────────────────────────────────────────────── + ('AC5001', '等级统计', 'statistics', '/api/statistics/level', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC5002', '订单统计', 'statistics', '/api/statistics/order', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC5003', '基础统计信息', 'statistics', '/api/statistics/info', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC5004', '热力图统计', 'statistics', '/api/statistics/heat', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 活动管理 ──────────────────────────────────────────────── + ('AC6001', '活动列表', 'activity', '/api/activity/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC6002', '活动编辑', 'activity', '/api/activity/edit', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC6003', '活动新增', 'activity', '/api/activity/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC6004', '活动删除', 'activity', '/api/activity/delete', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC6005', '活动同步', 'activity', '/api/activity/sync', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 邮件 ──────────────────────────────────────────────────── + ('AC7001', '发送邮件', 'mail', '/api/mail/send', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC7002', '邮件列表', 'mail', '/api/mail/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC7003', '删除邮件', 'mail', '/api/mail/delete', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 运营功能 ──────────────────────────────────────────────── + ('AC8001', '复制用户数据', 'operation', '/api/operation/copyUser', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 翻译管理 ──────────────────────────────────────────────── + ('AC9001', '语言列表', 'language', '/api/language/list', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9002', '语言导出', 'language', '/api/language/export', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9003', '语言保存', 'language', '/api/language/save', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9004', '语言新增', 'language', '/api/language/add', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9005', '语言删除', 'language', '/api/language/delete', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 通知配置 ──────────────────────────────────────────────── + ('AC9101', '通知配置查询', 'notification', '/api/config/notification', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9102', '通知配置更新', 'notification', '/api/config/notification/update', 'PUT', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── AB 实验 ───────────────────────────────────────────────── + ('AC9201', '实验列表', 'experiment', '/api/v1/experiments', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9202', '实验新增', 'experiment', '/api/v1/experiments', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9203', '实验更新', 'experiment', '/api/v1/experiments/:id', 'PUT', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9204', '实验删除', 'experiment', '/api/v1/experiments/:id', 'DELETE', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9205', '实验变体列表', 'experiment', '/api/v1/experiments/:id/variants', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9206', '实验变体新增', 'experiment', '/api/v1/experiments/:id/variants', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9207', '实验变体更新', 'experiment', '/api/v1/experiments/:id/variants/:variantId', 'PUT', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9208', '实验变体删除', 'experiment', '/api/v1/experiments/:id/variants/:variantId', 'DELETE', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9209', '实验白名单列表', 'experiment', '/api/v1/experiments/:id/whitelist', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9210', '实验白名单新增', 'experiment', '/api/v1/experiments/:id/whitelist', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9211', '实验白名单批量新增', 'experiment', '/api/v1/experiments/:id/whitelist/batch', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9212', '实验白名单删除', 'experiment', '/api/v1/experiments/:id/whitelist/:userId', 'DELETE', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9213', '实验结果查询', 'experiment', '/api/v1/experiments/:id/results', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9214', '用户实验分组查询', 'experiment', '/api/v1/users/:userId/groups', 'GET', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + -- ── 自动化脚本 ────────────────────────────────────────────── + ('AC9301', '下载文案文件', 'scripts', '/api/scripts/copywriting', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9302', '复制线上环境到QA', 'scripts', '/api/scripts/copyonline', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), + ('AC9303', '复制线下环境到QA', 'scripts', '/api/scripts/clientImageGitPull', 'POST', 1, '', 'system', 'system', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()) ON DUPLICATE KEY UPDATE - `permission_name` = VALUES(`permission_name`), + `permission_name` = VALUES(`permission_name`), `permission_group` = VALUES(`permission_group`), - `api_path` = VALUES(`api_path`), - `http_method` = VALUES(`http_method`), - `status` = VALUES(`status`), - `remark` = VALUES(`remark`), - `update_admin` = VALUES(`update_admin`), - `updateTime` = VALUES(`updateTime`); + `api_path` = VALUES(`api_path`), + `http_method` = VALUES(`http_method`), + `status` = VALUES(`status`), + `remark` = VALUES(`remark`), + `update_admin` = VALUES(`update_admin`), + `updateTime` = VALUES(`updateTime`); -- 初始化关联关系示例 INSERT INTO `admin_group_role_rel` (`group_id`, `role_id`, `create_admin`, `createTime`) @@ -199,8 +291,8 @@ SELECT r.id, p.id, 'system', UNIX_TIMESTAMP() FROM `admin_role` r JOIN `admin_permission` p WHERE (r.role_code = 'R_SUPER') - OR (r.role_code = 'R_ACTIVITY' AND p.permission_code IN ('AC0005')) - OR (r.role_code = 'R_NOTIFICATION' AND p.permission_code IN ('AC0003', 'AC0004')) + OR (r.role_code = 'R_ACTIVITY' AND p.permission_code IN ('AC6001','AC6002','AC6003','AC6004','AC6005')) + OR (r.role_code = 'R_NOTIFICATION' AND p.permission_code IN ('AC9101','AC9102')) ON DUPLICATE KEY UPDATE `create_admin` = VALUES(`create_admin`); diff --git a/db/init.sql b/db/init.sql index 5008727..627295b 100644 --- a/db/init.sql +++ b/db/init.sql @@ -67,13 +67,18 @@ CREATE TABLE `admin` ( `id` int NOT NULL AUTO_INCREMENT, `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户名', `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码', + `real_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '真实姓名', + `nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '昵称', `phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '手机号', `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '邮箱', `token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '令牌', `group` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户组', - `status` int DEFAULT NULL COMMENT '状态', + `status` int DEFAULT 1 COMMENT '状态 1=正常 0=禁用', `expires` int DEFAULT 0 COMMENT '过期时间', - `role` int DEFAULT NULL COMMENT '角色', + `role` int DEFAULT NULL COMMENT '角色 0=超管 1=管理员 2=普通用户 99=外包翻译', + `lastLoginTime` int DEFAULT 0 COMMENT '最后登录时间', + `lastLoginIp` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '最后登录IP', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '备注', `createTime` int DEFAULT NULL COMMENT '创建时间', `updateTime` int DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), diff --git a/log/backend.log b/log/backend.log index cdb935b..e69de29 100644 --- a/log/backend.log +++ b/log/backend.log @@ -1,507 +0,0 @@ -[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. - -[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - - using env: export GIN_MODE=release - - using code: gin.SetMode(gin.ReleaseMode) - -[GIN-debug] POST /api/auth/login --> backend/controller.Login (3 handlers) -[GIN-debug] GET /api/auth/Codes --> backend/controller.Codes (3 handlers) -[GIN-debug] POST /api/auth/phoneCode --> backend/controller.PhoneCode (3 handlers) -[GIN-debug] POST /api/auth/phoneLogin --> backend/controller.LoginCode (3 handlers) -[GIN-debug] POST /api/feishu/sendInfo --> backend/controller.FeishuSendInfo (3 handlers) -[GIN-debug] POST /api/feishu/sendInfo2 --> backend/controller.FeishuSendInfo2 (3 handlers) -[GIN-debug] POST /api/feishu/sendWeekInfo --> backend/controller.FeishuSendWeekInfo (3 handlers) -[GIN-debug] POST /api/feishu/updateApp --> backend/controller.FeishuUpdateApp (3 handlers) -[GIN-debug] POST /api/feishu/serverInfo --> backend/controller.FeishuServerInfo (3 handlers) -[GIN-debug] POST /api/feishu/notify --> backend/controller.FeishuNotify (3 handlers) -[GIN-debug] POST /api/feishu/notify/client --> backend/controller.FeishuNotifyClient (3 handlers) -[GIN-debug] POST /api/feishu/notify/order --> backend/controller.FeishuNotifyOrder (3 handlers) -[GIN-debug] POST /api/alibaba/zabbix/notify --> backend/controller.AlibabaNotify (3 handlers) -[GIN-debug] POST /api/alibaba/zabbix/recovery --> backend/controller.AlibabaRecovery (3 handlers) -[GIN-debug] POST /api/alibaba/game/notify --> backend/controller.AlibabaGameNotify (3 handlers) -[GIN-debug] POST /api/alibaba/notify/order --> backend/controller.AlibabaNotifyOrder (3 handlers) -[GIN-debug] GET /api/v1/experiments --> backend/controller.ExperimentList (4 handlers) -[GIN-debug] POST /api/v1/experiments --> backend/controller.ExperimentCreate (4 handlers) -[GIN-debug] PUT /api/v1/experiments/:id --> backend/controller.ExperimentUpdate (4 handlers) -[GIN-debug] DELETE /api/v1/experiments/:id --> backend/controller.ExperimentDelete (4 handlers) -[GIN-debug] GET /api/v1/experiments/:id/variants --> backend/controller.ExperimentVariantList (4 handlers) -[GIN-debug] POST /api/v1/experiments/:id/variants --> backend/controller.ExperimentVariantCreate (4 handlers) -[GIN-debug] PUT /api/v1/experiments/:id/variants/:variantId --> backend/controller.ExperimentVariantUpdate (4 handlers) -[GIN-debug] DELETE /api/v1/experiments/:id/variants/:variantId --> backend/controller.ExperimentVariantDelete (4 handlers) -[GIN-debug] GET /api/v1/experiments/:id/whitelist --> backend/controller.ExperimentWhitelistList (4 handlers) -[GIN-debug] POST /api/v1/experiments/:id/whitelist --> backend/controller.ExperimentWhitelistCreate (4 handlers) -[GIN-debug] POST /api/v1/experiments/:id/whitelist/batch --> backend/controller.ExperimentWhitelistBatchCreate (4 handlers) -[GIN-debug] DELETE /api/v1/experiments/:id/whitelist/:userId --> backend/controller.ExperimentWhitelistDelete (4 handlers) -[GIN-debug] GET /api/v1/experiments/:id/results --> backend/controller.ExperimentResult (4 handlers) -[GIN-debug] GET /api/v1/users/:userId/groups --> backend/controller.UserExperimentGroups (4 handlers) -[GIN-debug] POST /api/admin/list --> backend/controller.AdminList (4 handlers) -[GIN-debug] POST /api/admin/add --> backend/controller.AdminAdd (4 handlers) -[GIN-debug] POST /api/admin/log/list --> backend/controller.AdminLogList (4 handlers) -[GIN-debug] POST /api/admin/config/list --> backend/controller.AdminConfigList (4 handlers) -[GIN-debug] POST /api/admin/config/add --> backend/controller.AdminConfigAdd (4 handlers) -[GIN-debug] POST /api/admin/config/edit --> backend/controller.AdminConfigEdit (4 handlers) -[GIN-debug] POST /api/admin/usergroup/list --> backend/controller.PermissionUserGroupList (4 handlers) -[GIN-debug] POST /api/admin/usergroup/add --> backend/controller.PermissionUserGroupAdd (4 handlers) -[GIN-debug] POST /api/admin/usergroup/edit --> backend/controller.PermissionUserGroupEdit (4 handlers) -[GIN-debug] POST /api/admin/usergroup/delete --> backend/controller.PermissionUserGroupDelete (4 handlers) -[GIN-debug] POST /api/admin/usergroup/role/set --> backend/controller.PermissionGroupRoleSet (4 handlers) -[GIN-debug] POST /api/admin/usergroup/role/list --> backend/controller.PermissionGroupRoleList (4 handlers) -[GIN-debug] POST /api/admin/role/list --> backend/controller.PermissionRoleList (4 handlers) -[GIN-debug] POST /api/admin/role/add --> backend/controller.PermissionRoleAdd (4 handlers) -[GIN-debug] POST /api/admin/role/edit --> backend/controller.PermissionRoleEdit (4 handlers) -[GIN-debug] POST /api/admin/role/delete --> backend/controller.PermissionRoleDelete (4 handlers) -[GIN-debug] POST /api/admin/role/permission/set --> backend/controller.PermissionRolePermissionSet (4 handlers) -[GIN-debug] POST /api/admin/role/permission/list --> backend/controller.PermissionRolePermissionList (4 handlers) -[GIN-debug] POST /api/admin/permission/list --> backend/controller.PermissionPointList (4 handlers) -[GIN-debug] POST /api/admin/permission/add --> backend/controller.PermissionPointAdd (4 handlers) -[GIN-debug] POST /api/admin/permission/edit --> backend/controller.PermissionPointEdit (4 handlers) -[GIN-debug] POST /api/admin/permission/delete --> backend/controller.PermissionPointDelete (4 handlers) -[GIN-debug] POST /api/admin/user/group/list --> backend/controller.PermissionUserGroupRelList (4 handlers) -[GIN-debug] POST /api/admin/user/group/set --> backend/controller.PermissionUserGroupRelSet (4 handlers) -[GIN-debug] POST /api/log/user --> backend/controller.UserDetail (4 handlers) -[GIN-debug] POST /api/log/asset --> backend/controller.Asset (4 handlers) -[GIN-debug] POST /api/log/event --> backend/controller.Event (4 handlers) -[GIN-debug] POST /api/log/loginCountByMonth --> backend/controller.LoginCountByMonth (4 handlers) -[GIN-debug] POST /api/log/order --> backend/controller.Order (4 handlers) -[GIN-debug] POST /api/user/list --> backend/controller.UserList (4 handlers) -[GIN-debug] GET /api/user/info --> backend/controller.UserInfo (4 handlers) -[GIN-debug] POST /api/user/gm --> backend/controller.UserGM (4 handlers) -[GIN-debug] POST /api/user/ban --> backend/controller.UserBan (4 handlers) -[GIN-debug] POST /api/server/list --> backend/controller.AppList (4 handlers) -[GIN-debug] POST /api/server/serverList --> backend/controller.ServerList (4 handlers) -[GIN-debug] POST /api/server/addServer --> backend/controller.AddServer (4 handlers) -[GIN-debug] POST /api/server/nodeList --> backend/controller.NodeList (4 handlers) -[GIN-debug] POST /api/server/addNode --> backend/controller.AddNode (4 handlers) -[GIN-debug] POST /api/server/editServer --> backend/controller.EditServer (4 handlers) -[GIN-debug] POST /api/server/updateApp --> backend/controller.UpdateApp (4 handlers) -[GIN-debug] POST /api/server/updateAppReview --> backend/controller.UpdateAppReview (4 handlers) -[GIN-debug] POST /api/server/updateAppFeishu --> backend/controller.UpdateAppFeishu (4 handlers) -[GIN-debug] POST /api/server/restart --> backend/controller.RestartServer (4 handlers) -[GIN-debug] POST /api/server/reload --> backend/controller.ReloadServer (4 handlers) -[GIN-debug] POST /api/statistics/level --> backend/controller.StatisticsLevel (4 handlers) -[GIN-debug] POST /api/statistics/order --> backend/controller.StatisticsOrder (4 handlers) -[GIN-debug] POST /api/statistics/info --> backend/controller.StatisticsInfo (4 handlers) -[GIN-debug] POST /api/statistics/heat --> backend/controller.StatisticsHeat (4 handlers) -[GIN-debug] POST /api/activity/list --> backend/controller.ActivityList (4 handlers) -[GIN-debug] POST /api/activity/edit --> backend/controller.ActivityEdit (4 handlers) -[GIN-debug] POST /api/activity/add --> backend/controller.ActivityAdd (4 handlers) -[GIN-debug] POST /api/activity/delete --> backend/controller.ActivityDelete (4 handlers) -[GIN-debug] POST /api/activity/sync --> backend/controller.ActivitySync (4 handlers) -[GIN-debug] POST /api/mail/send --> backend/controller.SendMail (4 handlers) -[GIN-debug] POST /api/mail/list --> backend/controller.MailList (4 handlers) -[GIN-debug] POST /api/mail/delete --> backend/controller.MailDelete (4 handlers) -[GIN-debug] POST /api/operation/copyUser --> backend/controller.CopyUser (4 handlers) -[GIN-debug] POST /api/language/list --> backend/controller.Language (4 handlers) -[GIN-debug] POST /api/language/export --> backend/controller.LanguageExport (4 handlers) -[GIN-debug] POST /api/language/save --> backend/controller.LanguageSave (4 handlers) -[GIN-debug] POST /api/language/add --> backend/controller.LanguageAdd (4 handlers) -[GIN-debug] POST /api/language/delete --> backend/controller.LanguageDelete (4 handlers) -[GIN-debug] GET /api/config/notification --> backend/controller.NotificationConfigGet (4 handlers) -[GIN-debug] PUT /api/config/notification/update --> backend/controller.NotificationConfigSave (4 handlers) -[GIN-debug] POST /api/scripts/copywriting --> backend/controller.Copywriting (4 handlers) -[GIN-debug] POST /api/scripts/copyonline --> backend/controller.CopyOnline (4 handlers) -[GIN-debug] POST /api/scripts/clientImageGitPull --> backend/controller.ClientImageGitPull (4 handlers) -[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value. -Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details. -[GIN-debug] Listening and serving HTTP on :5320 -2026/04/28 15:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -[GIN] 2026/04/28 - 15:27:43 | 401 | 0s | ::1 | POST "/api/server/list" -[GIN] 2026/04/28 - 15:27:43 | 401 | 0s | ::1 | POST "/api/mail/list" -[GIN] 2026/04/28 - 15:27:43 | 404 | 0s | ::1 | POST "/api/auth/logout" -[GIN] 2026/04/28 - 15:27:43 | 404 | 0s | ::1 | POST "/api/auth/logout" -[GIN] 2026/04/28 - 15:27:51 | 200 | 81.32ms | ::1 | POST "/api/auth/login" -[GIN] 2026/04/28 - 15:27:51 | 200 | 533.1µs | ::1 | GET "/api/auth/Codes" -[GIN] 2026/04/28 - 15:27:51 | 200 | 58.65ms | ::1 | GET "/api/user/info" -[GIN] 2026/04/28 - 15:27:52 | 200 | 199.04ms | ::1 | POST "/api/server/list" -[GIN] 2026/04/28 - 15:27:52 | 200 | 298.53ms | ::1 | POST "/api/mail/list" -2026/04/28 15:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -[GIN] 2026/04/28 - 15:28:29 | 200 | 325.47ms | ::1 | POST "/api/mail/send" -2026/04/28 15:28:29 failed to send admin message: ReloadMail failed: rpc error: code = Unimplemented desc = unknown method ReloadMail for service tutorial.Backend -2026/04/28 15:28:29 sent reload mail message to server 0 -2026/04/28 15:28:29 sent reload mail message to server 2 -2026/04/28 15:28:29 sent reload mail message to server 1 -[GIN] 2026/04/28 - 15:28:30 | 200 | 197.42ms | ::1 | POST "/api/mail/list" -2026/04/28 15:28:32 failed to send admin message: ReloadMail failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:28:32 sent reload mail message to server 3 -2026/04/28 15:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:50:04 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:51:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:52:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:53:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:54:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:55:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:56:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:57:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:58:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 15:59:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:00:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:01:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:02:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:03:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:04:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:05:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:06:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:07:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:08:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:09:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:10:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:11:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:12:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:13:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:14:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:15:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:16:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:17:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:18:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:19:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:20:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:21:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:22:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:23:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:24:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:25:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:26:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:50:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:51:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:52:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:53:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:54:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:55:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:56:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:57:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:58:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 16:59:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:00:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:01:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:02:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:03:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:04:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:05:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:06:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:07:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:08:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:09:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:10:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:11:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:12:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:13:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:14:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:15:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:16:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:17:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:18:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:19:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:20:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:21:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:22:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:23:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:24:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:25:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:26:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:50:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:51:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:52:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:53:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:54:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:55:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:56:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:57:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:58:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 17:59:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:00:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:01:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:02:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:03:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:04:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:05:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:06:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:07:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:08:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:09:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:10:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:11:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:12:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:13:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:14:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:15:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:16:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:17:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:18:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:19:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:20:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:21:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:22:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:23:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:24:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:25:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:26:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:50:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:51:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:52:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:53:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:54:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:55:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:56:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:57:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:58:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 18:59:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:00:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:01:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:02:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:03:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:04:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:05:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:06:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:07:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:08:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:09:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:10:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:11:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:12:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:13:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:14:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:15:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:16:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:17:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:18:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:19:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:20:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:21:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:22:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:23:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:24:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:25:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:26:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:50:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:51:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:52:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:53:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:54:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:55:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:56:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:57:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:58:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 19:59:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:00:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:01:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:02:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:03:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:04:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:05:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:06:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:07:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:08:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:09:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:10:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:11:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:12:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:13:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:14:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:15:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:16:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:17:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:18:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:19:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:20:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:21:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:22:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:23:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:24:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:25:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:26:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:50:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:51:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:52:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:53:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:54:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:55:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:56:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:57:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:58:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 20:59:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:00:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:01:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:02:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:03:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:04:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:05:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:06:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:07:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:08:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:09:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:10:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:11:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:12:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:13:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:14:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:15:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:16:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:17:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:18:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:19:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:20:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:21:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:22:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:23:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:24:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:25:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:26:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:27:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:28:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:29:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:30:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:31:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:32:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:33:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:34:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:35:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:36:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:37:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:38:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:39:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:40:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:41:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:42:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:43:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:44:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:45:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:46:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:47:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:48:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:49:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded -2026/04/28 21:50:03 Failed to get server info for AppId=1, ServerId=3: ServerInfo failed: rpc error: code = DeadlineExceeded desc = received context error while waiting for new LB policy update: context deadline exceeded diff --git a/main.go b/main.go index d9d0040..90eeb44 100644 --- a/main.go +++ b/main.go @@ -78,6 +78,10 @@ func main() { } }() r := gin.Default() + openApi := r.Group("/api/open") + { + openApi.POST("/apk/upload", controller.UploadApkPackage) + } loginApi := r.Group("/api/auth") { // 认证 @@ -128,9 +132,18 @@ func main() { } api := r.Group("/api", middleware.ValidateToken()) { + // 以下路由只校验 token,不校验权限 + r.GET("/api/user/info", middleware.ValidateTokenOnly(), controller.UserInfo) + r.POST("/api/statistics/info", middleware.ValidateTokenOnly(), controller.StatisticsInfo) + r.POST("/api/statistics/level", middleware.ValidateTokenOnly(), controller.StatisticsLevel) + r.POST("/api/statistics/order", middleware.ValidateTokenOnly(), controller.StatisticsOrder) + r.POST("/api/statistics/heat", middleware.ValidateTokenOnly(), controller.StatisticsHeat) + // 账号管理 api.POST("/admin/list", controller.AdminList) api.POST("/admin/add", controller.AdminAdd) + api.POST("/admin/edit", controller.AdminEdit) + api.POST("/admin/delete", controller.AdminDelete) api.POST("/admin/log/list", controller.AdminLogList) api.POST("/admin/config/list", controller.AdminConfigList) api.POST("/admin/config/add", controller.AdminConfigAdd) @@ -156,6 +169,7 @@ func main() { api.POST("/admin/user/permission/list", controller.PermissionUserPermissionList) api.POST("/admin/user/permission/set", controller.PermissionUserPermissionSet) api.POST("/admin/user/role/list", controller.PermissionUserRoleList) + api.POST("/admin/user/role/batch-list", controller.PermissionUserRoleBatchList) // 玩家日志 api.POST("/log/user", controller.UserDetail) api.POST("/log/asset", controller.Asset) @@ -165,7 +179,6 @@ func main() { // 玩家数据 api.POST("/user/list", controller.UserList) - api.GET("/user/info", controller.UserInfo) api.POST("/user/gm", controller.UserGM) api.POST("/user/ban", controller.UserBan) @@ -182,11 +195,6 @@ func main() { api.POST("/server/restart", controller.RestartServer) api.POST("/server/reload", controller.ReloadServer) - api.POST("/statistics/level", controller.StatisticsLevel) - api.POST("/statistics/order", controller.StatisticsOrder) - api.POST("/statistics/info", controller.StatisticsInfo) - api.POST("/statistics/heat", controller.StatisticsHeat) - //活动 api.POST("/activity/list", controller.ActivityList) api.POST("/activity/edit", controller.ActivityEdit) @@ -200,6 +208,8 @@ func main() { api.POST("/mail/delete", controller.MailDelete) // 运营功能 api.POST("/operation/copyUser", controller.CopyUser) + api.GET("/apk/packages", controller.GetApkPackages) + api.GET("/apk/download/:env", controller.DownloadApkPackage) // 翻译 api.POST("/language/list", controller.Language) diff --git a/middleware/ginMid.go b/middleware/ginMid.go index 8652a81..6add2a8 100644 --- a/middleware/ginMid.go +++ b/middleware/ginMid.go @@ -30,7 +30,7 @@ func ValidateToken() gin.HandlerFunc { // 验证用户权限 if tokenInfo != nil { - hasPermission := model.CheckUserPermission(tokenInfo.UserName, path) + hasPermission := model.CheckUserPermission(tokenInfo.UserName, path, c.Request.Method) if !hasPermission { c.JSON(403, gin.H{"error": "Permission denied"}) c.Abort() @@ -41,3 +41,23 @@ func ValidateToken() gin.HandlerFunc { c.Next() } } + +// ValidateTokenOnly 只校验 token 有效性,不做权限校验 +func ValidateTokenOnly() gin.HandlerFunc { + return func(c *gin.Context) { + token := c.GetHeader("Authorization") + if len(token) > 7 && token[:7] == "Bearer " { + token = token[7:] + } + if token == "" || !store.IsTokenValid(token) { + c.JSON(401, gin.H{"error": "Authorization header is required"}) + c.Abort() + return + } + tokenInfo, _ := store.GetTokenInfo(token) + if tokenInfo != nil { + c.Set("admin", tokenInfo.UserName) + } + c.Next() + } +} diff --git a/model/Statistics.go b/model/Statistics.go index 9f16fd8..dde0a4a 100644 --- a/model/Statistics.go +++ b/model/Statistics.go @@ -5,8 +5,24 @@ import ( "fmt" "sort" "strconv" + "sync" + "time" ) +type statisticsInfoCacheEntry struct { + data map[string]interface{} + expireAt time.Time +} + +var statisticsInfoCache = struct { + mu sync.RWMutex + items map[int]statisticsInfoCacheEntry +}{ + items: make(map[int]statisticsInfoCacheEntry), +} + +const statisticsInfoCacheTTL = time.Minute + type Statistics struct { AppId int `json:"AppId"` ServerList []int `json:"ServerList"` @@ -57,40 +73,62 @@ func (s *Statistics) StatisticsLevel() (interface{}, error) { } func (s *Statistics) StatisticsInfo() (interface{}, error) { + statisticsInfoCache.mu.RLock() + if entry, ok := statisticsInfoCache.items[s.AppId]; ok && time.Now().Before(entry.expireAt) { + cached := make(map[string]interface{}, len(entry.data)) + for k, v := range entry.data { + cached[k] = v + } + statisticsInfoCache.mu.RUnlock() + return cached, nil + } + statisticsInfoCache.mu.RUnlock() + AppConfig, err := util.GetAppConfig(s.AppId) if err != nil { return nil, err } - LogDb := util.MPool.GetTopicDB(AppConfig.Topic) - defer LogDb.Close() - if LogDb == nil { - return nil, fmt.Errorf("failed to get mysql database") + overview, err := util.CountStatisticsOverview(s.AppId, AppConfig.OpenTime, AppConfig.Tz) + if err != nil { + return nil, err } - var Register int - var TotalRegistger int - var Recharge float64 - var TotalRecharge float64 - var RechargeUser int - - rechargeFloat, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", Recharge), 64) - totalRechargeFloat, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", TotalRecharge), 64) - return map[string]interface{}{ - "register": Register, - "totalRegister": TotalRegistger, + rechargeFloat, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", overview.Recharge), 64) + totalRechargeFloat, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", overview.TotalRecharge), 64) + result := map[string]interface{}{ + "register": overview.Register, + "totalRegister": overview.TotalRegister, "recharge": rechargeFloat, "totalRecharge": totalRechargeFloat, - "rechargeUser": RechargeUser, - "totalRechargeUser": 0, + "rechargeUser": overview.RechargeUser, + "totalRechargeUser": overview.TotalRechargeUser, "remain": 0, - }, nil + } + + statisticsInfoCache.mu.Lock() + statisticsInfoCache.items[s.AppId] = statisticsInfoCacheEntry{ + data: result, + expireAt: time.Now().Add(statisticsInfoCacheTTL), + } + statisticsInfoCache.mu.Unlock() + + return result, nil } func (s *Statistics) StatisticsHeat() (interface{}, error) { + AppConfig, err := util.GetAppConfig(s.AppId) + if err != nil { + return nil, err + } + trend, err := util.CountStatisticsHeat7Days(s.AppId, AppConfig.Tz) + if err != nil { + return nil, err + } + return map[string]interface{}{ - "key": nil, - "value": nil, - "value2": nil, + "key": trend.Key, + "value": trend.DailyActive, + "value2": trend.Register, }, nil } diff --git a/model/admin.go b/model/admin.go index 62e43ad..fb703e9 100644 --- a/model/admin.go +++ b/model/admin.go @@ -4,6 +4,7 @@ import ( "backend/store" "backend/util" "fmt" + "strings" "github.com/gin-gonic/gin" ) @@ -38,15 +39,13 @@ type AdminLog struct { } func (a *Admin) List() (*Result, error) { - // 这里可以添加数据库查询逻辑来获取管理员列表 - // 假设我们从数据库中查询到数据并返回 var admins []Admin - db := util.MPool.GetGameDB() // 假设使用默认的AppConfig和ServerId为0 + db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } - err := db.Select(&admins, "SELECT * FROM admin") + err := db.Select(&admins, "SELECT `id`,`username`,`real_name`,`nickname`,`phone`,`email`,`group`,`status`,`role`,`lastLoginTime`,`lastLoginIp`,`createTime`,`updateTime`,`remark` FROM admin ORDER BY id DESC") if err != nil { return nil, fmt.Errorf("failed to scan rows: %v", err) } @@ -69,8 +68,11 @@ func (a *Admin) Add() (*Result, error) { defer db.Close() a.CreateTime = int(util.Now()) a.UpdateTime = a.CreateTime - a.Password, _ = util.Encrypt(a.Password) // 假设有一个加密函数 - _, err := db.NamedExec("INSERT INTO admin (`username`, `password`, `phone`, `email`, `token`, `group`, `status`, `role`, `createTime`, `updateTime`, `expires`, `remark`) VALUES (:username, :password, :phone, :email, :token, :group, :status, :role, :createTime, :updateTime, :expires, :remark)", a) + if a.Status == 0 { + a.Status = 1 // 默认启用 + } + a.Password, _ = util.Encrypt(a.Password) + _, err := db.NamedExec("INSERT INTO admin (`username`, `password`, `real_name`, `nickname`, `phone`, `email`, `token`, `group`, `status`, `role`, `createTime`, `updateTime`, `expires`, `remark`) VALUES (:username, :password, :real_name, :nickname, :phone, :email, :token, :group, :status, :role, :createTime, :updateTime, :expires, :remark)", a) if err != nil { return nil, fmt.Errorf("failed to add admin: %v", err) } @@ -186,6 +188,32 @@ func InitToken() { } } +func (a *Admin) Edit() error { + db := util.MPool.GetGameDB() + defer db.Close() + if db == nil { + return fmt.Errorf("failed to get database connection") + } + a.UpdateTime = int(util.Now()) + if a.Password != "" { + a.Password, _ = util.Encrypt(a.Password) + _, err := db.NamedExec("UPDATE admin SET `real_name`=:real_name, `nickname`=:nickname, `phone`=:phone, `email`=:email, `group`=:group, `role`=:role, `status`=:status, `remark`=:remark, `password`=:password, `updateTime`=:updateTime WHERE id=:id", a) + return err + } + _, err := db.NamedExec("UPDATE admin SET `real_name`=:real_name, `nickname`=:nickname, `phone`=:phone, `email`=:email, `group`=:group, `role`=:role, `status`=:status, `remark`=:remark, `updateTime`=:updateTime WHERE id=:id", a) + return err +} + +func (a *Admin) Delete() error { + db := util.MPool.GetGameDB() + defer db.Close() + if db == nil { + return fmt.Errorf("failed to get database connection") + } + _, err := db.Exec("DELETE FROM admin WHERE id = ?", a.ID) + return err +} + func SendPhoneCode(phone string) error { // 这里可以添加逻辑来发送验证码到手机 // 假设我们使用一个外部服务发送验证码 @@ -197,83 +225,90 @@ func SendPhoneCode(phone string) error { return nil } -var PermissionList = map[string][]string{ - "/api/admin/list": {"super", "admin"}, - "/api/admin/add": {"super"}, - "/api/admin/log/list": {"super", "admin"}, - "/api/admin/usergroup/list": {"super", "admin"}, - "/api/admin/usergroup/add": {"super", "admin"}, - "/api/admin/usergroup/edit": {"super", "admin"}, - "/api/admin/usergroup/delete": {"super", "admin"}, - "/api/admin/usergroup/role/set": {"super", "admin"}, - "/api/admin/usergroup/role/list": {"super", "admin"}, - "/api/admin/role/list": {"super", "admin"}, - "/api/admin/role/add": {"super", "admin"}, - "/api/admin/role/edit": {"super", "admin"}, - "/api/admin/role/delete": {"super", "admin"}, - "/api/admin/role/permission/set": {"super", "admin"}, - "/api/admin/role/permission/list": {"super", "admin"}, - "/api/admin/permission/list": {"super", "admin"}, - "/api/admin/permission/add": {"super", "admin"}, - "/api/admin/permission/edit": {"super", "admin"}, - "/api/admin/permission/delete": {"super", "admin"}, - "/api/admin/user/group/list": {"super", "admin"}, - "/api/admin/user/group/set": {"super", "admin"}, - "/api/log/user": {"super", "admin", "user"}, - "/api/log/asset": {"super", "admin", "user"}, - "/api/log/event": {"super", "admin", "user"}, - "/api/log/order": {"super", "admin", "user"}, - "/api/user/list": {"super", "admin", "user"}, - "/api/user/gm": {"super", "admin"}, - "/api/user/ban": {"super", "admin"}, - "/api/server/list": {"super", "admin"}, - "/api/server/serverList": {"super", "admin"}, - "/api/server/addServer": {"super"}, - "/api/server/nodeList": {"super"}, - "/api/server/addNode": {"super"}, - "/api/server/updateApp": {"super", "admin"}, - "/api/server/restart": {"super", "admin"}, - "/api/server/reload": {"super", "admin"}, - "/api/statistics/level": {"super", "admin"}, - "/api/statistics/order": {"super", "admin"}, - "/api/statistics/info": {"super", "admin"}, - "/api/statistics/heat": {"super", "admin"}, - "/api/mail/send": {"super", "admin"}, - "/api/mail/list": {"super", "admin"}, - "/api/mail/delete": {"super", "admin"}, - "/api/language/list": {"super", "admin", "wb_transfer"}, - "/api/language/export": {"super", "admin", "wb_transfer"}, - "/api/language/save": {"super", "admin", "wb_transfer"}, - "/api/language/add": {"super", "admin", "wb_transfer"}, - "/api/language/delete": {"super", "admin"}, - "/api/client/notification": {"super", "admin"}, - "/api/v1/experiments": {"super", "admin"}, - "/api/v1/experiments/:id": {"super", "admin"}, - "/api/v1/experiments/:id/variants": {"super", "admin"}, - "/api/v1/experiments/:id/variants/:variantId": {"super", "admin"}, - "/api/v1/experiments/:id/whitelist": {"super", "admin"}, - "/api/v1/experiments/:id/whitelist/batch": {"super", "admin"}, - "/api/v1/experiments/:id/whitelist/:userId": {"super", "admin"}, - "/api/v1/experiments/:id/results": {"super", "admin"}, - "/api/v1/users/:userId/groups": {"super", "admin"}, -} - -func CheckUserPermission(username, path string) bool { - Admin := &Admin{} - err := Admin.GetAdmin(username) - if err != nil { +// CheckUserPermission 基于 admin_permission 表进行动态 DB 鉴权。 +// 鉴权优先级:super 全放行 → 路径无受控权限点放行 → +// 用户直接权限(显式允许/拒绝)→ 用户组→角色→权限链路 → 默认拒绝。 +func CheckUserPermission(username, path, method string) bool { + db := util.MPool.GetGameDB() + if db == nil { return false } - PermissionRoles, exists := PermissionList[path] - if !exists { - // 如果路径不存在于权限列表中,默认允许访问 + defer db.Close() + + // 查询用户 ID 和角色 + var adminInfo struct { + ID int `db:"id"` + Role int `db:"role"` + } + if err := db.Get(&adminInfo, "SELECT id, role FROM admin WHERE username = ?", username); err != nil { + return false + } + + // super 超级管理员跳过所有权限检查 + if util.GetRole(adminInfo.Role) == util.RoleSuper { return true } - for _, role := range PermissionRoles { - if util.GetRole(Admin.Role) == role { - return true + + // 用户通过用户组继承到 R_SUPER 角色时放行 + var superRoleCount int + if err := db.Get(&superRoleCount, + `SELECT COUNT(*) + FROM admin_user_group_rel ugr + INNER JOIN admin_group_role_rel grr ON grr.group_id = ugr.group_id + INNER JOIN admin_role r ON r.id = grr.role_id + WHERE ugr.admin_id = ? AND r.role_code = 'R_SUPER' AND r.status = 1`, + adminInfo.ID, + ); err == nil && superRoleCount > 0 { + return true + } + + // 查找匹配路径的受控权限点(http_method 为空视为不限方法) + var permIDs []int + if err := db.Select(&permIDs, + "SELECT id FROM admin_permission WHERE api_path = ? AND status = 1 AND (http_method = '' OR http_method = ?)", + path, method, + ); err != nil || len(permIDs) == 0 { + // 路径未被任何权限点管控 → 放行 + return true + } + + // 检查用户直接权限(优先级最高) + for _, pid := range permIDs { + var grantType int + err := db.Get(&grantType, + "SELECT grant_type FROM admin_user_permission_rel WHERE admin_id = ? AND permission_id = ?", + adminInfo.ID, pid, + ) + if err == nil { + if grantType == 2 { + return false // 显式拒绝 + } + if grantType == 1 { + return true // 显式允许 + } } } + + // 检查 用户 → 用户组 → 角色 → 权限 链路 + placeholders := make([]string, len(permIDs)) + pidArgs := make([]interface{}, 1+len(permIDs)) + pidArgs[0] = adminInfo.ID + for i, pid := range permIDs { + placeholders[i] = "?" + pidArgs[i+1] = pid + } + var count int + q := fmt.Sprintf( + `SELECT COUNT(*) FROM admin_role_permission_rel rpr + INNER JOIN admin_group_role_rel grr ON grr.role_id = rpr.role_id + INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id + WHERE ugr.admin_id = ? AND rpr.permission_id IN (%s)`, + strings.Join(placeholders, ","), + ) + if err := db.Get(&count, q, pidArgs...); err == nil && count > 0 { + return true + } + return false } diff --git a/model/permission.go b/model/permission.go index eee1e95..1a1af10 100644 --- a/model/permission.go +++ b/model/permission.go @@ -541,3 +541,135 @@ func ListUserRoles(adminID int) ([]PermissionRole, error) { } return list, nil } + +func ListUserRolesByAdminIDs(adminIDs []int) (map[int][]PermissionRole, error) { + result := make(map[int][]PermissionRole, len(adminIDs)) + if len(adminIDs) == 0 { + return result, nil + } + + db := util.MPool.GetGameDB() + defer db.Close() + if db == nil { + return nil, fmt.Errorf("failed to get database connection") + } + + placeholders := strings.TrimRight(strings.Repeat("?,", len(adminIDs)), ",") + args := make([]interface{}, 0, len(adminIDs)) + for _, adminID := range adminIDs { + args = append(args, adminID) + result[adminID] = []PermissionRole{} + } + + type userRoleRow struct { + AdminID int `db:"admin_id"` + PermissionRole + } + + rows := []userRoleRow{} + query := `SELECT DISTINCT ugr.admin_id, r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime + FROM admin_role r + INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id + INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id + WHERE ugr.admin_id IN (` + placeholders + `) + ORDER BY ugr.admin_id ASC, r.id DESC` + if err := db.Select(&rows, query, args...); err != nil { + return nil, err + } + + for _, row := range rows { + result[row.AdminID] = append(result[row.AdminID], row.PermissionRole) + } + + return result, nil +} + +// UserEffectiveInfo 用户登录后的有效权限摘要 +type UserEffectiveInfo struct { + // Roles 用户通过用户组继承的角色 code 列表 + Roles []string `json:"roles"` + // Permissions 用户最终有效的权限 code 列表: + // 角色链路授予 + 直接允许(grant_type=1),再减去直接拒绝(grant_type=2) + Permissions []string `json:"permissions"` +} + +// GetUserEffectiveInfo 一次查询返回用户的有效角色和权限列表。 +// adminID 为 admin 表的 id,isSuperAdmin 时直接返回空列表(表示不受控)。 +func GetUserEffectiveInfo(adminID int, isSuperAdmin bool) (*UserEffectiveInfo, error) { + if isSuperAdmin { + return &UserEffectiveInfo{Roles: []string{}, Permissions: []string{}}, nil + } + + db := util.MPool.GetGameDB() + if db == nil { + return nil, fmt.Errorf("failed to get database connection") + } + defer db.Close() + + // 1. 角色 code 列表(用户组 → 角色) + var roleCodes []string + roleQuery := `SELECT DISTINCT r.role_code + FROM admin_role r + INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id + INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id + WHERE ugr.admin_id = ? AND r.status = 1` + if err := db.Select(&roleCodes, roleQuery, adminID); err != nil { + return nil, err + } + if roleCodes == nil { + roleCodes = []string{} + } + + // 2. 通过角色链路获得的权限 code 集合 + permSet := map[string]struct{}{} + if len(roleCodes) > 0 { + ph := strings.Repeat("?,", len(roleCodes)) + ph = ph[:len(ph)-1] + args := make([]interface{}, len(roleCodes)) + for i, c := range roleCodes { + args[i] = c + } + var rolePerm []string + q := fmt.Sprintf(`SELECT DISTINCT p.permission_code + FROM admin_permission p + INNER JOIN admin_role_permission_rel rpr ON rpr.permission_id = p.id + INNER JOIN admin_role r ON r.id = rpr.role_id + WHERE r.role_code IN (%s) AND p.status = 1`, ph) + if err := db.Select(&rolePerm, q, args...); err != nil { + return nil, err + } + for _, code := range rolePerm { + permSet[code] = struct{}{} + } + } + + // 3. 直接单点权限:允许补入,拒绝剔除 + var directPerms []struct { + Code string `db:"permission_code"` + GrantType int `db:"grant_type"` + } + directQuery := `SELECT p.permission_code, rel.grant_type + FROM admin_permission p + INNER JOIN admin_user_permission_rel rel ON rel.permission_id = p.id + WHERE rel.admin_id = ? AND p.status = 1` + if err := db.Select(&directPerms, directQuery, adminID); err != nil { + return nil, err + } + for _, dp := range directPerms { + if dp.GrantType == 1 { + permSet[dp.Code] = struct{}{} + } else if dp.GrantType == 2 { + delete(permSet, dp.Code) + } + } + + perms := make([]string, 0, len(permSet)) + for code := range permSet { + perms = append(perms, code) + } + + return &UserEffectiveInfo{ + Roles: roleCodes, + Permissions: perms, + }, nil +} diff --git a/monitor/Monitor.go b/monitor/Monitor.go index 1171587..12c1e48 100644 --- a/monitor/Monitor.go +++ b/monitor/Monitor.go @@ -7,6 +7,7 @@ import ( "backend/model" "backend/msg" "backend/util" + "errors" "fmt" "log" "net" @@ -59,10 +60,10 @@ func ServerInfoMonitor() { } func monitorServerInfo() { - Db := util.MPool.GetGameDB() + db := util.MPool.GetGameDB() var server []*Type.ServerInfo - defer Db.Close() - err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Host`, `Port` FROM server ") + defer db.Close() + err := db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Host`, `Port` FROM server ") if err != nil { return } @@ -70,85 +71,117 @@ func monitorServerInfo() { if v.Status == 2 || v.Status == 3 { // 维护中或停用跳过 continue } - if v.AppId == 1 || v.AppId == 2 { // example condition, adjust as needed - go func(v *Type.ServerInfo) { - resp, err := client.GetServerInfo(v.AppId, v.ServerId, &msg.ReqServerInfo{}) - if err != nil { - log.Printf("Failed to get server info for AppId=%d, ServerId=%d: %v", v.AppId, v.ServerId, err) - return - } - tmpDb := util.MPool.GetGameDB() - defer tmpDb.Close() - latency, err := util.GetAddressLatency(v.Host, v.Port) - if err != nil { - // Connection failed, mark server as offline - tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId) - return - } - weight := util.GetServerWeight(resp) - extra, _ := protojson.Marshal(resp) - tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=?,latency=?,extra=? where AppId=? and ServerId=?", resp.PlayerNum, resp.Sys, resp.CPU, weight, latency, string(extra), v.AppId, v.ServerId) - }(v) - continue - } go func(v *Type.ServerInfo) { - tmpDb := util.MPool.GetGameDB() - defer tmpDb.Close() - // TCP ping test for server connectivity - address := fmt.Sprintf("%s:%d", v.Host, v.Port) // adjust port as needed - timeout := 3 * time.Second - start := time.Now() - conn, err := net.DialTimeout("tcp", address, timeout) - latency := time.Since(start).Milliseconds() - if err != nil { - // Connection failed, mark server as offline - tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId) - return + if err := monitorServerByFallback(v); err != nil { + log.Printf("monitor server failed, AppId=%d, ServerId=%d, err=%v", v.AppId, v.ServerId, err) + markServerOffline(v.AppId, v.ServerId) } - conn.Close() - res, err := model.GetServerInfo(v.AppId, v.ServerId) - if err != nil { - //tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId) - return - } - serverInfo := res.(map[string]interface{}) - free_mem := util.Int(serverInfo["FreeMem"]) - usage_mem := util.Int(serverInfo["Sys"]) - cpu := util.Int(serverInfo["CPU"]) - // compute weight in 0-100 based on free_mem (MB) and cpu (%) - // heuristic: more free memory and lower CPU -> higher weight - memCap := 8192 // 8GB as reference cap for normalization - if free_mem < 0 { - free_mem = 0 - } - memScore := 0 - if free_mem >= memCap { - memScore = 100 - } else { - memScore = free_mem * 100 / memCap - } - - if cpu < 0 { - cpu = 0 - } - if cpu > 100 { - cpu = 100 - } - cpuScore := 100 - cpu // lower CPU -> higher score - - // weighted: 60% memory, 40% CPU - weight := (memScore*6 + cpuScore*4) / 10 - if weight < 0 { - weight = 0 - } - if weight > 100 { - weight = 100 - } - - // optionally store/update weight - serverInfo["Weight"] = weight - // Process serverInfo as needed - tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=?,latency=? where AppId=? and ServerId=?", util.Int(serverInfo["PlayerNum"]), usage_mem, cpu, weight, latency, v.AppId, v.ServerId) }(v) } } + +func monitorServerByFallback(v *Type.ServerInfo) error { + // 默认优先使用第一种方式;失败后自动切换第二种,再反向回退第一种重试一次。 + firstErr := monitorServerByMethod1(v) + if firstErr == nil { + return nil + } + + secondErr := monitorServerByMethod2(v) + if secondErr == nil { + return nil + } + + if err := monitorServerByMethod1(v); err == nil { + return nil + } + + return fmt.Errorf("method1 and method2 both failed, method1Err=%v, method2Err=%v", firstErr, secondErr) +} + +func monitorServerByMethod1(v *Type.ServerInfo) error { + resp, err := client.GetServerInfo(v.AppId, v.ServerId, &msg.ReqServerInfo{}) + if err != nil { + return err + } + + latency, err := util.GetAddressLatency(v.Host, v.Port) + if err != nil { + return err + } + + tmpDb := util.MPool.GetGameDB() + defer tmpDb.Close() + weight := util.GetServerWeight(resp) + extra, _ := protojson.Marshal(resp) + _, err = tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=?,latency=?,extra=? where AppId=? and ServerId=?", resp.PlayerNum, resp.Sys, resp.CPU, weight, latency, string(extra), v.AppId, v.ServerId) + return err +} + +func monitorServerByMethod2(v *Type.ServerInfo) error { + address := fmt.Sprintf("%s:%d", v.Host, v.Port) + timeout := 3 * time.Second + start := time.Now() + conn, err := net.DialTimeout("tcp", address, timeout) + latency := time.Since(start).Milliseconds() + if err != nil { + return err + } + conn.Close() + + res, err := model.GetServerInfo(v.AppId, v.ServerId) + if err != nil { + return err + } + + serverInfo, ok := res.(map[string]interface{}) + if !ok { + return errors.New("invalid server info response type") + } + + freeMem := util.Int(serverInfo["FreeMem"]) + usageMem := util.Int(serverInfo["Sys"]) + cpu := util.Int(serverInfo["CPU"]) + weight := calcServerWeight(freeMem, cpu) + + tmpDb := util.MPool.GetGameDB() + defer tmpDb.Close() + _, err = tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=?,latency=? where AppId=? and ServerId=?", util.Int(serverInfo["PlayerNum"]), usageMem, cpu, weight, latency, v.AppId, v.ServerId) + return err +} + +func calcServerWeight(freeMem int, cpu int) int { + memCap := 8192 // 8GB as reference cap for normalization + if freeMem < 0 { + freeMem = 0 + } + memScore := 0 + if freeMem >= memCap { + memScore = 100 + } else { + memScore = freeMem * 100 / memCap + } + + if cpu < 0 { + cpu = 0 + } + if cpu > 100 { + cpu = 100 + } + cpuScore := 100 - cpu + + weight := (memScore*6 + cpuScore*4) / 10 + if weight < 0 { + return 0 + } + if weight > 100 { + return 100 + } + return weight +} + +func markServerOffline(appID int, serverID int) { + tmpDb := util.MPool.GetGameDB() + defer tmpDb.Close() + _, _ = tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", appID, serverID) +} diff --git a/unit_test.go b/unit_test.go index e4932f6..57c3dce 100644 --- a/unit_test.go +++ b/unit_test.go @@ -140,7 +140,7 @@ func TestEncrypt(t *testing.T) { } func TestDecrypt(t *testing.T) { - str := "linyiling123" + str := "guositeng123" enc, _ := util.Encrypt(str) dec, _ := util.Decrypt("mz-AJj2wjQ5F6MY5hbxiqsfqcwjRj8P85w==") fmt.Printf("enc:%s\ndec:%s\n", enc, dec) diff --git a/util/es.go b/util/es.go index 075af0e..699ff5d 100644 --- a/util/es.go +++ b/util/es.go @@ -45,14 +45,14 @@ func GetEsClient() (*elasticsearch.Client, error) { // DSlSearch 执行 DSL 查询 // query 参数为查询 DSL 的 map 结构 // sort 参数为排序条件,传 nil 表示不排序 -func DSlSearch(ctx context.Context, index string, query map[string]interface{}, from, size int, sort []map[string]interface{}) (map[string]interface{}, error) { +func DSlSearch(ctx context.Context, index string, query map[string]any, from, size int, sort []map[string]any) (map[string]any, error) { client, err := GetEsClient() if err != nil { return nil, err } // 构建完整查询 - fullQuery := map[string]interface{}{ + fullQuery := map[string]any{ "query": query, "from": from, "size": size, @@ -67,7 +67,6 @@ func DSlSearch(ctx context.Context, index string, query map[string]interface{}, if err := json.NewEncoder(&buf).Encode(fullQuery); err != nil { return nil, fmt.Errorf("编码查询失败: %w", err) } - fmt.Printf("%s", buf.String()) res, err := client.Search( client.Search.WithContext(ctx), client.Search.WithIndex(index), @@ -84,7 +83,7 @@ func DSlSearch(ctx context.Context, index string, query map[string]interface{}, return nil, fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes)) } - var result map[string]interface{} + var result map[string]any if err := json.NewDecoder(res.Body).Decode(&result); err != nil { return nil, fmt.Errorf("解析响应失败: %w", err) } @@ -93,9 +92,9 @@ func DSlSearch(ctx context.Context, index string, query map[string]interface{}, } // SimpleSearch 简单搜索(match 查询) -func SimpleSearch(ctx context.Context, index, field, value string, from, size int) (map[string]interface{}, error) { - query := map[string]interface{}{ - "match": map[string]interface{}{ +func SimpleSearch(ctx context.Context, index, field, value string, from, size int) (map[string]any, error) { + query := map[string]any{ + "match": map[string]any{ field: value, }, } @@ -103,15 +102,405 @@ func SimpleSearch(ctx context.Context, index, field, value string, from, size in } // TermSearch 精确匹配查询 -func TermSearch(ctx context.Context, index, field, value string, from, size int) (map[string]interface{}, error) { - query := map[string]interface{}{ - "term": map[string]interface{}{ +func TermSearch(ctx context.Context, index, field, value string, from, size int) (map[string]any, error) { + query := map[string]any{ + "term": map[string]any{ field: value, }, } return DSlSearch(ctx, index, query, from, size, nil) } +type StatisticsOverview struct { + Register int64 + TotalRegister int64 + Recharge float64 + TotalRecharge float64 + RechargeUser int64 + TotalRechargeUser int64 +} + +type StatisticsHeatTrend struct { + Key []string + DailyActive []int64 + Register []int64 +} + +func CountStatisticsOverview(appId int, appOpenTime int64, tz string) (*StatisticsOverview, error) { + client, err := GetEsClient() + if err != nil { + return nil, err + } + + todayStart, err := GetZeroTimestamp(tz, 0) + if err != nil { + return nil, err + } + + now := time.Now().Unix() + if appOpenTime <= 0 { + appOpenTime = todayStart + } + + region := GetAppRegion(appId) + query := map[string]any{ + "size": 0, + "query": map[string]any{ + "bool": map[string]any{ + "must": []map[string]any{ + { + "term": map[string]any{ + "fields.environment": region, + }, + }, + { + "range": map[string]any{ + "game.#timestamp": map[string]any{ + "gte": appOpenTime, + "lte": now, + }, + }, + }, + }, + }, + }, + "aggs": map[string]any{ + "scopes": map[string]any{ + "filters": map[string]any{ + "filters": map[string]any{ + "today": map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ + "gte": todayStart, + "lte": now, + }, + }, + }, + "total": map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ + "gte": appOpenTime, + "lte": now, + }, + }, + }, + }, + }, + "aggs": map[string]any{ + "register": map[string]any{ + "filter": map[string]any{ + "term": map[string]any{ + "game.#event_name": "register", + }, + }, + }, + "login": map[string]any{ + "filter": map[string]any{ + "bool": map[string]any{ + "minimum_should_match": 1, + "should": []map[string]any{ + { + "term": map[string]any{ + "game.#event_name": "Login_log", + }, + }, + { + "term": map[string]any{ + "game.#event_name": "login", + }, + }, + { + "term": map[string]any{ + "game.#event_name": "Login", + }, + }, + }, + }, + }, + "aggs": map[string]any{ + "uid_count": map[string]any{ + "cardinality": map[string]any{ + "field": "game.#distinct_id.keyword", + }, + }, + }, + }, + "pay": map[string]any{ + "filter": map[string]any{ + "term": map[string]any{ + "game.#event_name": "pay", + }, + }, + "aggs": map[string]any{ + "uid_count": map[string]any{ + "cardinality": map[string]any{ + "field": "game.#distinct_id.keyword", + }, + }, + "amount_sum": map[string]any{ + "sum": map[string]any{ + "script": map[string]any{ + "source": "double v = 0; if (doc.containsKey('game.properties.price') && !doc['game.properties.price'].empty) { v = doc['game.properties.price'].value; } else if (doc.containsKey('game.properties.Price') && !doc['game.properties.Price'].empty) { v = doc['game.properties.Price'].value; } else if (doc.containsKey('game.properties.amount') && !doc['game.properties.amount'].empty) { v = doc['game.properties.amount'].value; } else if (doc.containsKey('game.properties.pay_amount') && !doc['game.properties.pay_amount'].empty) { v = doc['game.properties.pay_amount'].value; } return v;", + }, + }, + }, + }, + }, + }, + }, + }, + } + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(query); err != nil { + return nil, fmt.Errorf("编码查询失败: %w", err) + } + + res, err := client.Search( + client.Search.WithContext(context.Background()), + client.Search.WithIndex("game-user-log*"), + client.Search.WithBody(&buf), + ) + if err != nil { + return nil, fmt.Errorf("执行搜索失败: %w", err) + } + defer res.Body.Close() + + if res.IsError() { + bodyBytes, _ := io.ReadAll(res.Body) + return nil, fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes)) + } + + var result map[string]any + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("解析响应失败: %w", err) + } + + overview := &StatisticsOverview{} + aggs, ok := result["aggregations"].(map[string]any) + if !ok { + return overview, nil + } + + scopes, ok := aggs["scopes"].(map[string]any) + if !ok { + return overview, nil + } + + buckets, ok := scopes["buckets"].(map[string]any) + if !ok { + return overview, nil + } + + parseScope := func(scopeName string) (int64, float64, int64, int64) { + scope, ok := buckets[scopeName].(map[string]any) + if !ok { + return 0, 0, 0, 0 + } + + registerCount := int64(0) + if registerAgg, ok := scope["register"].(map[string]any); ok { + if docCount, ok := registerAgg["doc_count"].(float64); ok { + registerCount = int64(docCount) + } + } + + loginUser := int64(0) + if loginAgg, ok := scope["login"].(map[string]any); ok { + if uidCount, ok := loginAgg["uid_count"].(map[string]any); ok { + if value, ok := uidCount["value"].(float64); ok { + loginUser = int64(value) + } + } + } + + payAmount := float64(0) + payUser := int64(0) + if payAgg, ok := scope["pay"].(map[string]any); ok { + if amountSum, ok := payAgg["amount_sum"].(map[string]any); ok { + if value, ok := amountSum["value"].(float64); ok { + payAmount = value + } + } + if uidCount, ok := payAgg["uid_count"].(map[string]any); ok { + if value, ok := uidCount["value"].(float64); ok { + payUser = int64(value) + } + } + } + + return registerCount, payAmount, payUser, loginUser + } + + overview.Register, overview.Recharge, overview.RechargeUser, _ = parseScope("today") + overview.TotalRegister, overview.TotalRecharge, overview.TotalRechargeUser, _ = parseScope("total") + + return overview, nil +} + +func CountStatisticsHeat7Days(appId int, tz string) (*StatisticsHeatTrend, error) { + client, err := GetEsClient() + if err != nil { + return nil, err + } + + start, err := GetZeroTimestamp(tz, -6) + if err != nil { + return nil, err + } + now := time.Now().Unix() + region := GetAppRegion(appId) + + dayKeys := make([]string, 0, 7) + dayLabels := make([]string, 0, 7) + dayFilters := make(map[string]any, 7) + for i := -6; i <= 0; i++ { + dayKey, err := GetDateStr(tz, i) + if err != nil { + return nil, err + } + dayStart, err := GetZeroTimestamp(tz, i) + if err != nil { + return nil, err + } + dayEnd := now + if i < 0 { + nextDayStart, err := GetZeroTimestamp(tz, i+1) + if err != nil { + return nil, err + } + dayEnd = nextDayStart - 1 + } + + dayKeys = append(dayKeys, dayKey) + dayLabels = append(dayLabels, dayKey[5:]) + dayFilters[dayKey] = map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ + "gte": dayStart, + "lte": dayEnd, + }, + }, + } + } + + query := map[string]any{ + "size": 0, + "query": map[string]any{ + "bool": map[string]any{ + "must": []map[string]any{ + { + "term": map[string]any{ + "fields.environment": region, + }, + }, + { + "range": map[string]any{ + "game.#timestamp": map[string]any{ + "gte": start, + "lte": now, + }, + }, + }, + }, + }, + }, + "aggs": map[string]any{ + "days": map[string]any{ + "filters": map[string]any{ + "filters": dayFilters, + }, + "aggs": map[string]any{ + "register": map[string]any{ + "filter": map[string]any{ + "term": map[string]any{ + "game.#event_name": "register", + }, + }, + }, + "login": map[string]any{ + "filter": map[string]any{ + "term": map[string]any{ + "game.#event_name.keyword": "Login_log", + }, + }, + "aggs": map[string]any{ + "uid_count": map[string]any{ + "cardinality": map[string]any{ + "field": "game.#distinct_id.keyword", + }, + }, + }, + }, + }, + }, + }, + } + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(query); err != nil { + return nil, fmt.Errorf("编码查询失败: %w", err) + } + + res, err := client.Search( + client.Search.WithContext(context.Background()), + client.Search.WithIndex("game-user-log*"), + client.Search.WithBody(&buf), + ) + if err != nil { + return nil, fmt.Errorf("执行搜索失败: %w", err) + } + defer res.Body.Close() + + if res.IsError() { + bodyBytes, _ := io.ReadAll(res.Body) + return nil, fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes)) + } + + var result map[string]any + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("解析响应失败: %w", err) + } + + registerByDay := make(map[string]int64) + activeByDay := make(map[string]int64) + + aggs, _ := result["aggregations"].(map[string]any) + daysAgg, _ := aggs["days"].(map[string]any) + buckets, _ := daysAgg["buckets"].(map[string]any) + for day, b := range buckets { + bucket, ok := b.(map[string]any) + if !ok { + continue + } + if registerAgg, ok := bucket["register"].(map[string]any); ok { + if docCount, ok := registerAgg["doc_count"].(float64); ok { + registerByDay[day] = int64(docCount) + } + } + if loginAgg, ok := bucket["login"].(map[string]any); ok { + if uidCount, ok := loginAgg["uid_count"].(map[string]any); ok { + if value, ok := uidCount["value"].(float64); ok { + activeByDay[day] = int64(value) + } + } + } + } + + trend := &StatisticsHeatTrend{ + Key: make([]string, 0, 7), + DailyActive: make([]int64, 0, 7), + Register: make([]int64, 0, 7), + } + for idx, day := range dayKeys { + trend.Key = append(trend.Key, dayLabels[idx]) + trend.DailyActive = append(trend.DailyActive, activeByDay[day]) + trend.Register = append(trend.Register, registerByDay[day]) + } + + return trend, nil +} + func SearchAssetByUid(app, _uid int, from, size int, start, end int64, itemid int, param string) ([]*Type.AssetData, int64, error) { defer func() { if r := recover(); r != nil { @@ -121,25 +510,25 @@ func SearchAssetByUid(app, _uid int, from, size int, start, end int64, itemid in uid := Int(_uid) ctx := context.Background() region := GetAppRegion(app) - mustCondition := []map[string]interface{}{ + mustCondition := []map[string]any{ { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#distinct_id.keyword": uid, }, }, { - "term": map[string]interface{}{ + "term": map[string]any{ "fields.environment": region, }, }, { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#event_name": "asset_change", }, }, { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": start, "lte": end, }, @@ -147,29 +536,29 @@ func SearchAssetByUid(app, _uid int, from, size int, start, end int64, itemid in }, } if itemid != 0 { - mustCondition = append(mustCondition, map[string]interface{}{ - "term": map[string]interface{}{ + mustCondition = append(mustCondition, map[string]any{ + "term": map[string]any{ "game.properties.item_id": itemid, }, }) } if param != "" { - mustCondition = append(mustCondition, map[string]interface{}{ - "match": map[string]interface{}{ + mustCondition = append(mustCondition, map[string]any{ + "match": map[string]any{ "game.properties.change_type": param, }, }) } - query := map[string]interface{}{ - "bool": map[string]interface{}{ + query := map[string]any{ + "bool": map[string]any{ "must": mustCondition, }, } // 添加降序排序 - sort := []map[string]interface{}{ + sort := []map[string]any{ { - "game.#timestamp": map[string]interface{}{ + "game.#timestamp": map[string]any{ "order": "desc", }, }, @@ -182,18 +571,18 @@ func SearchAssetByUid(app, _uid int, from, size int, start, end int64, itemid in // 获取总数 var total int64 - hits := result["hits"].(map[string]interface{}) - if totalObj, ok := hits["total"].(map[string]interface{}); ok { + hits := result["hits"].(map[string]any) + if totalObj, ok := hits["total"].(map[string]any); ok { if value, ok := totalObj["value"].(float64); ok { total = int64(value) } } var assets []*Type.AssetData - for _, hit := range hits["hits"].([]interface{}) { - source := hit.(map[string]interface{})["_source"].(map[string]interface{}) - game := source["game"].(map[string]interface{}) - properties := game["properties"].(map[string]interface{}) + for _, hit := range hits["hits"].([]any) { + source := hit.(map[string]any)["_source"].(map[string]any) + game := source["game"].(map[string]any) + properties := game["properties"].(map[string]any) hitData := Type.AssetData{ ChangeNum: int(properties["change_num"].(float64)), ChangeAfter: int(properties["change_after"].(float64)), @@ -216,20 +605,20 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam uid := Int(_uid) ctx := context.Background() region := GetAppRegion(app) - mustConditions := []map[string]interface{}{ + mustConditions := []map[string]any{ { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#distinct_id.keyword": uid, }, }, { - "term": map[string]interface{}{ + "term": map[string]any{ "fields.environment": region, }, }, { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": start, "lte": end, }, @@ -238,24 +627,24 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam } if event_name != "" { - mustConditions = append(mustConditions, map[string]interface{}{ - "term": map[string]interface{}{ + mustConditions = append(mustConditions, map[string]any{ + "term": map[string]any{ "game.#event_name": event_name, }, }) } - query := map[string]interface{}{ - "bool": map[string]interface{}{ + query := map[string]any{ + "bool": map[string]any{ "must": mustConditions, - "must_not": []map[string]interface{}{ + "must_not": []map[string]any{ { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#event_name": "asset_change", }, }, { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#event_name": "func_exec_time", }, }, @@ -264,9 +653,9 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam } // 添加降序排序 - sort := []map[string]interface{}{ + sort := []map[string]any{ { - "game.#timestamp": map[string]interface{}{ + "game.#timestamp": map[string]any{ "order": "desc", }, }, @@ -278,18 +667,18 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam // 获取总数 var total int64 - hits := result["hits"].(map[string]interface{}) - if totalObj, ok := hits["total"].(map[string]interface{}); ok { + hits := result["hits"].(map[string]any) + if totalObj, ok := hits["total"].(map[string]any); ok { if value, ok := totalObj["value"].(float64); ok { total = int64(value) } } var assets []*Type.EventData - for _, hit := range hits["hits"].([]interface{}) { - source := hit.(map[string]interface{})["_source"].(map[string]interface{}) - game := source["game"].(map[string]interface{}) - //properites := game["properties"].(map[string]interface{}) + for _, hit := range hits["hits"].([]any) { + source := hit.(map[string]any)["_source"].(map[string]any) + game := source["game"].(map[string]any) + //properites := game["properties"].(map[string]any) properties_summary := game["properties_summary"].(string) hitData := Type.EventData{ Event: game["#event_name"].(string), @@ -333,13 +722,13 @@ func SearchLoginCountByUidMonth(app, _uid int, month string) ([]*Type.LoginDaily monthEnd := monthStart.AddDate(0, 1, 0).Add(-time.Second) region := GetAppRegion(app) - dailyFilters := make(map[string]interface{}) + dailyFilters := make(map[string]any) for day := monthStart; !day.After(monthEnd); day = day.AddDate(0, 0, 1) { dayStart := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, loc) dayEnd := dayStart.AddDate(0, 0, 1).Add(-time.Second) - dailyFilters[dayStart.Format("2006-01-02")] = map[string]interface{}{ - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + dailyFilters[dayStart.Format("2006-01-02")] = map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": dayStart.Unix(), "lte": dayEnd.Unix(), }, @@ -347,27 +736,27 @@ func SearchLoginCountByUidMonth(app, _uid int, month string) ([]*Type.LoginDaily } } - query := map[string]interface{}{ - "bool": map[string]interface{}{ - "must": []map[string]interface{}{ + query := map[string]any{ + "bool": map[string]any{ + "must": []map[string]any{ { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#distinct_id.keyword": uid, }, }, { - "term": map[string]interface{}{ + "term": map[string]any{ "fields.environment": region, }, }, { - "term": map[string]interface{}{ + "term": map[string]any{ "game.#event_name.keyword": "Login_log", }, }, { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": monthStart.Unix(), "lte": monthEnd.Unix(), }, @@ -382,12 +771,12 @@ func SearchLoginCountByUidMonth(app, _uid int, month string) ([]*Type.LoginDaily return nil, 0, err } - fullQuery := map[string]interface{}{ + fullQuery := map[string]any{ "query": query, "size": 0, - "aggs": map[string]interface{}{ - "daily_login": map[string]interface{}{ - "filters": map[string]interface{}{ + "aggs": map[string]any{ + "daily_login": map[string]any{ + "filters": map[string]any{ "filters": dailyFilters, }, }, @@ -415,14 +804,14 @@ func SearchLoginCountByUidMonth(app, _uid int, month string) ([]*Type.LoginDaily return nil, 0, fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes)) } - var result map[string]interface{} + var result map[string]any if err := json.NewDecoder(res.Body).Decode(&result); err != nil { return nil, 0, fmt.Errorf("解析响应失败: %w", err) } var total int64 - if hits, ok := result["hits"].(map[string]interface{}); ok { - if totalObj, ok := hits["total"].(map[string]interface{}); ok { + if hits, ok := result["hits"].(map[string]any); ok { + if totalObj, ok := hits["total"].(map[string]any); ok { if value, ok := totalObj["value"].(float64); ok { total = int64(value) } @@ -430,11 +819,11 @@ func SearchLoginCountByUidMonth(app, _uid int, month string) ([]*Type.LoginDaily } counts := make(map[string]int64, len(dailyFilters)) - if aggregations, ok := result["aggregations"].(map[string]interface{}); ok { - if dailyLogin, ok := aggregations["daily_login"].(map[string]interface{}); ok { - if buckets, ok := dailyLogin["buckets"].(map[string]interface{}); ok { + if aggregations, ok := result["aggregations"].(map[string]any); ok { + if dailyLogin, ok := aggregations["daily_login"].(map[string]any); ok { + if buckets, ok := dailyLogin["buckets"].(map[string]any); ok { for day, bucket := range buckets { - bucketMap, ok := bucket.(map[string]interface{}) + bucketMap, ok := bucket.(map[string]any) if !ok { continue } @@ -488,28 +877,28 @@ func CountDistinctUidLastHour() (int64, int64, error) { oneDayAgo := (now - 24*3600) // 构建查询:使用过滤器聚合分别统计两个时间段 - query := map[string]interface{}{ - "query": map[string]interface{}{ - "bool": map[string]interface{}{ - "must": []map[string]interface{}{ + query := map[string]any{ + "query": map[string]any{ + "bool": map[string]any{ + "must": []map[string]any{ { - "term": map[string]interface{}{ + "term": map[string]any{ "fields.region.keyword": "us-newyork", }, }, }, - "should": []map[string]interface{}{ + "should": []map[string]any{ { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneHourAgo, "lte": nowMs, }, }, }, { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneDayOneHourAgo, "lte": oneDayAgo, }, @@ -520,36 +909,36 @@ func CountDistinctUidLastHour() (int64, int64, error) { }, }, "from": 0, - "aggs": map[string]interface{}{ - "current_hour": map[string]interface{}{ - "filter": map[string]interface{}{ - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "aggs": map[string]any{ + "current_hour": map[string]any{ + "filter": map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneHourAgo, "lte": nowMs, }, }, }, - "aggs": map[string]interface{}{ - "unique_users": map[string]interface{}{ - "cardinality": map[string]interface{}{ + "aggs": map[string]any{ + "unique_users": map[string]any{ + "cardinality": map[string]any{ "field": "game.#distinct_id.keyword", }, }, }, }, - "yesterday_hour": map[string]interface{}{ - "filter": map[string]interface{}{ - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "yesterday_hour": map[string]any{ + "filter": map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneDayOneHourAgo, "lte": oneDayAgo, }, }, }, - "aggs": map[string]interface{}{ - "unique_users": map[string]interface{}{ - "cardinality": map[string]interface{}{ + "aggs": map[string]any{ + "unique_users": map[string]any{ + "cardinality": map[string]any{ "field": "game.#distinct_id.keyword", }, }, @@ -562,7 +951,6 @@ func CountDistinctUidLastHour() (int64, int64, error) { if err := json.NewEncoder(&buf).Encode(query); err != nil { return 0, 0, fmt.Errorf("编码查询失败: %w", err) } - fmt.Printf("%s", buf.String()) res, err := client.Search( client.Search.WithContext(ctx), client.Search.WithIndex("game-user-log*"), @@ -579,7 +967,7 @@ func CountDistinctUidLastHour() (int64, int64, error) { return 0, 0, fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes)) } - var result map[string]interface{} + var result map[string]any if err := json.NewDecoder(res.Body).Decode(&result); err != nil { return 0, 0, fmt.Errorf("解析响应失败: %w", err) } @@ -587,10 +975,10 @@ func CountDistinctUidLastHour() (int64, int64, error) { // 从聚合结果中提取去重计数 var currentCount, yesterdayCount int64 - if aggregations, ok := result["aggregations"].(map[string]interface{}); ok { + if aggregations, ok := result["aggregations"].(map[string]any); ok { // 提取当前小时的数据 - if currentHour, ok := aggregations["current_hour"].(map[string]interface{}); ok { - if uniqueUsers, ok := currentHour["unique_users"].(map[string]interface{}); ok { + if currentHour, ok := aggregations["current_hour"].(map[string]any); ok { + if uniqueUsers, ok := currentHour["unique_users"].(map[string]any); ok { if value, ok := uniqueUsers["value"].(float64); ok { currentCount = int64(value) } @@ -598,8 +986,8 @@ func CountDistinctUidLastHour() (int64, int64, error) { } // 提取昨天同一小时的数据 - if yesterdayHour, ok := aggregations["yesterday_hour"].(map[string]interface{}); ok { - if uniqueUsers, ok := yesterdayHour["unique_users"].(map[string]interface{}); ok { + if yesterdayHour, ok := aggregations["yesterday_hour"].(map[string]any); ok { + if uniqueUsers, ok := yesterdayHour["unique_users"].(map[string]any); ok { if value, ok := uniqueUsers["value"].(float64); ok { yesterdayCount = int64(value) } @@ -610,7 +998,7 @@ func CountDistinctUidLastHour() (int64, int64, error) { return currentCount, yesterdayCount, nil } -func CountDistinctUidLastHourTest() interface{} { +func CountDistinctUidLastHourTest() any { defer func() { if r := recover(); r != nil { log.Println("Recovered in CountDistinctUidLastHour", r) @@ -633,28 +1021,28 @@ func CountDistinctUidLastHourTest() interface{} { oneDayAgo := (now - 24*3600) // 构建查询:使用过滤器聚合分别统计两个时间段 - query := map[string]interface{}{ - "query": map[string]interface{}{ - "bool": map[string]interface{}{ - "must": []map[string]interface{}{ + query := map[string]any{ + "query": map[string]any{ + "bool": map[string]any{ + "must": []map[string]any{ { - "term": map[string]interface{}{ + "term": map[string]any{ "fields.region.keyword": "us-newyork", }, }, }, - "should": []map[string]interface{}{ + "should": []map[string]any{ { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneHourAgo, "lte": nowMs, }, }, }, { - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneDayOneHourAgo, "lte": oneDayAgo, }, @@ -666,36 +1054,36 @@ func CountDistinctUidLastHourTest() interface{} { }, "size": 0, "from": 0, - "aggs": map[string]interface{}{ - "current_hour": map[string]interface{}{ - "filter": map[string]interface{}{ - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "aggs": map[string]any{ + "current_hour": map[string]any{ + "filter": map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneHourAgo, "lte": nowMs, }, }, }, - "aggs": map[string]interface{}{ - "unique_users": map[string]interface{}{ - "cardinality": map[string]interface{}{ + "aggs": map[string]any{ + "unique_users": map[string]any{ + "cardinality": map[string]any{ "field": "game.#distinct_id.keyword", }, }, }, }, - "yesterday_hour": map[string]interface{}{ - "filter": map[string]interface{}{ - "range": map[string]interface{}{ - "game.#timestamp": map[string]interface{}{ + "yesterday_hour": map[string]any{ + "filter": map[string]any{ + "range": map[string]any{ + "game.#timestamp": map[string]any{ "gte": oneDayOneHourAgo, "lte": oneDayAgo, }, }, }, - "aggs": map[string]interface{}{ - "unique_users": map[string]interface{}{ - "cardinality": map[string]interface{}{ + "aggs": map[string]any{ + "unique_users": map[string]any{ + "cardinality": map[string]any{ "field": "game.#distinct_id.keyword", }, }, @@ -725,7 +1113,7 @@ func CountDistinctUidLastHourTest() interface{} { return fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes)) } - var result map[string]interface{} + var result map[string]any if err := json.NewDecoder(res.Body).Decode(&result); err != nil { return fmt.Errorf("解析响应失败: %w", err) }