版本更新
This commit is contained in:
parent
3dc71f22be
commit
f0a0c4ac57
21
.env
Normal file
21
.env
Normal file
@ -0,0 +1,21 @@
|
||||
OSS_ACCESS_KEY_ID=LTAI5t7e94rne7K7JYiJFm1N
|
||||
OSS_ACCESS_KEY_SECRET=wvZyRmuQ81qwnVv2f3EOAZGgm0Ot2c
|
||||
OSS_SESSION_TOKEN=
|
||||
OSS_REGION=cn-hangzhou
|
||||
OSS_BUCKET=merge-pet-elastic
|
||||
OSS_OBJECT_KEY=example-object.txt
|
||||
|
||||
# Nacos connection
|
||||
NACOS_SERVER_ADDRS=127.0.0.1:8848
|
||||
NACOS_USERNAME=nacos
|
||||
NACOS_PASSWORD=nacos
|
||||
NACOS_NAMESPACE_ID=public
|
||||
NACOS_GROUP=server
|
||||
NACOS_TIMEOUT_MS=5000
|
||||
NACOS_LOG_DIR=./log/nacos
|
||||
NACOS_CACHE_DIR=./runtime/nacos
|
||||
NACOS_LOG_LEVEL=info
|
||||
|
||||
# OSS config stored in Nacos JSON
|
||||
OSS_NACOS_DATA_ID=oss.json
|
||||
OSS_NACOS_GROUP=server
|
||||
42
.github/agents/game-admin-backend.agent.md
vendored
Normal file
42
.github/agents/game-admin-backend.agent.md
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
name: 游戏中台 Admin 后端专家
|
||||
description: "Use when: 开发或维护游戏中台 web admin 服务端;处理 Golang Gin 接口、protobuf/thrift 协议、MySQL 数据访问、Python 配置工具、监控指标、负载均衡、GM 后台、管理后台接口、游戏服管理逻辑、elastic 日志收集整理。"
|
||||
tools: [read, search, edit, execute, todo]
|
||||
argument-hint: "描述你的后台服务端任务,例如修改接口、优化权重算法、调整协议字段、排查 MySQL 查询或配置生成流程"
|
||||
user-invocable: true
|
||||
---
|
||||
你是资深的游戏中台 web admin 服务端工程师,技术栈包括 Golang、Gin、protobuf、thrift、Python、MySQL。你的任务是帮助用户在游戏管理后台和相关服务端代码中做出高质量、可验证、可上线的修改。
|
||||
|
||||
## 适用范围
|
||||
- Go + Gin 的后台接口、路由、中间件、控制器、模型和工具函数
|
||||
- protobuf / thrift 协议字段、序列化结构、兼容性调整
|
||||
- MySQL 查询、数据模型、后台统计和管理功能
|
||||
- Python 配置脚本、配置生成链路、后台依赖的静态配置
|
||||
- 监控、权重分配、负载均衡、游戏服状态聚合
|
||||
- GM 工具、运营配置、资源发放、账号或服务器管理逻辑
|
||||
|
||||
## 约束
|
||||
- 只聚焦游戏中台 admin 服务端,不主动扩展到无关前端或基础设施改造
|
||||
- 优先修根因,不做只掩盖问题的表层补丁
|
||||
- 优先最小改动,保持现有协议、表结构和调用方兼容
|
||||
- 修改协议、配置或权重逻辑时,必须检查上下游消费方
|
||||
- 涉及数据库、配置、协议生成时,优先做窄范围验证,避免全量破坏性操作
|
||||
- 不在未确认需求的情况下重写模块或大范围重构
|
||||
|
||||
## 工具偏好
|
||||
- 先用搜索和局部阅读定位真实控制路径,再动手修改
|
||||
- 优先做可执行验证:局部编译、针对性测试、协议生成、配置生成
|
||||
- 需要命令执行时,使用最小范围的构建、测试或生成命令
|
||||
- 除非任务明确要求,不依赖外网资料来替代仓库事实
|
||||
|
||||
## 工作方式
|
||||
1. 先定位用户请求对应的控制路径、协议定义、表结构或配置链路。
|
||||
2. 基于真实代码提出一个可证伪的本地假设,并优先做最小修改。
|
||||
3. 修改后立刻做窄范围验证,例如相关包编译、单测、生成任务或查询校验。
|
||||
4. 返回结果时明确说明改了什么、为什么这样改、验证是否通过、剩余风险是什么。
|
||||
|
||||
## 输出要求
|
||||
- 先给结论,再补关键依据
|
||||
- 涉及文件时引用具体文件位置
|
||||
- 如果存在歧义,明确列出需要用户确认的点
|
||||
- 如果无法安全落地,给出最小可行替代方案
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -12,4 +12,5 @@ log/*.log
|
||||
*.log
|
||||
runtime/*.db
|
||||
config/*
|
||||
unit/config/*
|
||||
unit/config/*
|
||||
runtime/*
|
||||
|
||||
@ -206,3 +206,8 @@ type EventData struct {
|
||||
Param string `json:"Param"`
|
||||
Timestamp int `json:"Timestamp"`
|
||||
}
|
||||
|
||||
type LoginDailyCount struct {
|
||||
Date string `json:"date"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
@ -98,3 +98,28 @@ func GetUserInfo(AppId, ServerId int, req *msg.UserDetailParam) (*msg.ResUserDet
|
||||
}
|
||||
return resp.GetInfo(), nil
|
||||
}
|
||||
|
||||
func GetServerInfo(AppId, ServerId int, req *msg.ReqServerInfo) (*msg.ResServerInfo, error) {
|
||||
ServerConfig, err := util.GetServerConfig(AppId, ServerId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get server config: %v", err)
|
||||
}
|
||||
if ServerConfig == nil {
|
||||
return nil, fmt.Errorf("server config not found for AppId %d and ServerId %d", AppId, ServerId)
|
||||
}
|
||||
conn, err := grpc.NewClient(fmt.Sprintf("%s:%d", ServerConfig.Host, ServerConfig.GrpcPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
// TODO : 目前先连接本地,后续改为连接对应服务器
|
||||
//conn, err := grpc.NewClient("127.0.0.1:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := msg.NewBackendClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
resp, err := client.ServerInfo(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ServerInfo failed: %v", err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gitea.bywaystudios.com/pet_home/nacos"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
@ -65,11 +67,12 @@ type LanguageLimit struct {
|
||||
var config *Config
|
||||
var tranlaterConfig *TranlaterConfig
|
||||
|
||||
func Init() {
|
||||
func Init() error {
|
||||
err := loadConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load config: %v", err)
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitTranlater() error {
|
||||
@ -85,15 +88,23 @@ func InitTranlater() error {
|
||||
}
|
||||
|
||||
func loadConfig() error {
|
||||
data, err := os.ReadFile("conf/server.yml")
|
||||
nacosClient, err := nacos.GetNacosClient()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("get nacos client: %w", err)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(data, &config)
|
||||
err = nacosClient.GetYAML("web-backend-env-conf", "web", &config)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("get nacos config: %w", err)
|
||||
}
|
||||
nacosClient.Listen("web-backend-env-conf", "web", func(event nacos.ChangeEvent) {
|
||||
var newConfig Config
|
||||
if err := yaml.Unmarshal([]byte(event.Content), &newConfig); err != nil {
|
||||
log.Printf("解析 Nacos 配置变更失败: %v", err)
|
||||
return
|
||||
}
|
||||
config = &newConfig
|
||||
log.Printf("Nacos 配置已更新: %v", config)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
system:
|
||||
nmap: false
|
||||
feishu_url: 'https://open.feishu.cn/open-apis/bot/v2/hook/70e24a79-b019-434a-b4d1-4592bbf7c311'
|
||||
notice_url: 'https://open.feishu.cn/open-apis/bot/v2/hook/64bad1f3-3a41-4dca-9037-399067ffb252'
|
||||
operation_url: 'https://open.feishu.cn/open-apis/bot/v2/hook/70e24a79-b019-434a-b4d1-4592bbf7c311'
|
||||
@ -7,25 +6,25 @@ system:
|
||||
operation_chat_id: 'oc_f6e10a55f28f31e2a5677bdcb6aed599'
|
||||
us_operation_chat_id: 'oc_a3d1268f63573563fdaea3dedb3bf78d'
|
||||
client_chat_id: 'oc_f6e10a55f28f31e2a5677bdcb6aed599'
|
||||
ssh: true
|
||||
ssh: false
|
||||
env: 'dev'
|
||||
rpc_switch: true
|
||||
mysqls:
|
||||
- host: '127.0.0.1'
|
||||
- host: '112.124.54.243'
|
||||
name: 'merge_pet_test'
|
||||
port: 3306
|
||||
user: 'root'
|
||||
password: 'GWFj1cHaqjpzvcsHBWTFtLWtm8MUZKROx_wvbV6jPg=='
|
||||
database: 'pet_home_%d'
|
||||
idleTimeout: Infinity
|
||||
- host: '127.0.0.1'
|
||||
- host: '1.15.182.107'
|
||||
name: 'merge_pet_audit'
|
||||
port: 3306
|
||||
user: 'root'
|
||||
password: 'GWFj1cHaqjpzvcsHBWTFtLWtm8MUZKROx_wvbV6jPg=='
|
||||
database: 'merge_pet_audit_%d'
|
||||
idleTimeout: Infinity
|
||||
- host: '127.0.0.1'
|
||||
- host: '112.124.54.243'
|
||||
name: 'merge_pet_sdk'
|
||||
port: 3306
|
||||
user: 'root'
|
||||
@ -53,25 +52,3 @@ mysqls:
|
||||
password: 'GWFj1cHaqjpzvcsHBWTFtLWtm8MUZKROx_wvbV6jPg=='
|
||||
database: 'game'
|
||||
idleTimeout: Infinity
|
||||
|
||||
servers:
|
||||
- name: 'server1'
|
||||
host: '112.124.54.243'
|
||||
port: 22
|
||||
username: 'root'
|
||||
password: 'H3ukUvaLVLvWRXn9zGeAM9fspkGy6VUpMn7bEtWaTg=='
|
||||
- name: 'server2'
|
||||
host: '47.254.83.25'
|
||||
port: 22
|
||||
username: 'root'
|
||||
password: 'ynAMWcS4YpHozPHuudywcIZuBnTiSSaWF2iLoSlRVA=='
|
||||
- name: 'london'
|
||||
host: '8.208.47.208'
|
||||
port: 22
|
||||
username: 'root'
|
||||
password: 'dhzyiIMG0LkzSmY0lVEukdbM1uIt8OY8qljhgUJnBT8='
|
||||
- name: 'log'
|
||||
host: '8.155.14.94'
|
||||
port: 22
|
||||
username: 'root'
|
||||
password: 'gDcfdjgyq60A-8q_cZ_CbSQnTlY0YakpiYVyTmFTEkk='
|
||||
@ -36,6 +36,21 @@ func Event(c *gin.Context) {
|
||||
success(c, res)
|
||||
}
|
||||
|
||||
func LoginCountByMonth(c *gin.Context) {
|
||||
log := model.Log{}
|
||||
err := c.BindJSON(&log)
|
||||
if err != nil {
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
res, err := log.LoginCountByMonth()
|
||||
if err != nil {
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, res)
|
||||
}
|
||||
|
||||
func Order(c *gin.Context) {
|
||||
log := model.Log{}
|
||||
err := c.BindJSON(&log)
|
||||
|
||||
@ -375,3 +375,19 @@ func CopyOnlineStep4(c *gin.Context) {
|
||||
"code": 0,
|
||||
})
|
||||
}
|
||||
|
||||
func ClientImageGitPull(c *gin.Context) {
|
||||
nodeInfo := util.GetNodeByName("devops")
|
||||
SshClient, err := util.NewSshClient(nodeInfo)
|
||||
if err != nil {
|
||||
scritp_fail(c, "连接devops节点失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
defer SshClient.Close()
|
||||
cmd := "ansible-playbook /data/devops/playbook/web-client.yml -i /data/devops/playbook/hosts"
|
||||
output, err := SshClient.RunCommand(cmd)
|
||||
if err != nil {
|
||||
scritp_fail(c, "执行更新翻译图标失败: "+err.Error()+": "+output)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,10 +28,6 @@ func AppList(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, AppList)
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"backend/common"
|
||||
"backend/model"
|
||||
"backend/store"
|
||||
"backend/util"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -77,67 +74,24 @@ func UserDetail(c *gin.Context) {
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
if common.GetEnv() == "dev" {
|
||||
user, err := model.UserDetail2(request.AppId, request.Uid, request.Node)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
for _, v := range user.Order {
|
||||
for _, chessInfo := range v.Chess {
|
||||
chess_url := util.GetChessURL(util.String(chessInfo.GetId()))
|
||||
chessInfo.Icon = chess_url
|
||||
}
|
||||
v.ChessId = v.Chess
|
||||
}
|
||||
for _, v := range user.FriendList {
|
||||
face_url := util.GetFaceURL(util.Int(v.Avatar))
|
||||
v.AvatarUrl = face_url
|
||||
v.OnlineStatus = util.Int(v.LoginTime) > util.Int(v.LogoutTime)
|
||||
}
|
||||
success(c, user)
|
||||
return
|
||||
}
|
||||
user, err := model.UserDetail(request.AppId, request.Uid, request.Node)
|
||||
if user["Order"] != nil {
|
||||
order := user["Order"].(map[string]interface{})
|
||||
for k, v := range order {
|
||||
info := v.(map[string]interface{})
|
||||
chess_id := info["ChessId"].(string)
|
||||
chess_list := strings.Split(chess_id, " ")
|
||||
chess_arr := []Type.ChessData{}
|
||||
for _, cid := range chess_list {
|
||||
if cid == "" {
|
||||
continue
|
||||
}
|
||||
chess_url := util.GetChessURL(cid)
|
||||
chess_arr = append(chess_arr, Type.ChessData{
|
||||
Id: cid,
|
||||
Icon: chess_url,
|
||||
})
|
||||
}
|
||||
info["ChessId"] = chess_arr
|
||||
order[k] = info
|
||||
}
|
||||
}
|
||||
|
||||
if user["FriendList"] != nil {
|
||||
friendList := user["FriendList"].([]interface{})
|
||||
for k, v := range friendList {
|
||||
info := v.(map[string]interface{})
|
||||
face_url := util.GetFaceURL(util.Int(info["Avatar"]))
|
||||
info["AvatarUrl"] = face_url
|
||||
friendList[k] = info
|
||||
info["OnlineStatus"] = util.Int(info["LoginTime"]) > util.Int(info["LogoutTime"])
|
||||
}
|
||||
user["FriendList"] = friendList
|
||||
}
|
||||
user, err := model.UserDetail2(request.AppId, request.Uid, request.Node)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
for _, v := range user.Order {
|
||||
for _, chessInfo := range v.Chess {
|
||||
chess_url := util.GetChessURL(util.String(chessInfo.GetId()))
|
||||
chessInfo.Icon = chess_url
|
||||
}
|
||||
v.ChessId = v.Chess
|
||||
}
|
||||
for _, v := range user.FriendList {
|
||||
face_url := util.GetFaceURL(util.Int(v.Avatar))
|
||||
v.AvatarUrl = face_url
|
||||
v.OnlineStatus = util.Int(v.LoginTime) > util.Int(v.LogoutTime)
|
||||
}
|
||||
success(c, user)
|
||||
}
|
||||
|
||||
|
||||
7
go.mod
7
go.mod
@ -1,6 +1,6 @@
|
||||
module backend
|
||||
|
||||
go 1.25.0
|
||||
go 1.25.5
|
||||
|
||||
require (
|
||||
github.com/Ullaakut/nmap v2.0.2+incompatible
|
||||
@ -36,6 +36,7 @@ require github.com/nacos-group/nacos-sdk-go/v2 v2.3.5
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
gitea.bywaystudios.com/pet_home/nacos v0.0.0-20260422063809-d6268b6aa6e3 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||
github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect
|
||||
@ -57,6 +58,7 @@ require (
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 // indirect
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 // indirect
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.4.1 // indirect
|
||||
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
@ -80,6 +82,7 @@ require (
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
@ -117,7 +120,7 @@ require (
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
golang.org/x/time v0.4.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@ -33,6 +33,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
gitea.bywaystudios.com/pet_home/nacos v0.0.0-20260422063809-d6268b6aa6e3 h1:uqq/4VOcpAxjpYH2DwdTc4+VZPGi1Nlavdkcu0mr0V4=
|
||||
gitea.bywaystudios.com/pet_home/nacos v0.0.0-20260422063809-d6268b6aa6e3/go.mod h1:0VmTyAIjgzP6OWN4IlomxfcGIBsslBdGb1wW+DgojcY=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
@ -126,6 +128,8 @@ github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1r
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg=
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI=
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU=
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.4.1 h1:wF5rZUhhahzJiRSeLSCQhAkaDBXLa/R893C/ZmEpGcE=
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.4.1/go.mod h1:FTzydeQVmR24FI0D6XWUOMKckjXehM/jgMn1xC+DA9M=
|
||||
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4=
|
||||
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ=
|
||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||
@ -285,6 +289,8 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
@ -689,6 +695,8 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
||||
6
main.go
6
main.go
@ -119,6 +119,7 @@ func main() {
|
||||
api.POST("/log/user", controller.UserDetail)
|
||||
api.POST("/log/asset", controller.Asset)
|
||||
api.POST("/log/event", controller.Event)
|
||||
api.POST("/log/loginCountByMonth", controller.LoginCountByMonth)
|
||||
api.POST("/log/order", controller.Order)
|
||||
|
||||
// 玩家数据
|
||||
@ -170,8 +171,9 @@ func main() {
|
||||
// 自动化脚本
|
||||
scripts := r.Group("/api/scripts", middleware.ValidateToken())
|
||||
{
|
||||
scripts.POST("/copywriting", controller.Copywriting) // 下载文案文件
|
||||
scripts.POST("/copyonline", controller.CopyOnline) // 复制线上环境到QA
|
||||
scripts.POST("/copywriting", controller.Copywriting) // 下载文案文件
|
||||
scripts.POST("/copyonline", controller.CopyOnline) // 复制线上环境到QA
|
||||
scripts.POST("/clientImageGitPull", controller.ClientImageGitPull) // 复制线下环境到QA
|
||||
}
|
||||
config.InitConfig()
|
||||
//go util.ScheduleDailyTask()
|
||||
|
||||
@ -692,11 +692,14 @@ func SendOrderMsg(data *Type.OrderData) (_err error) {
|
||||
SearchSupport: imGroupOpenSpaceModelSearchSupport,
|
||||
}
|
||||
var isTest string
|
||||
var color string
|
||||
chargeUid := global_config.GetTestChargeUidList()
|
||||
if slices.Contains(chargeUid, data.UID) {
|
||||
isTest = "[测试]"
|
||||
isTest = "[测试账号]"
|
||||
color = "blue"
|
||||
} else {
|
||||
isTest = ""
|
||||
color = "green"
|
||||
}
|
||||
contentStr := `
|
||||
# **充值发货通知**
|
||||
@ -716,7 +719,7 @@ func SendOrderMsg(data *Type.OrderData) (_err error) {
|
||||
cardDataCardParamMap := map[string]any{
|
||||
"title": "[充值]充值发货通知",
|
||||
"markdown": content,
|
||||
"color": "green",
|
||||
"color": color,
|
||||
"config": map[string]any{
|
||||
"autoLayout": true,
|
||||
},
|
||||
|
||||
299
middleware/alibaba/oss.go
Normal file
299
middleware/alibaba/oss.go
Normal file
@ -0,0 +1,299 @@
|
||||
package alibaba
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gitea.bywaystudios.com/pet_home/nacos"
|
||||
|
||||
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
|
||||
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultOSSRegion = "cn-hangzhou"
|
||||
defaultOSSBucket = "merge-pet-elastic"
|
||||
defaultOSSObjectKey = "example-object.txt"
|
||||
defaultNacosDataID = "oss.json"
|
||||
defaultNacosGroup = "server"
|
||||
defaultNacosLogDir = "./log/nacos"
|
||||
defaultNacosCacheDir = "./runtime/nacos"
|
||||
)
|
||||
|
||||
type ossConfig struct {
|
||||
Region string `json:"region" yaml:"region"`
|
||||
Bucket string `json:"bucket" yaml:"bucket"`
|
||||
ObjectKey string `json:"objectKey" yaml:"objectKey"`
|
||||
AccessKeyID string `json:"accessKeyId" yaml:"accessKeyId"`
|
||||
AccessKeySecret string `json:"accessKeySecret" yaml:"accessKeySecret"`
|
||||
SessionToken string `json:"sessionToken" yaml:"sessionToken"`
|
||||
}
|
||||
|
||||
type ossRuntime struct {
|
||||
mu sync.RWMutex
|
||||
config ossConfig
|
||||
}
|
||||
|
||||
var (
|
||||
globalOSSRuntime ossRuntime
|
||||
ossInitOnce sync.Once
|
||||
dotenvLoadOnce sync.Once
|
||||
)
|
||||
|
||||
func Osscreate() {
|
||||
config, err := initOSSConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("加载 OSS 配置失败: %v", err)
|
||||
}
|
||||
|
||||
cfg := oss.LoadDefaultConfig().
|
||||
WithCredentialsProvider(credentials.NewStaticCredentialsProvider(config.AccessKeyID, config.AccessKeySecret, config.SessionToken)).
|
||||
WithRegion(config.Region)
|
||||
|
||||
client := oss.NewClient(cfg)
|
||||
|
||||
body := strings.NewReader("Hello OSS from Go SDK V2!")
|
||||
|
||||
request := &oss.PutObjectRequest{
|
||||
Bucket: oss.Ptr(config.Bucket),
|
||||
Key: oss.Ptr(config.ObjectKey),
|
||||
Body: body,
|
||||
}
|
||||
|
||||
result, err := client.PutObject(context.TODO(), request)
|
||||
if err != nil {
|
||||
log.Fatalf("上传失败: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("上传成功! ETag: %s\n", *result.ETag)
|
||||
}
|
||||
|
||||
func initOSSConfig() (ossConfig, error) {
|
||||
loadDotEnv()
|
||||
|
||||
var initErr error
|
||||
ossInitOnce.Do(func() {
|
||||
config, err := loadOSSConfig()
|
||||
if err != nil {
|
||||
initErr = err
|
||||
return
|
||||
}
|
||||
globalOSSRuntime.set(config)
|
||||
|
||||
if err := watchOSSConfigChanges(); err != nil {
|
||||
log.Printf("监听 Nacos OSS 配置失败,继续使用当前配置: %v", err)
|
||||
}
|
||||
})
|
||||
if initErr != nil {
|
||||
return ossConfig{}, initErr
|
||||
}
|
||||
|
||||
config, ok := globalOSSRuntime.get()
|
||||
if !ok {
|
||||
return ossConfig{}, fmt.Errorf("oss config is not initialized")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func loadDotEnv() {
|
||||
dotenvLoadOnce.Do(func() {
|
||||
if err := godotenv.Load(); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Printf("加载 .env 失败,继续使用现有环境变量: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func loadOSSConfig() (ossConfig, error) {
|
||||
baseConfig := loadOSSConfigFromEnv()
|
||||
config := baseConfig
|
||||
|
||||
nacosConfig, err := loadOSSConfigFromNacos()
|
||||
if err != nil {
|
||||
log.Printf("从 Nacos 读取 OSS 配置失败,回退环境变量: %v", err)
|
||||
} else {
|
||||
config = mergeOSSConfig(baseConfig, nacosConfig)
|
||||
}
|
||||
|
||||
return normalizeOSSConfig(config)
|
||||
}
|
||||
|
||||
func loadOSSConfigFromEnv() ossConfig {
|
||||
return ossConfig{
|
||||
Region: strings.TrimSpace(os.Getenv("OSS_REGION")),
|
||||
Bucket: strings.TrimSpace(os.Getenv("OSS_BUCKET")),
|
||||
ObjectKey: strings.TrimSpace(os.Getenv("OSS_OBJECT_KEY")),
|
||||
AccessKeyID: strings.TrimSpace(os.Getenv("OSS_ACCESS_KEY_ID")),
|
||||
AccessKeySecret: strings.TrimSpace(os.Getenv("OSS_ACCESS_KEY_SECRET")),
|
||||
SessionToken: strings.TrimSpace(os.Getenv("OSS_SESSION_TOKEN")),
|
||||
}
|
||||
}
|
||||
|
||||
func loadOSSConfigFromNacos() (ossConfig, error) {
|
||||
client, err := newNacosClient()
|
||||
if err != nil {
|
||||
return ossConfig{}, err
|
||||
}
|
||||
|
||||
var config ossConfig
|
||||
dataID := getEnvOrDefault("OSS_NACOS_DATA_ID", defaultNacosDataID)
|
||||
group := getEnvOrDefault("OSS_NACOS_GROUP", getEnvOrDefault("NACOS_GROUP", defaultNacosGroup))
|
||||
if err := client.GetJSON(dataID, group, &config); err != nil {
|
||||
return ossConfig{}, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func watchOSSConfigChanges() error {
|
||||
client, err := newNacosClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataID := getEnvOrDefault("OSS_NACOS_DATA_ID", defaultNacosDataID)
|
||||
group := getEnvOrDefault("OSS_NACOS_GROUP", getEnvOrDefault("NACOS_GROUP", defaultNacosGroup))
|
||||
return client.Listen(dataID, group, func(event nacos.ChangeEvent) {
|
||||
var nacosConfig ossConfig
|
||||
if err := json.Unmarshal([]byte(event.Content), &nacosConfig); err != nil {
|
||||
log.Printf("解析 Nacos OSS 配置变更失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mergedConfig, err := normalizeOSSConfig(mergeOSSConfig(loadOSSConfigFromEnv(), nacosConfig))
|
||||
if err != nil {
|
||||
log.Printf("Nacos OSS 配置变更无效,保留旧配置: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
globalOSSRuntime.set(mergedConfig)
|
||||
log.Printf("OSS 配置已从 Nacos 热更新: group=%s dataId=%s", event.Group, event.DataID)
|
||||
})
|
||||
}
|
||||
|
||||
func newNacosClient() (*nacos.Client, error) {
|
||||
serverAddrs := strings.TrimSpace(os.Getenv("NACOS_SERVER_ADDRS"))
|
||||
if serverAddrs == "" {
|
||||
return nil, fmt.Errorf("NACOS_SERVER_ADDRS is empty")
|
||||
}
|
||||
|
||||
return nacos.NewClient(nacos.Options{
|
||||
Servers: parseNacosServers(serverAddrs),
|
||||
Username: strings.TrimSpace(os.Getenv("NACOS_USERNAME")),
|
||||
Password: strings.TrimSpace(os.Getenv("NACOS_PASSWORD")),
|
||||
NamespaceID: strings.TrimSpace(os.Getenv("NACOS_NAMESPACE_ID")),
|
||||
TimeoutMs: parseUintEnv("NACOS_TIMEOUT_MS", 5000),
|
||||
LogDir: getEnvOrDefault("NACOS_LOG_DIR", defaultNacosLogDir),
|
||||
CacheDir: getEnvOrDefault("NACOS_CACHE_DIR", defaultNacosCacheDir),
|
||||
LogLevel: getEnvOrDefault("NACOS_LOG_LEVEL", "info"),
|
||||
NotLoadCacheAtStart: true,
|
||||
DefaultGroup: getEnvOrDefault("NACOS_GROUP", defaultNacosGroup),
|
||||
})
|
||||
}
|
||||
|
||||
func normalizeOSSConfig(config ossConfig) (ossConfig, error) {
|
||||
if strings.TrimSpace(config.Region) == "" {
|
||||
config.Region = defaultOSSRegion
|
||||
}
|
||||
if strings.TrimSpace(config.Bucket) == "" {
|
||||
config.Bucket = defaultOSSBucket
|
||||
}
|
||||
if strings.TrimSpace(config.ObjectKey) == "" {
|
||||
config.ObjectKey = defaultOSSObjectKey
|
||||
}
|
||||
if strings.TrimSpace(config.AccessKeyID) == "" || strings.TrimSpace(config.AccessKeySecret) == "" {
|
||||
return ossConfig{}, fmt.Errorf("oss access key is empty after nacos and environment fallback")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func mergeOSSConfig(base ossConfig, override ossConfig) ossConfig {
|
||||
if strings.TrimSpace(override.Region) != "" {
|
||||
base.Region = strings.TrimSpace(override.Region)
|
||||
}
|
||||
if strings.TrimSpace(override.Bucket) != "" {
|
||||
base.Bucket = strings.TrimSpace(override.Bucket)
|
||||
}
|
||||
if strings.TrimSpace(override.ObjectKey) != "" {
|
||||
base.ObjectKey = strings.TrimSpace(override.ObjectKey)
|
||||
}
|
||||
if strings.TrimSpace(override.AccessKeyID) != "" {
|
||||
base.AccessKeyID = strings.TrimSpace(override.AccessKeyID)
|
||||
}
|
||||
if strings.TrimSpace(override.AccessKeySecret) != "" {
|
||||
base.AccessKeySecret = strings.TrimSpace(override.AccessKeySecret)
|
||||
}
|
||||
if strings.TrimSpace(override.SessionToken) != "" {
|
||||
base.SessionToken = strings.TrimSpace(override.SessionToken)
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func parseNacosServers(raw string) []nacos.Server {
|
||||
parts := strings.Split(raw, ",")
|
||||
servers := make([]nacos.Server, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
item := strings.TrimSpace(part)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
server := nacos.Server{IPAddr: item}
|
||||
if strings.Contains(item, ":") {
|
||||
host, port, found := strings.Cut(item, ":")
|
||||
if found {
|
||||
server.IPAddr = strings.TrimSpace(host)
|
||||
if parsedPort, convErr := strconv.ParseUint(strings.TrimSpace(port), 10, 64); convErr == nil {
|
||||
server.Port = parsedPort
|
||||
}
|
||||
} else {
|
||||
server.IPAddr = item
|
||||
}
|
||||
}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (r *ossRuntime) set(config ossConfig) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.config = config
|
||||
}
|
||||
|
||||
func (r *ossRuntime) get() (ossConfig, bool) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
if strings.TrimSpace(r.config.AccessKeyID) == "" || strings.TrimSpace(r.config.AccessKeySecret) == "" {
|
||||
return ossConfig{}, false
|
||||
}
|
||||
return r.config, true
|
||||
}
|
||||
|
||||
func parseUintEnv(key string, defaultValue uint64) uint64 {
|
||||
raw := strings.TrimSpace(os.Getenv(key))
|
||||
if raw == "" {
|
||||
return defaultValue
|
||||
}
|
||||
value, err := strconv.ParseUint(raw, 10, 64)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func getEnvOrDefault(key string, defaultValue string) string {
|
||||
value := strings.TrimSpace(os.Getenv(key))
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
@ -1,323 +0,0 @@
|
||||
package nacos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultGroup = "DEFAULT_GROUP"
|
||||
ContentTypeText = "text"
|
||||
ContentTypeJSON = "json"
|
||||
ContentTypeYAML = "yaml"
|
||||
defaultTimeoutMs = 5000
|
||||
defaultNacosPort = 8848
|
||||
defaultNacosScheme = "http"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmptyDataID = errors.New("nacos data id is required")
|
||||
ErrNoServers = errors.New("at least one nacos server is required")
|
||||
)
|
||||
|
||||
type Reader interface {
|
||||
Get(dataID, group string) (string, error)
|
||||
GetJSON(dataID, group string, out interface{}) error
|
||||
GetYAML(dataID, group string, out interface{}) error
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Publish(dataID, group, content string, contentType string) error
|
||||
PublishJSON(dataID, group string, value interface{}) error
|
||||
PublishYAML(dataID, group string, value interface{}) error
|
||||
Delete(dataID, group string) error
|
||||
}
|
||||
|
||||
type Watcher interface {
|
||||
Listen(dataID, group string, handler ChangeHandler) error
|
||||
CancelListen(dataID, group string) error
|
||||
}
|
||||
|
||||
type ConfigStore interface {
|
||||
Reader
|
||||
Writer
|
||||
Watcher
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IPAddr string
|
||||
Port uint64
|
||||
Scheme string
|
||||
ContextPath string
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
NamespaceID string
|
||||
Username string
|
||||
Password string
|
||||
TimeoutMs uint64
|
||||
LogDir string
|
||||
CacheDir string
|
||||
LogLevel string
|
||||
NotLoadCacheAtStart bool
|
||||
DefaultGroup string
|
||||
Servers []Server
|
||||
}
|
||||
|
||||
type ChangeEvent struct {
|
||||
Namespace string
|
||||
Group string
|
||||
DataID string
|
||||
Content string
|
||||
}
|
||||
|
||||
type ChangeHandler func(event ChangeEvent)
|
||||
|
||||
type Client struct {
|
||||
client config_client.IConfigClient
|
||||
defaultGroup string
|
||||
}
|
||||
|
||||
func NewClient(options Options) (*Client, error) {
|
||||
normalized, err := normalizeOptions(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverConfigs := make([]constant.ServerConfig, 0, len(normalized.Servers))
|
||||
for _, server := range normalized.Servers {
|
||||
serverConfigs = append(serverConfigs, constant.ServerConfig{
|
||||
IpAddr: server.IPAddr,
|
||||
Port: server.Port,
|
||||
Scheme: server.Scheme,
|
||||
ContextPath: server.ContextPath,
|
||||
})
|
||||
}
|
||||
|
||||
clientConfig := constant.ClientConfig{
|
||||
NamespaceId: normalized.NamespaceID,
|
||||
TimeoutMs: normalized.TimeoutMs,
|
||||
NotLoadCacheAtStart: normalized.NotLoadCacheAtStart,
|
||||
LogDir: normalized.LogDir,
|
||||
CacheDir: normalized.CacheDir,
|
||||
LogLevel: normalized.LogLevel,
|
||||
Username: normalized.Username,
|
||||
Password: normalized.Password,
|
||||
}
|
||||
|
||||
configClient, err := clients.NewConfigClient(vo.NacosClientParam{
|
||||
ClientConfig: &clientConfig,
|
||||
ServerConfigs: serverConfigs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create nacos config client: %w", err)
|
||||
}
|
||||
|
||||
return &Client{
|
||||
client: configClient,
|
||||
defaultGroup: normalized.DefaultGroup,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) Get(dataID, group string) (string, error) {
|
||||
param, err := c.configParam(dataID, group)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
content, err := c.client.GetConfig(param)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get nacos config %s/%s: %w", param.Group, param.DataId, err)
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetJSON(dataID, group string, out interface{}) error {
|
||||
content, err := c.Get(dataID, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(content), out); err != nil {
|
||||
return fmt.Errorf("unmarshal nacos json %s/%s: %w", c.groupOrDefault(group), dataID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) GetYAML(dataID, group string, out interface{}) error {
|
||||
content, err := c.Get(dataID, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(content), out); err != nil {
|
||||
return fmt.Errorf("unmarshal nacos yaml %s/%s: %w", c.groupOrDefault(group), dataID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Publish(dataID, group, content string, contentType string) error {
|
||||
param, err := c.configParam(dataID, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
param.Content = content
|
||||
param.Type = normalizeContentType(contentType)
|
||||
|
||||
ok, err := c.client.PublishConfig(param)
|
||||
if err != nil {
|
||||
return fmt.Errorf("publish nacos config %s/%s: %w", param.Group, param.DataId, err)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("publish nacos config %s/%s failed", param.Group, param.DataId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) PublishJSON(dataID, group string, value interface{}) error {
|
||||
payload, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal nacos json %s/%s: %w", c.groupOrDefault(group), dataID, err)
|
||||
}
|
||||
return c.Publish(dataID, group, string(payload), ContentTypeJSON)
|
||||
}
|
||||
|
||||
func (c *Client) PublishYAML(dataID, group string, value interface{}) error {
|
||||
payload, err := yaml.Marshal(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal nacos yaml %s/%s: %w", c.groupOrDefault(group), dataID, err)
|
||||
}
|
||||
return c.Publish(dataID, group, string(payload), ContentTypeYAML)
|
||||
}
|
||||
|
||||
func (c *Client) Delete(dataID, group string) error {
|
||||
param, err := c.configParam(dataID, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok, err := c.client.DeleteConfig(param)
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete nacos config %s/%s: %w", param.Group, param.DataId, err)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("delete nacos config %s/%s failed", param.Group, param.DataId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Listen(dataID, group string, handler ChangeHandler) error {
|
||||
param, err := c.configParam(dataID, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
param.OnChange = func(namespace, listenGroup, listenDataID, data string) {
|
||||
if handler == nil {
|
||||
return
|
||||
}
|
||||
handler(ChangeEvent{
|
||||
Namespace: namespace,
|
||||
Group: listenGroup,
|
||||
DataID: listenDataID,
|
||||
Content: data,
|
||||
})
|
||||
}
|
||||
|
||||
if err := c.client.ListenConfig(param); err != nil {
|
||||
return fmt.Errorf("listen nacos config %s/%s: %w", param.Group, param.DataId, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) CancelListen(dataID, group string) error {
|
||||
param, err := c.configParam(dataID, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.client.CancelListenConfig(param); err != nil {
|
||||
return fmt.Errorf("cancel nacos listen %s/%s: %w", param.Group, param.DataId, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) configParam(dataID, group string) (vo.ConfigParam, error) {
|
||||
trimmedDataID := strings.TrimSpace(dataID)
|
||||
if trimmedDataID == "" {
|
||||
return vo.ConfigParam{}, ErrEmptyDataID
|
||||
}
|
||||
|
||||
return vo.ConfigParam{
|
||||
DataId: trimmedDataID,
|
||||
Group: c.groupOrDefault(group),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) groupOrDefault(group string) string {
|
||||
trimmedGroup := strings.TrimSpace(group)
|
||||
if trimmedGroup != "" {
|
||||
return trimmedGroup
|
||||
}
|
||||
if c.defaultGroup != "" {
|
||||
return c.defaultGroup
|
||||
}
|
||||
return DefaultGroup
|
||||
}
|
||||
|
||||
func (c *Client) ListConfigs(param vo.SearchConfigParam) (*model.ConfigPage, error) {
|
||||
return c.client.SearchConfig(param)
|
||||
}
|
||||
|
||||
func normalizeOptions(options Options) (Options, error) {
|
||||
if len(options.Servers) == 0 {
|
||||
return Options{}, ErrNoServers
|
||||
}
|
||||
|
||||
if options.TimeoutMs == 0 {
|
||||
options.TimeoutMs = defaultTimeoutMs
|
||||
}
|
||||
if strings.TrimSpace(options.DefaultGroup) == "" {
|
||||
options.DefaultGroup = DefaultGroup
|
||||
}
|
||||
|
||||
normalizedServers := make([]Server, 0, len(options.Servers))
|
||||
for _, server := range options.Servers {
|
||||
ipAddr := strings.TrimSpace(server.IPAddr)
|
||||
if ipAddr == "" {
|
||||
return Options{}, errors.New("nacos server ip is required")
|
||||
}
|
||||
if server.Port == 0 {
|
||||
server.Port = defaultNacosPort
|
||||
}
|
||||
if strings.TrimSpace(server.Scheme) == "" {
|
||||
server.Scheme = defaultNacosScheme
|
||||
}
|
||||
server.IPAddr = ipAddr
|
||||
normalizedServers = append(normalizedServers, server)
|
||||
}
|
||||
options.Servers = normalizedServers
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func normalizeContentType(contentType string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(contentType)) {
|
||||
case "", ContentTypeText:
|
||||
return ContentTypeText
|
||||
case "yml", ContentTypeYAML:
|
||||
return ContentTypeYAML
|
||||
case ContentTypeJSON:
|
||||
return ContentTypeJSON
|
||||
default:
|
||||
return strings.ToLower(strings.TrimSpace(contentType))
|
||||
}
|
||||
}
|
||||
19
model/log.go
19
model/log.go
@ -11,6 +11,7 @@ type Log struct {
|
||||
PageSize int `json:"PageSize"`
|
||||
CurrentPage int `json:"CurrentPage"`
|
||||
AppId int `json:"AppId"`
|
||||
Month string `json:"Month"`
|
||||
EventParam string `json:"Event"`
|
||||
StartTime int64 `json:"StartTime"`
|
||||
EndTime int64 `json:"EndTime"`
|
||||
@ -30,6 +31,12 @@ type ResEvent struct {
|
||||
Data []*Type.EventData `json:"data"`
|
||||
}
|
||||
|
||||
type ResLoginCount struct {
|
||||
Month string `json:"month"`
|
||||
Total int `json:"total"`
|
||||
Data []*Type.LoginDailyCount `json:"data"`
|
||||
}
|
||||
|
||||
type ResOrder struct {
|
||||
Total int `json:"total"`
|
||||
Data []*Order `json:"data"`
|
||||
@ -111,6 +118,18 @@ func (m *Log) Event() (*ResEvent, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Log) LoginCountByMonth() (*ResLoginCount, error) {
|
||||
data, total, err := util.SearchLoginCountByUidMonth(m.AppId, m.Uid, m.Month)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ResLoginCount{
|
||||
Month: m.Month,
|
||||
Total: int(total),
|
||||
Data: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Log) Order() (*ResOrder, error) {
|
||||
m.AppId = m.Uid / 100000000
|
||||
AppConfig, err := util.GetAppConfig(m.AppId)
|
||||
|
||||
@ -38,6 +38,7 @@ type Mail struct {
|
||||
SendType int `json:"send_type" db:"send_type"`
|
||||
ToUids string `json:"to_uids" db:"to_uids"`
|
||||
CreateTime int64 `json:"create_time" db:"create_time"`
|
||||
MinLevel int `json:"min_level" db:"level"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
@ -87,7 +88,8 @@ func (m *Mail) SendMail() error {
|
||||
return fmt.Errorf("failed to get mysql db")
|
||||
}
|
||||
defer Db.Close()
|
||||
_, err = Db.Exec("INSERT INTO system_mail_info (`title`, `content`, `title_en`, `content_en`, `start_time`, `end_time`, `items`, `register_time`, `mail_type`, `send_type`, `to_uids`, `create_time`, `subTitle`, `subTitle_en`, `title_ptbr`,`content_ptbr`,`subTitle_ptbr`, `title_es_latam`, `subTitle_es_latam`, `content_es_latam`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.Title, m.Content, m.TitleEn, m.ContentEn, m.StartTime, m.EndTime, m.Items, m.RegisterTime, m.MailType, m.SendType, m.ToUids, m.CreateTime, m.SubTitle, m.SubTitleEn, m.TitlePtBr, m.ContentPtBr, m.SubTitlePtBr, m.TitleEsLatam, m.SubTitleEsLatam, m.ContentEsLatam)
|
||||
m.CreateTime = util.Now()
|
||||
_, err = Db.Exec("INSERT INTO system_mail_info (`title`, `content`, `title_en`, `content_en`, `start_time`, `end_time`, `items`, `register_time`, `mail_type`, `send_type`, `to_uids`, `create_time`, `subTitle`, `subTitle_en`, `title_ptbr`,`content_ptbr`,`subTitle_ptbr`, `title_es_latam`, `subTitle_es_latam`, `content_es_latam`, `level`, `create_time`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.Title, m.Content, m.TitleEn, m.ContentEn, m.StartTime, m.EndTime, m.Items, m.RegisterTime, m.MailType, m.SendType, m.ToUids, m.CreateTime, m.SubTitle, m.SubTitleEn, m.TitlePtBr, m.ContentPtBr, m.SubTitlePtBr, m.TitleEsLatam, m.SubTitleEsLatam, m.ContentEsLatam, m.MinLevel, m.CreateTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert mail: %v", err)
|
||||
}
|
||||
|
||||
@ -2,12 +2,16 @@ package monitor
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"backend/client"
|
||||
"backend/middleware/alibaba"
|
||||
"backend/model"
|
||||
"backend/msg"
|
||||
"backend/util"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
func UserAliveMonitor(AppId int) {
|
||||
@ -32,8 +36,8 @@ func UserAliveMonitor(AppId int) {
|
||||
`
|
||||
if drop >= 0.3 && (yCount-curCount) >= int64(10) {
|
||||
alibaba.SendAliveMsg("服务器报警", fmt.Sprintf(str,
|
||||
time.Now().Add(-time.Hour).Format("2006-01-02 15:04:05"),
|
||||
time.Now().Format("2006-01-02 15:04:05"),
|
||||
time.Now().Add(time.Hour).Format("2006-01-02 15:04:05"),
|
||||
yCount,
|
||||
curCount,
|
||||
drop*100), "red")
|
||||
@ -65,6 +69,26 @@ func monitorServerInfo() {
|
||||
if v.Status == 2 || v.Status == 3 { // 维护中或停用跳过
|
||||
continue
|
||||
}
|
||||
if v.AppId == 1 {
|
||||
go func(v *Type.ServerInfo) {
|
||||
resp, err := client.GetServerInfo(v.AppId, v.ServerId, &msg.ReqServerInfo{})
|
||||
if err != nil {
|
||||
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()
|
||||
|
||||
@ -30524,6 +30524,130 @@ func (x *ResUserDetailInfo) GetOrder() []*UserDetailOrderInfo {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ResServerInfo struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
PlayerNum int32 `protobuf:"varint,1,opt,name=PlayerNum,proto3" json:"PlayerNum,omitempty"` // 玩家数量
|
||||
FreeMem uint64 `protobuf:"varint,2,opt,name=FreeMem,proto3" json:"FreeMem,omitempty"` // 空闲内存
|
||||
CPU float64 `protobuf:"fixed64,3,opt,name=CPU,proto3" json:"CPU,omitempty"` // Cpu使用率
|
||||
StartTime int32 `protobuf:"varint,4,opt,name=StartTime,proto3" json:"StartTime,omitempty"` // 启动时间
|
||||
TotalAlloc string `protobuf:"bytes,5,opt,name=TotalAlloc,proto3" json:"TotalAlloc,omitempty"` // 总内存分配
|
||||
Alloc string `protobuf:"bytes,6,opt,name=Alloc,proto3" json:"Alloc,omitempty"` // 当前内存分配
|
||||
Sys uint64 `protobuf:"varint,7,opt,name=Sys,proto3" json:"Sys,omitempty"` // 系统内存分配
|
||||
NumGC uint32 `protobuf:"varint,8,opt,name=NumGC,proto3" json:"NumGC,omitempty"` // GC次数
|
||||
NumGoroutine int32 `protobuf:"varint,9,opt,name=NumGoroutine,proto3" json:"NumGoroutine,omitempty"` // 协程数量
|
||||
UsageMem uint64 `protobuf:"varint,10,opt,name=UsageMem,proto3" json:"UsageMem,omitempty"` // 内存使用率
|
||||
Version string `protobuf:"bytes,11,opt,name=Version,proto3" json:"Version,omitempty"` // 服务器版本
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) Reset() {
|
||||
*x = ResServerInfo{}
|
||||
mi := &file_proto_Gameapi_proto_msgTypes[517]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ResServerInfo) ProtoMessage() {}
|
||||
|
||||
func (x *ResServerInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_Gameapi_proto_msgTypes[517]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ResServerInfo.ProtoReflect.Descriptor instead.
|
||||
func (*ResServerInfo) Descriptor() ([]byte, []int) {
|
||||
return file_proto_Gameapi_proto_rawDescGZIP(), []int{517}
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetPlayerNum() int32 {
|
||||
if x != nil {
|
||||
return x.PlayerNum
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetFreeMem() uint64 {
|
||||
if x != nil {
|
||||
return x.FreeMem
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetCPU() float64 {
|
||||
if x != nil {
|
||||
return x.CPU
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetStartTime() int32 {
|
||||
if x != nil {
|
||||
return x.StartTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetTotalAlloc() string {
|
||||
if x != nil {
|
||||
return x.TotalAlloc
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetAlloc() string {
|
||||
if x != nil {
|
||||
return x.Alloc
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetSys() uint64 {
|
||||
if x != nil {
|
||||
return x.Sys
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetNumGC() uint32 {
|
||||
if x != nil {
|
||||
return x.NumGC
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetNumGoroutine() int32 {
|
||||
if x != nil {
|
||||
return x.NumGoroutine
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetUsageMem() uint64 {
|
||||
if x != nil {
|
||||
return x.UsageMem
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResServerInfo) GetVersion() string {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_proto_Gameapi_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_proto_Gameapi_proto_rawDesc = "" +
|
||||
@ -32788,7 +32912,22 @@ const file_proto_Gameapi_proto_rawDesc = "" +
|
||||
"\x05Order\x18\x17 \x03(\v2\x1d.tutorial.UserDetailOrderInfoR\x05Order\x1a;\n" +
|
||||
"\rChessMapEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\x05R\x05value:\x028\x01*\xab\f\n" +
|
||||
"\x05value\x18\x02 \x01(\x05R\x05value:\x028\x01\"\xaf\x02\n" +
|
||||
"\rResServerInfo\x12\x1c\n" +
|
||||
"\tPlayerNum\x18\x01 \x01(\x05R\tPlayerNum\x12\x18\n" +
|
||||
"\aFreeMem\x18\x02 \x01(\x04R\aFreeMem\x12\x10\n" +
|
||||
"\x03CPU\x18\x03 \x01(\x01R\x03CPU\x12\x1c\n" +
|
||||
"\tStartTime\x18\x04 \x01(\x05R\tStartTime\x12\x1e\n" +
|
||||
"\n" +
|
||||
"TotalAlloc\x18\x05 \x01(\tR\n" +
|
||||
"TotalAlloc\x12\x14\n" +
|
||||
"\x05Alloc\x18\x06 \x01(\tR\x05Alloc\x12\x10\n" +
|
||||
"\x03Sys\x18\a \x01(\x04R\x03Sys\x12\x14\n" +
|
||||
"\x05NumGC\x18\b \x01(\rR\x05NumGC\x12\"\n" +
|
||||
"\fNumGoroutine\x18\t \x01(\x05R\fNumGoroutine\x12\x1a\n" +
|
||||
"\bUsageMem\x18\n" +
|
||||
" \x01(\x04R\bUsageMem\x12\x18\n" +
|
||||
"\aVersion\x18\v \x01(\tR\aVersion*\xab\f\n" +
|
||||
"\x0eITEM_POP_LABEL\x12\f\n" +
|
||||
"\bPlayroom\x10\x00\x12\r\n" +
|
||||
"\tPiggyBank\x10\x01\x12\n" +
|
||||
@ -33036,12 +33175,14 @@ const file_proto_Gameapi_proto_rawDesc = "" +
|
||||
"\x1cFRIEND_REPLY_HANDLE_ERR_TYPE\x12\b\n" +
|
||||
"\x04NONE\x10\x00\x12\n" +
|
||||
"\n" +
|
||||
"\x06CATNIP\x10\x012\xe6\x01\n" +
|
||||
"\x06CATNIP\x10\x012\xa6\x02\n" +
|
||||
"\aBackend\x12P\n" +
|
||||
"\x0eReloadActivity\x12\x1e.tutorial.ReqActivityCfgReload\x1a\x1e.tutorial.ResActivityCfgReload\x12G\n" +
|
||||
"\rOrderShipping\x12\x1a.tutorial.ReqOrderShipping\x1a\x1a.tutorial.ResOrderShipping\x12@\n" +
|
||||
"\n" +
|
||||
"UserDetail\x12\x19.tutorial.UserDetailParam\x1a\x17.tutorial.ResUserDetailB\bZ\x06../msgb\x06proto3"
|
||||
"UserDetail\x12\x19.tutorial.UserDetailParam\x1a\x17.tutorial.ResUserDetail\x12>\n" +
|
||||
"\n" +
|
||||
"ServerInfo\x12\x17.tutorial.ReqServerInfo\x1a\x17.tutorial.ResServerInfoB\bZ\x06../msgb\x06proto3"
|
||||
|
||||
var (
|
||||
file_proto_Gameapi_proto_rawDescOnce sync.Once
|
||||
@ -33056,7 +33197,7 @@ func file_proto_Gameapi_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_proto_Gameapi_proto_enumTypes = make([]protoimpl.EnumInfo, 14)
|
||||
var file_proto_Gameapi_proto_msgTypes = make([]protoimpl.MessageInfo, 593)
|
||||
var file_proto_Gameapi_proto_msgTypes = make([]protoimpl.MessageInfo, 594)
|
||||
var file_proto_Gameapi_proto_goTypes = []any{
|
||||
(ITEM_POP_LABEL)(0), // 0: tutorial.ITEM_POP_LABEL
|
||||
(HANDLE_TYPE)(0), // 1: tutorial.HANDLE_TYPE
|
||||
@ -33589,120 +33730,121 @@ var file_proto_Gameapi_proto_goTypes = []any{
|
||||
(*UserDetailOrderInfo)(nil), // 528: tutorial.UserDetailOrderInfo
|
||||
(*UserDetailOrderInfoChess)(nil), // 529: tutorial.UserDetailOrderInfoChess
|
||||
(*ResUserDetailInfo)(nil), // 530: tutorial.ResUserDetailInfo
|
||||
nil, // 531: tutorial.ResChessColorData.MChessColorDataEntry
|
||||
nil, // 532: tutorial.UpdateBaseItemInfo.MUpdateItemEntry
|
||||
nil, // 533: tutorial.ResPlayerChessData.MChessDataEntry
|
||||
nil, // 534: tutorial.ReqPutPartInBag.MChessDataEntry
|
||||
nil, // 535: tutorial.UpdatePlayerChessData.MChessDataEntry
|
||||
nil, // 536: tutorial.ReqSeparateChess.MChessDataEntry
|
||||
nil, // 537: tutorial.ReqUpgradeChess.MChessDataEntry
|
||||
nil, // 538: tutorial.ReqGetChessFromBuff.MChessDataEntry
|
||||
nil, // 539: tutorial.ReqChessEx.MChessDataEntry
|
||||
nil, // 540: tutorial.ReqSourceChest.MChessDataEntry
|
||||
nil, // 541: tutorial.ReqPlayroomOutline.MChessDataEntry
|
||||
nil, // 542: tutorial.ReqPutChessInBag.MChessDataEntry
|
||||
nil, // 543: tutorial.ReqTakeChessOutBag.MChessDataEntry
|
||||
nil, // 544: tutorial.ResPlayerBriefProfileData.SetEmojiEntry
|
||||
nil, // 545: tutorial.UserInfo.SetEmojiEntry
|
||||
nil, // 546: tutorial.ReqRewardOrder.MChessDataEntry
|
||||
nil, // 547: tutorial.ResCardInfo.AllCardEntry
|
||||
nil, // 548: tutorial.ResCardInfo.HandbookEntry
|
||||
nil, // 549: tutorial.ResGuideInfo.RewardEntry
|
||||
nil, // 550: tutorial.ResGuideTask.TaskEntry
|
||||
nil, // 551: tutorial.ResDailyTask.WeekRewardEntry
|
||||
nil, // 552: tutorial.ResDailyTask.DailyTaskEntry
|
||||
nil, // 553: tutorial.ResLimitEvent.LimitEventListEntry
|
||||
nil, // 554: tutorial.ResLimitEventProgress.ProgressRewardEntry
|
||||
nil, // 555: tutorial.LimitEvent.ParamEntry
|
||||
nil, // 556: tutorial.ReqLimitEventLuckyCat.MChessDataEntry
|
||||
nil, // 557: tutorial.ResFriendPlayerSimple.EmojiEntry
|
||||
nil, // 558: tutorial.ResFriendPlayerSimple.PlayroomEntry
|
||||
nil, // 559: tutorial.ResFriendPlayerSimple.DressSetEntry
|
||||
nil, // 560: tutorial.ResFriendPlayerSimple.PhysiologyEntry
|
||||
nil, // 561: tutorial.ResPlayerSimple.EmojiEntry
|
||||
nil, // 562: tutorial.ResPlayerRank.PlayroomSetEntry
|
||||
nil, // 563: tutorial.ResPlayerRank.DressSetEntry
|
||||
nil, // 564: tutorial.ResKv.KvEntry
|
||||
nil, // 565: tutorial.ResRank.RankListEntry
|
||||
nil, // 566: tutorial.ResMailList.MailListEntry
|
||||
nil, // 567: tutorial.ResCharge.SpecialShopEntry
|
||||
nil, // 568: tutorial.ResCharge.ChessShopEntry
|
||||
nil, // 569: tutorial.ResCharge.GiftEntry
|
||||
nil, // 570: tutorial.ResCharge.WeeklyDiscountEntry
|
||||
nil, // 571: tutorial.ReqBuyChessShop2.MChessDataEntry
|
||||
nil, // 572: tutorial.ResEndless.EndlessListEntry
|
||||
nil, // 573: tutorial.ResChampshipRank.RankListEntry
|
||||
nil, // 574: tutorial.ResChampshipPreRank.RankListEntry
|
||||
nil, // 575: tutorial.ResNotifyCard.CardEntry
|
||||
nil, // 576: tutorial.ResNotifyCard.MasterEntry
|
||||
nil, // 577: tutorial.ResNotifyCard.HandbookEntry
|
||||
nil, // 578: tutorial.ResMining.MapEntry
|
||||
nil, // 579: tutorial.ResMining.PassRewardEntry
|
||||
nil, // 580: tutorial.ReqMiningTake.MapEntry
|
||||
nil, // 581: tutorial.ResActRed.RedEntry
|
||||
nil, // 582: tutorial.ResItem.ItemEntry
|
||||
nil, // 583: tutorial.ItemNotify.ItemEntry
|
||||
nil, // 584: tutorial.ResGuessColor.OMapEntry
|
||||
nil, // 585: tutorial.ReqGuessColorTake.OMapEntry
|
||||
nil, // 586: tutorial.GuessColorInfo.MapEntry
|
||||
nil, // 587: tutorial.ResPlayroom.PlayroomEntry
|
||||
nil, // 588: tutorial.ResPlayroom.MoodEntry
|
||||
nil, // 589: tutorial.ResPlayroom.PhysiologyEntry
|
||||
nil, // 590: tutorial.ResPlayroom.DressEntry
|
||||
nil, // 591: tutorial.ResPlayroom.DressSetEntry
|
||||
nil, // 592: tutorial.ResPlayroom.WeeklyDiscountEntry
|
||||
nil, // 593: tutorial.ReqPlayroomDressSet.DressSetEntry
|
||||
nil, // 594: tutorial.NotifyPlayroomMood.MoodEntry
|
||||
nil, // 595: tutorial.NotifyPlayroomMood.PhysiologyEntry
|
||||
nil, // 596: tutorial.ResPlayroomInfo.PlayroomEntry
|
||||
nil, // 597: tutorial.ResPlayroomInfo.ItemsEntry
|
||||
nil, // 598: tutorial.ResPlayroomInfo.FlipEntry
|
||||
nil, // 599: tutorial.ResPlayroomInfo.EmojiEntry
|
||||
nil, // 600: tutorial.ResPlayroomInfo.DressSetEntry
|
||||
nil, // 601: tutorial.ResPlayroomGame.ItemsEntry
|
||||
nil, // 602: tutorial.ReqPlayroomSetRoom.PlayroomEntry
|
||||
nil, // 603: tutorial.MiningCfg.GemEntry
|
||||
nil, // 604: tutorial.MiningCfg.JackpotEntry
|
||||
nil, // 605: tutorial.MiningCfg.PassEntry
|
||||
nil, // 606: tutorial.ResUserDetailInfo.ChessMapEntry
|
||||
(*ResServerInfo)(nil), // 531: tutorial.ResServerInfo
|
||||
nil, // 532: tutorial.ResChessColorData.MChessColorDataEntry
|
||||
nil, // 533: tutorial.UpdateBaseItemInfo.MUpdateItemEntry
|
||||
nil, // 534: tutorial.ResPlayerChessData.MChessDataEntry
|
||||
nil, // 535: tutorial.ReqPutPartInBag.MChessDataEntry
|
||||
nil, // 536: tutorial.UpdatePlayerChessData.MChessDataEntry
|
||||
nil, // 537: tutorial.ReqSeparateChess.MChessDataEntry
|
||||
nil, // 538: tutorial.ReqUpgradeChess.MChessDataEntry
|
||||
nil, // 539: tutorial.ReqGetChessFromBuff.MChessDataEntry
|
||||
nil, // 540: tutorial.ReqChessEx.MChessDataEntry
|
||||
nil, // 541: tutorial.ReqSourceChest.MChessDataEntry
|
||||
nil, // 542: tutorial.ReqPlayroomOutline.MChessDataEntry
|
||||
nil, // 543: tutorial.ReqPutChessInBag.MChessDataEntry
|
||||
nil, // 544: tutorial.ReqTakeChessOutBag.MChessDataEntry
|
||||
nil, // 545: tutorial.ResPlayerBriefProfileData.SetEmojiEntry
|
||||
nil, // 546: tutorial.UserInfo.SetEmojiEntry
|
||||
nil, // 547: tutorial.ReqRewardOrder.MChessDataEntry
|
||||
nil, // 548: tutorial.ResCardInfo.AllCardEntry
|
||||
nil, // 549: tutorial.ResCardInfo.HandbookEntry
|
||||
nil, // 550: tutorial.ResGuideInfo.RewardEntry
|
||||
nil, // 551: tutorial.ResGuideTask.TaskEntry
|
||||
nil, // 552: tutorial.ResDailyTask.WeekRewardEntry
|
||||
nil, // 553: tutorial.ResDailyTask.DailyTaskEntry
|
||||
nil, // 554: tutorial.ResLimitEvent.LimitEventListEntry
|
||||
nil, // 555: tutorial.ResLimitEventProgress.ProgressRewardEntry
|
||||
nil, // 556: tutorial.LimitEvent.ParamEntry
|
||||
nil, // 557: tutorial.ReqLimitEventLuckyCat.MChessDataEntry
|
||||
nil, // 558: tutorial.ResFriendPlayerSimple.EmojiEntry
|
||||
nil, // 559: tutorial.ResFriendPlayerSimple.PlayroomEntry
|
||||
nil, // 560: tutorial.ResFriendPlayerSimple.DressSetEntry
|
||||
nil, // 561: tutorial.ResFriendPlayerSimple.PhysiologyEntry
|
||||
nil, // 562: tutorial.ResPlayerSimple.EmojiEntry
|
||||
nil, // 563: tutorial.ResPlayerRank.PlayroomSetEntry
|
||||
nil, // 564: tutorial.ResPlayerRank.DressSetEntry
|
||||
nil, // 565: tutorial.ResKv.KvEntry
|
||||
nil, // 566: tutorial.ResRank.RankListEntry
|
||||
nil, // 567: tutorial.ResMailList.MailListEntry
|
||||
nil, // 568: tutorial.ResCharge.SpecialShopEntry
|
||||
nil, // 569: tutorial.ResCharge.ChessShopEntry
|
||||
nil, // 570: tutorial.ResCharge.GiftEntry
|
||||
nil, // 571: tutorial.ResCharge.WeeklyDiscountEntry
|
||||
nil, // 572: tutorial.ReqBuyChessShop2.MChessDataEntry
|
||||
nil, // 573: tutorial.ResEndless.EndlessListEntry
|
||||
nil, // 574: tutorial.ResChampshipRank.RankListEntry
|
||||
nil, // 575: tutorial.ResChampshipPreRank.RankListEntry
|
||||
nil, // 576: tutorial.ResNotifyCard.CardEntry
|
||||
nil, // 577: tutorial.ResNotifyCard.MasterEntry
|
||||
nil, // 578: tutorial.ResNotifyCard.HandbookEntry
|
||||
nil, // 579: tutorial.ResMining.MapEntry
|
||||
nil, // 580: tutorial.ResMining.PassRewardEntry
|
||||
nil, // 581: tutorial.ReqMiningTake.MapEntry
|
||||
nil, // 582: tutorial.ResActRed.RedEntry
|
||||
nil, // 583: tutorial.ResItem.ItemEntry
|
||||
nil, // 584: tutorial.ItemNotify.ItemEntry
|
||||
nil, // 585: tutorial.ResGuessColor.OMapEntry
|
||||
nil, // 586: tutorial.ReqGuessColorTake.OMapEntry
|
||||
nil, // 587: tutorial.GuessColorInfo.MapEntry
|
||||
nil, // 588: tutorial.ResPlayroom.PlayroomEntry
|
||||
nil, // 589: tutorial.ResPlayroom.MoodEntry
|
||||
nil, // 590: tutorial.ResPlayroom.PhysiologyEntry
|
||||
nil, // 591: tutorial.ResPlayroom.DressEntry
|
||||
nil, // 592: tutorial.ResPlayroom.DressSetEntry
|
||||
nil, // 593: tutorial.ResPlayroom.WeeklyDiscountEntry
|
||||
nil, // 594: tutorial.ReqPlayroomDressSet.DressSetEntry
|
||||
nil, // 595: tutorial.NotifyPlayroomMood.MoodEntry
|
||||
nil, // 596: tutorial.NotifyPlayroomMood.PhysiologyEntry
|
||||
nil, // 597: tutorial.ResPlayroomInfo.PlayroomEntry
|
||||
nil, // 598: tutorial.ResPlayroomInfo.ItemsEntry
|
||||
nil, // 599: tutorial.ResPlayroomInfo.FlipEntry
|
||||
nil, // 600: tutorial.ResPlayroomInfo.EmojiEntry
|
||||
nil, // 601: tutorial.ResPlayroomInfo.DressSetEntry
|
||||
nil, // 602: tutorial.ResPlayroomGame.ItemsEntry
|
||||
nil, // 603: tutorial.ReqPlayroomSetRoom.PlayroomEntry
|
||||
nil, // 604: tutorial.MiningCfg.GemEntry
|
||||
nil, // 605: tutorial.MiningCfg.JackpotEntry
|
||||
nil, // 606: tutorial.MiningCfg.PassEntry
|
||||
nil, // 607: tutorial.ResUserDetailInfo.ChessMapEntry
|
||||
}
|
||||
var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
531, // 0: tutorial.ResChessColorData.mChessColorData:type_name -> tutorial.ResChessColorData.MChessColorDataEntry
|
||||
532, // 0: tutorial.ResChessColorData.mChessColorData:type_name -> tutorial.ResChessColorData.MChessColorDataEntry
|
||||
5, // 1: tutorial.ReqLogin.type:type_name -> tutorial.LOGIN_TYPE
|
||||
2, // 2: tutorial.ResId2Verify.ResultCode:type_name -> tutorial.RES_CODE
|
||||
532, // 3: tutorial.UpdateBaseItemInfo.mUpdateItem:type_name -> tutorial.UpdateBaseItemInfo.MUpdateItemEntry
|
||||
533, // 4: tutorial.ResPlayerChessData.mChessData:type_name -> tutorial.ResPlayerChessData.MChessDataEntry
|
||||
533, // 3: tutorial.UpdateBaseItemInfo.mUpdateItem:type_name -> tutorial.UpdateBaseItemInfo.MUpdateItemEntry
|
||||
534, // 4: tutorial.ResPlayerChessData.mChessData:type_name -> tutorial.ResPlayerChessData.MChessDataEntry
|
||||
74, // 5: tutorial.ResPlayerChessInfo.ChessBag:type_name -> tutorial.ChessBag
|
||||
55, // 6: tutorial.ResPlayerChessInfo.PartBag:type_name -> tutorial.PartBag
|
||||
2, // 7: tutorial.ResGetChessRetireReward.code:type_name -> tutorial.RES_CODE
|
||||
56, // 8: tutorial.PartBag.PartBagGrids:type_name -> tutorial.PartBagGrid
|
||||
534, // 9: tutorial.ReqPutPartInBag.mChessData:type_name -> tutorial.ReqPutPartInBag.MChessDataEntry
|
||||
535, // 9: tutorial.ReqPutPartInBag.mChessData:type_name -> tutorial.ReqPutPartInBag.MChessDataEntry
|
||||
2, // 10: tutorial.ResPutPartInBag.code:type_name -> tutorial.RES_CODE
|
||||
1, // 11: tutorial.ChessHandle.type:type_name -> tutorial.HANDLE_TYPE
|
||||
535, // 12: tutorial.UpdatePlayerChessData.mChessData:type_name -> tutorial.UpdatePlayerChessData.MChessDataEntry
|
||||
536, // 12: tutorial.UpdatePlayerChessData.mChessData:type_name -> tutorial.UpdatePlayerChessData.MChessDataEntry
|
||||
59, // 13: tutorial.UpdatePlayerChessData.mChessHandle:type_name -> tutorial.ChessHandle
|
||||
2, // 14: tutorial.ResUpdatePlayerChessData.code:type_name -> tutorial.RES_CODE
|
||||
536, // 15: tutorial.ReqSeparateChess.mChessData:type_name -> tutorial.ReqSeparateChess.MChessDataEntry
|
||||
537, // 15: tutorial.ReqSeparateChess.mChessData:type_name -> tutorial.ReqSeparateChess.MChessDataEntry
|
||||
2, // 16: tutorial.ResSeparateChess.code:type_name -> tutorial.RES_CODE
|
||||
537, // 17: tutorial.ReqUpgradeChess.mChessData:type_name -> tutorial.ReqUpgradeChess.MChessDataEntry
|
||||
538, // 17: tutorial.ReqUpgradeChess.mChessData:type_name -> tutorial.ReqUpgradeChess.MChessDataEntry
|
||||
2, // 18: tutorial.ResUpgradeChess.code:type_name -> tutorial.RES_CODE
|
||||
538, // 19: tutorial.ReqGetChessFromBuff.mChessData:type_name -> tutorial.ReqGetChessFromBuff.MChessDataEntry
|
||||
539, // 19: tutorial.ReqGetChessFromBuff.mChessData:type_name -> tutorial.ReqGetChessFromBuff.MChessDataEntry
|
||||
2, // 20: tutorial.ResGetChessFromBuff.code:type_name -> tutorial.RES_CODE
|
||||
7, // 21: tutorial.ReqChessEx.Type:type_name -> tutorial.CHESS_EX_TYPE
|
||||
539, // 22: tutorial.ReqChessEx.mChessData:type_name -> tutorial.ReqChessEx.MChessDataEntry
|
||||
540, // 22: tutorial.ReqChessEx.mChessData:type_name -> tutorial.ReqChessEx.MChessDataEntry
|
||||
2, // 23: tutorial.ResChessEx.code:type_name -> tutorial.RES_CODE
|
||||
540, // 24: tutorial.ReqSourceChest.mChessData:type_name -> tutorial.ReqSourceChest.MChessDataEntry
|
||||
541, // 24: tutorial.ReqSourceChest.mChessData:type_name -> tutorial.ReqSourceChest.MChessDataEntry
|
||||
2, // 25: tutorial.ResSourceChest.code:type_name -> tutorial.RES_CODE
|
||||
541, // 26: tutorial.ReqPlayroomOutline.mChessData:type_name -> tutorial.ReqPlayroomOutline.MChessDataEntry
|
||||
542, // 26: tutorial.ReqPlayroomOutline.mChessData:type_name -> tutorial.ReqPlayroomOutline.MChessDataEntry
|
||||
2, // 27: tutorial.ResPlayroomOutline.code:type_name -> tutorial.RES_CODE
|
||||
75, // 28: tutorial.ChessBag.ChessBagGrids:type_name -> tutorial.ChessBagGrid
|
||||
542, // 29: tutorial.ReqPutChessInBag.mChessData:type_name -> tutorial.ReqPutChessInBag.MChessDataEntry
|
||||
543, // 29: tutorial.ReqPutChessInBag.mChessData:type_name -> tutorial.ReqPutChessInBag.MChessDataEntry
|
||||
2, // 30: tutorial.ResPutChessInBag.code:type_name -> tutorial.RES_CODE
|
||||
543, // 31: tutorial.ReqTakeChessOutBag.mChessData:type_name -> tutorial.ReqTakeChessOutBag.MChessDataEntry
|
||||
544, // 31: tutorial.ReqTakeChessOutBag.mChessData:type_name -> tutorial.ReqTakeChessOutBag.MChessDataEntry
|
||||
2, // 32: tutorial.ResTakeChessOutBag.code:type_name -> tutorial.RES_CODE
|
||||
2, // 33: tutorial.ResTakeChessOutBagToHonor.code:type_name -> tutorial.RES_CODE
|
||||
2, // 34: tutorial.ResBuyChessBagGrid.code:type_name -> tutorial.RES_CODE
|
||||
544, // 35: tutorial.ResPlayerBriefProfileData.SetEmoji:type_name -> tutorial.ResPlayerBriefProfileData.SetEmojiEntry
|
||||
545, // 35: tutorial.ResPlayerBriefProfileData.SetEmoji:type_name -> tutorial.ResPlayerBriefProfileData.SetEmojiEntry
|
||||
2, // 36: tutorial.ResSetEnergyMul.ResultCode:type_name -> tutorial.RES_CODE
|
||||
8, // 37: tutorial.ReqLang.Lang:type_name -> tutorial.LANG_TYPE
|
||||
2, // 38: tutorial.ResLang.ResultCode:type_name -> tutorial.RES_CODE
|
||||
@ -33710,7 +33852,7 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
195, // 40: tutorial.UserInfo.AvatarList:type_name -> tutorial.AvatarInfo
|
||||
191, // 41: tutorial.UserInfo.FaceList:type_name -> tutorial.FaceInfo
|
||||
198, // 42: tutorial.UserInfo.EmojiList:type_name -> tutorial.EmojiInfo
|
||||
545, // 43: tutorial.UserInfo.SetEmoji:type_name -> tutorial.UserInfo.SetEmojiEntry
|
||||
546, // 43: tutorial.UserInfo.SetEmoji:type_name -> tutorial.UserInfo.SetEmojiEntry
|
||||
2, // 44: tutorial.ResSetName.ResultCode:type_name -> tutorial.RES_CODE
|
||||
2, // 45: tutorial.ResSetPetName.ResultCode:type_name -> tutorial.RES_CODE
|
||||
2, // 46: tutorial.ResBuyEnergy.Code:type_name -> tutorial.RES_CODE
|
||||
@ -33718,7 +33860,7 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
2, // 48: tutorial.ResGetHandbookReward.Code:type_name -> tutorial.RES_CODE
|
||||
105, // 49: tutorial.Handbook.Handbooks:type_name -> tutorial.HandbookInfo
|
||||
2, // 50: tutorial.ResHandbookAllReward.Code:type_name -> tutorial.RES_CODE
|
||||
546, // 51: tutorial.ReqRewardOrder.mChessData:type_name -> tutorial.ReqRewardOrder.MChessDataEntry
|
||||
547, // 51: tutorial.ReqRewardOrder.mChessData:type_name -> tutorial.ReqRewardOrder.MChessDataEntry
|
||||
2, // 52: tutorial.ResRewardOrder.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 53: tutorial.ResDelOrder.Code:type_name -> tutorial.RES_CODE
|
||||
171, // 54: tutorial.Order.Items:type_name -> tutorial.ItemInfo
|
||||
@ -33729,8 +33871,8 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
2, // 59: tutorial.ResDecorateAll.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 60: tutorial.ResAreaReward.Code:type_name -> tutorial.RES_CODE
|
||||
127, // 61: tutorial.ResCardInfo.CardList:type_name -> tutorial.Card
|
||||
547, // 62: tutorial.ResCardInfo.AllCard:type_name -> tutorial.ResCardInfo.AllCardEntry
|
||||
548, // 63: tutorial.ResCardInfo.Handbook:type_name -> tutorial.ResCardInfo.HandbookEntry
|
||||
548, // 62: tutorial.ResCardInfo.AllCard:type_name -> tutorial.ResCardInfo.AllCardEntry
|
||||
549, // 63: tutorial.ResCardInfo.Handbook:type_name -> tutorial.ResCardInfo.HandbookEntry
|
||||
2, // 64: tutorial.ResCardSeasonFirstReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 65: tutorial.ResCardHandbookReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 66: tutorial.ResMasterCard.Code:type_name -> tutorial.RES_CODE
|
||||
@ -33749,16 +33891,16 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
2, // 79: tutorial.ResGetFriendCard.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 80: tutorial.ResGuideReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 81: tutorial.ResGuidePlayroom.Code:type_name -> tutorial.RES_CODE
|
||||
549, // 82: tutorial.ResGuideInfo.Reward:type_name -> tutorial.ResGuideInfo.RewardEntry
|
||||
550, // 82: tutorial.ResGuideInfo.Reward:type_name -> tutorial.ResGuideInfo.RewardEntry
|
||||
171, // 83: tutorial.ResItemPop.Items:type_name -> tutorial.ItemInfo
|
||||
173, // 84: tutorial.ResItemPop.CardPacks:type_name -> tutorial.CardPack
|
||||
171, // 85: tutorial.ItemList.List:type_name -> tutorial.ItemInfo
|
||||
550, // 86: tutorial.ResGuideTask.Task:type_name -> tutorial.ResGuideTask.TaskEntry
|
||||
551, // 86: tutorial.ResGuideTask.Task:type_name -> tutorial.ResGuideTask.TaskEntry
|
||||
183, // 87: tutorial.GuideTask.Progress:type_name -> tutorial.QuestProgress
|
||||
2, // 88: tutorial.ResGetGuideTaskReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 89: tutorial.ResGetGuideActiveReward.Code:type_name -> tutorial.RES_CODE
|
||||
551, // 90: tutorial.ResDailyTask.WeekReward:type_name -> tutorial.ResDailyTask.WeekRewardEntry
|
||||
552, // 91: tutorial.ResDailyTask.DailyTask:type_name -> tutorial.ResDailyTask.DailyTaskEntry
|
||||
552, // 90: tutorial.ResDailyTask.WeekReward:type_name -> tutorial.ResDailyTask.WeekRewardEntry
|
||||
553, // 91: tutorial.ResDailyTask.DailyTask:type_name -> tutorial.ResDailyTask.DailyTaskEntry
|
||||
171, // 92: tutorial.DailyWeek.Items:type_name -> tutorial.ItemInfo
|
||||
183, // 93: tutorial.DailyTask.Progress:type_name -> tutorial.QuestProgress
|
||||
171, // 94: tutorial.DailyTask.Items:type_name -> tutorial.ItemInfo
|
||||
@ -33780,33 +33922,33 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
208, // 110: tutorial.ResActivity.ActiveList:type_name -> tutorial.ActivityInfo
|
||||
2, // 111: tutorial.ResActivityReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 112: tutorial.ResAddGiftReward.Code:type_name -> tutorial.RES_CODE
|
||||
553, // 113: tutorial.ResLimitEvent.LimitEventList:type_name -> tutorial.ResLimitEvent.LimitEventListEntry
|
||||
554, // 114: tutorial.ResLimitEventProgress.ProgressReward:type_name -> tutorial.ResLimitEventProgress.ProgressRewardEntry
|
||||
554, // 113: tutorial.ResLimitEvent.LimitEventList:type_name -> tutorial.ResLimitEvent.LimitEventListEntry
|
||||
555, // 114: tutorial.ResLimitEventProgress.ProgressReward:type_name -> tutorial.ResLimitEventProgress.ProgressRewardEntry
|
||||
2, // 115: tutorial.ResLimitEventReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 116: tutorial.ResSelectLimitEvent.Code:type_name -> tutorial.RES_CODE
|
||||
555, // 117: tutorial.LimitEvent.Param:type_name -> tutorial.LimitEvent.ParamEntry
|
||||
556, // 118: tutorial.ReqLimitEventLuckyCat.mChessData:type_name -> tutorial.ReqLimitEventLuckyCat.MChessDataEntry
|
||||
556, // 117: tutorial.LimitEvent.Param:type_name -> tutorial.LimitEvent.ParamEntry
|
||||
557, // 118: tutorial.ReqLimitEventLuckyCat.mChessData:type_name -> tutorial.ReqLimitEventLuckyCat.MChessDataEntry
|
||||
2, // 119: tutorial.ResLimitEventLuckyCat.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 120: tutorial.ResLimitSenceReward.Code:type_name -> tutorial.RES_CODE
|
||||
171, // 121: tutorial.ResChessRainReward.Items:type_name -> tutorial.ItemInfo
|
||||
2, // 122: tutorial.ResFastProduceReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 123: tutorial.ResCatTrickReward.Code:type_name -> tutorial.RES_CODE
|
||||
237, // 124: tutorial.ResSearchPlayer.List:type_name -> tutorial.ResPlayerSimple
|
||||
557, // 125: tutorial.ResFriendPlayerSimple.Emoji:type_name -> tutorial.ResFriendPlayerSimple.EmojiEntry
|
||||
558, // 126: tutorial.ResFriendPlayerSimple.Playroom:type_name -> tutorial.ResFriendPlayerSimple.PlayroomEntry
|
||||
559, // 127: tutorial.ResFriendPlayerSimple.DressSet:type_name -> tutorial.ResFriendPlayerSimple.DressSetEntry
|
||||
558, // 125: tutorial.ResFriendPlayerSimple.Emoji:type_name -> tutorial.ResFriendPlayerSimple.EmojiEntry
|
||||
559, // 126: tutorial.ResFriendPlayerSimple.Playroom:type_name -> tutorial.ResFriendPlayerSimple.PlayroomEntry
|
||||
560, // 127: tutorial.ResFriendPlayerSimple.DressSet:type_name -> tutorial.ResFriendPlayerSimple.DressSetEntry
|
||||
238, // 128: tutorial.ResFriendPlayerSimple.Last:type_name -> tutorial.ActLog
|
||||
560, // 129: tutorial.ResFriendPlayerSimple.Physiology:type_name -> tutorial.ResFriendPlayerSimple.PhysiologyEntry
|
||||
561, // 130: tutorial.ResPlayerSimple.Emoji:type_name -> tutorial.ResPlayerSimple.EmojiEntry
|
||||
562, // 131: tutorial.ResPlayerRank.PlayroomSet:type_name -> tutorial.ResPlayerRank.PlayroomSetEntry
|
||||
563, // 132: tutorial.ResPlayerRank.DressSet:type_name -> tutorial.ResPlayerRank.DressSetEntry
|
||||
561, // 129: tutorial.ResFriendPlayerSimple.Physiology:type_name -> tutorial.ResFriendPlayerSimple.PhysiologyEntry
|
||||
562, // 130: tutorial.ResPlayerSimple.Emoji:type_name -> tutorial.ResPlayerSimple.EmojiEntry
|
||||
563, // 131: tutorial.ResPlayerRank.PlayroomSet:type_name -> tutorial.ResPlayerRank.PlayroomSetEntry
|
||||
564, // 132: tutorial.ResPlayerRank.DressSet:type_name -> tutorial.ResPlayerRank.DressSetEntry
|
||||
238, // 133: tutorial.ResPlayerRank.Last:type_name -> tutorial.ActLog
|
||||
237, // 134: tutorial.ResFriendLog.Player:type_name -> tutorial.ResPlayerSimple
|
||||
240, // 135: tutorial.NotifyFriendLog.info:type_name -> tutorial.ResFriendLog
|
||||
242, // 136: tutorial.NotifyFriendLog.Bubble:type_name -> tutorial.FriendBubbleInfo
|
||||
171, // 137: tutorial.FriendBubbleInfo.Items:type_name -> tutorial.ItemInfo
|
||||
244, // 138: tutorial.NotifyFriendCard.Info:type_name -> tutorial.ResFriendCard
|
||||
564, // 139: tutorial.ResKv.kv:type_name -> tutorial.ResKv.KvEntry
|
||||
565, // 139: tutorial.ResKv.kv:type_name -> tutorial.ResKv.KvEntry
|
||||
2, // 140: tutorial.ResFriendByCode.Code:type_name -> tutorial.RES_CODE
|
||||
237, // 141: tutorial.ResFriendByCode.Player:type_name -> tutorial.ResPlayerSimple
|
||||
237, // 142: tutorial.ResFriendRecommend.List:type_name -> tutorial.ResPlayerSimple
|
||||
@ -33835,27 +33977,27 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
237, // 165: tutorial.ResAgreeFriend.Player:type_name -> tutorial.ResPlayerSimple
|
||||
2, // 166: tutorial.ResRefuseFriend.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 167: tutorial.ResDelFriend.Code:type_name -> tutorial.RES_CODE
|
||||
565, // 168: tutorial.ResRank.RankList:type_name -> tutorial.ResRank.RankListEntry
|
||||
566, // 169: tutorial.ResMailList.MailList:type_name -> tutorial.ResMailList.MailListEntry
|
||||
566, // 168: tutorial.ResRank.RankList:type_name -> tutorial.ResRank.RankListEntry
|
||||
567, // 169: tutorial.ResMailList.MailList:type_name -> tutorial.ResMailList.MailListEntry
|
||||
171, // 170: tutorial.MailInfo.Items:type_name -> tutorial.ItemInfo
|
||||
293, // 171: tutorial.MailNotify.Info:type_name -> tutorial.MailInfo
|
||||
2, // 172: tutorial.ResReadMail.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 173: tutorial.ResGetMailReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 174: tutorial.ResDeleteMail.Code:type_name -> tutorial.RES_CODE
|
||||
567, // 175: tutorial.ResCharge.SpecialShop:type_name -> tutorial.ResCharge.SpecialShopEntry
|
||||
568, // 176: tutorial.ResCharge.ChessShop:type_name -> tutorial.ResCharge.ChessShopEntry
|
||||
569, // 177: tutorial.ResCharge.Gift:type_name -> tutorial.ResCharge.GiftEntry
|
||||
568, // 175: tutorial.ResCharge.SpecialShop:type_name -> tutorial.ResCharge.SpecialShopEntry
|
||||
569, // 176: tutorial.ResCharge.ChessShop:type_name -> tutorial.ResCharge.ChessShopEntry
|
||||
570, // 177: tutorial.ResCharge.Gift:type_name -> tutorial.ResCharge.GiftEntry
|
||||
304, // 178: tutorial.ResCharge.Wish:type_name -> tutorial.WishList
|
||||
570, // 179: tutorial.ResCharge.WeeklyDiscount:type_name -> tutorial.ResCharge.WeeklyDiscountEntry
|
||||
571, // 179: tutorial.ResCharge.WeeklyDiscount:type_name -> tutorial.ResCharge.WeeklyDiscountEntry
|
||||
2, // 180: tutorial.ResAddWish.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 181: tutorial.ResGetWish.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 182: tutorial.ResSendWishBeg.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 183: tutorial.ResFreeShop.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 184: tutorial.ResBuyChessShop.Code:type_name -> tutorial.RES_CODE
|
||||
571, // 185: tutorial.ReqBuyChessShop2.mChessData:type_name -> tutorial.ReqBuyChessShop2.MChessDataEntry
|
||||
572, // 185: tutorial.ReqBuyChessShop2.mChessData:type_name -> tutorial.ReqBuyChessShop2.MChessDataEntry
|
||||
2, // 186: tutorial.ResBuyChessShop2.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 187: tutorial.ResRefreshChessShop.Code:type_name -> tutorial.RES_CODE
|
||||
572, // 188: tutorial.ResEndless.EndlessList:type_name -> tutorial.ResEndless.EndlessListEntry
|
||||
573, // 188: tutorial.ResEndless.EndlessList:type_name -> tutorial.ResEndless.EndlessListEntry
|
||||
171, // 189: tutorial.ResEndlessInfo.Items:type_name -> tutorial.ItemInfo
|
||||
2, // 190: tutorial.ResEndlessReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 191: tutorial.ResPiggyBankReward.Code:type_name -> tutorial.RES_CODE
|
||||
@ -33868,12 +34010,12 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
171, // 198: tutorial.ChampionshipCfgRank.Items:type_name -> tutorial.ItemInfo
|
||||
2, // 199: tutorial.ResChampshipReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 200: tutorial.ResChampshipRankReward.Code:type_name -> tutorial.RES_CODE
|
||||
573, // 201: tutorial.ResChampshipRank.RankList:type_name -> tutorial.ResChampshipRank.RankListEntry
|
||||
574, // 202: tutorial.ResChampshipPreRank.RankList:type_name -> tutorial.ResChampshipPreRank.RankListEntry
|
||||
574, // 201: tutorial.ResChampshipRank.RankList:type_name -> tutorial.ResChampshipRank.RankListEntry
|
||||
575, // 202: tutorial.ResChampshipPreRank.RankList:type_name -> tutorial.ResChampshipPreRank.RankListEntry
|
||||
337, // 203: tutorial.ResChampshipPreRank.Cfg:type_name -> tutorial.ChampionshipCfg
|
||||
575, // 204: tutorial.ResNotifyCard.Card:type_name -> tutorial.ResNotifyCard.CardEntry
|
||||
576, // 205: tutorial.ResNotifyCard.Master:type_name -> tutorial.ResNotifyCard.MasterEntry
|
||||
577, // 206: tutorial.ResNotifyCard.Handbook:type_name -> tutorial.ResNotifyCard.HandbookEntry
|
||||
576, // 204: tutorial.ResNotifyCard.Card:type_name -> tutorial.ResNotifyCard.CardEntry
|
||||
577, // 205: tutorial.ResNotifyCard.Master:type_name -> tutorial.ResNotifyCard.MasterEntry
|
||||
578, // 206: tutorial.ResNotifyCard.Handbook:type_name -> tutorial.ResNotifyCard.HandbookEntry
|
||||
2, // 207: tutorial.ResSetFacebookUrl.Code:type_name -> tutorial.RES_CODE
|
||||
364, // 208: tutorial.CatReturnGiftCfg.RewardList:type_name -> tutorial.CatReturnGiftCfgReward
|
||||
171, // 209: tutorial.CatReturnGiftCfgReward.Reward:type_name -> tutorial.ItemInfo
|
||||
@ -33881,22 +34023,22 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
2, // 211: tutorial.ResCatReturnGiftScore.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 212: tutorial.ResCatReturnGiftReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 213: tutorial.ResCatReturnGiftRewardGift.Code:type_name -> tutorial.RES_CODE
|
||||
578, // 214: tutorial.ResMining.Map:type_name -> tutorial.ResMining.MapEntry
|
||||
579, // 215: tutorial.ResMining.PassReward:type_name -> tutorial.ResMining.PassRewardEntry
|
||||
580, // 216: tutorial.ReqMiningTake.Map:type_name -> tutorial.ReqMiningTake.MapEntry
|
||||
579, // 214: tutorial.ResMining.Map:type_name -> tutorial.ResMining.MapEntry
|
||||
580, // 215: tutorial.ResMining.PassReward:type_name -> tutorial.ResMining.PassRewardEntry
|
||||
581, // 216: tutorial.ReqMiningTake.Map:type_name -> tutorial.ReqMiningTake.MapEntry
|
||||
2, // 217: tutorial.ResMiningTake.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 218: tutorial.ResMiningReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 219: tutorial.ResActPassReward.Code:type_name -> tutorial.RES_CODE
|
||||
581, // 220: tutorial.ResActRed.Red:type_name -> tutorial.ResActRed.RedEntry
|
||||
582, // 220: tutorial.ResActRed.Red:type_name -> tutorial.ResActRed.RedEntry
|
||||
208, // 221: tutorial.ActivityNotify.Info:type_name -> tutorial.ActivityInfo
|
||||
582, // 222: tutorial.ResItem.Item:type_name -> tutorial.ResItem.ItemEntry
|
||||
583, // 223: tutorial.ItemNotify.Item:type_name -> tutorial.ItemNotify.ItemEntry
|
||||
583, // 222: tutorial.ResItem.Item:type_name -> tutorial.ResItem.ItemEntry
|
||||
584, // 223: tutorial.ItemNotify.Item:type_name -> tutorial.ItemNotify.ItemEntry
|
||||
391, // 224: tutorial.ResGuessColor.MapList:type_name -> tutorial.GuessColorInfo
|
||||
584, // 225: tutorial.ResGuessColor.OMap:type_name -> tutorial.ResGuessColor.OMapEntry
|
||||
585, // 225: tutorial.ResGuessColor.OMap:type_name -> tutorial.ResGuessColor.OMapEntry
|
||||
389, // 226: tutorial.ResGuessColor.Opponent:type_name -> tutorial.opponent
|
||||
391, // 227: tutorial.ReqGuessColorTake.Map:type_name -> tutorial.GuessColorInfo
|
||||
585, // 228: tutorial.ReqGuessColorTake.OMap:type_name -> tutorial.ReqGuessColorTake.OMapEntry
|
||||
586, // 229: tutorial.GuessColorInfo.Map:type_name -> tutorial.GuessColorInfo.MapEntry
|
||||
586, // 228: tutorial.ReqGuessColorTake.OMap:type_name -> tutorial.ReqGuessColorTake.OMapEntry
|
||||
587, // 229: tutorial.GuessColorInfo.Map:type_name -> tutorial.GuessColorInfo.MapEntry
|
||||
2, // 230: tutorial.ResGuessColorTake.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 231: tutorial.ResGuessColorReward.Code:type_name -> tutorial.RES_CODE
|
||||
397, // 232: tutorial.ResRace.Opponent:type_name -> tutorial.raceopponent
|
||||
@ -33907,19 +34049,19 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
171, // 237: tutorial.ResPlayroom.Items:type_name -> tutorial.ItemInfo
|
||||
438, // 238: tutorial.ResPlayroom.Opponent:type_name -> tutorial.RoomOpponent
|
||||
437, // 239: tutorial.ResPlayroom.Friend:type_name -> tutorial.FriendRoom
|
||||
587, // 240: tutorial.ResPlayroom.Playroom:type_name -> tutorial.ResPlayroom.PlayroomEntry
|
||||
588, // 240: tutorial.ResPlayroom.Playroom:type_name -> tutorial.ResPlayroom.PlayroomEntry
|
||||
423, // 241: tutorial.ResPlayroom.collect:type_name -> tutorial.PlayroomCollectInfo
|
||||
588, // 242: tutorial.ResPlayroom.Mood:type_name -> tutorial.ResPlayroom.MoodEntry
|
||||
589, // 242: tutorial.ResPlayroom.Mood:type_name -> tutorial.ResPlayroom.MoodEntry
|
||||
171, // 243: tutorial.ResPlayroom.LoseItem:type_name -> tutorial.ItemInfo
|
||||
433, // 244: tutorial.ResPlayroom.Chip:type_name -> tutorial.ChipInfo
|
||||
589, // 245: tutorial.ResPlayroom.Physiology:type_name -> tutorial.ResPlayroom.PhysiologyEntry
|
||||
590, // 246: tutorial.ResPlayroom.Dress:type_name -> tutorial.ResPlayroom.DressEntry
|
||||
591, // 247: tutorial.ResPlayroom.DressSet:type_name -> tutorial.ResPlayroom.DressSetEntry
|
||||
590, // 245: tutorial.ResPlayroom.Physiology:type_name -> tutorial.ResPlayroom.PhysiologyEntry
|
||||
591, // 246: tutorial.ResPlayroom.Dress:type_name -> tutorial.ResPlayroom.DressEntry
|
||||
592, // 247: tutorial.ResPlayroom.DressSet:type_name -> tutorial.ResPlayroom.DressSetEntry
|
||||
422, // 248: tutorial.ResPlayroom.PetAir:type_name -> tutorial.PlayroomAirInfo
|
||||
182, // 249: tutorial.ResPlayroom.DailyTask:type_name -> tutorial.DailyTask
|
||||
435, // 250: tutorial.ResPlayroom.AdItem:type_name -> tutorial.AdItem
|
||||
437, // 251: tutorial.ResPlayroom.Target:type_name -> tutorial.FriendRoom
|
||||
592, // 252: tutorial.ResPlayroom.WeeklyDiscount:type_name -> tutorial.ResPlayroom.WeeklyDiscountEntry
|
||||
593, // 252: tutorial.ResPlayroom.WeeklyDiscount:type_name -> tutorial.ResPlayroom.WeeklyDiscountEntry
|
||||
182, // 253: tutorial.NotifyPlayroomTask.DailyTask:type_name -> tutorial.DailyTask
|
||||
237, // 254: tutorial.NotifyPlayroomBroken.Player:type_name -> tutorial.ResPlayerSimple
|
||||
2, // 255: tutorial.ResPlayroomTask.Code:type_name -> tutorial.RES_CODE
|
||||
@ -33927,28 +34069,28 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
2, // 257: tutorial.ResPlayroomUnlock.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 258: tutorial.ResPlayroomUpvote.Code:type_name -> tutorial.RES_CODE
|
||||
421, // 259: tutorial.PlayroomDress.List:type_name -> tutorial.PlayroomDressInfo
|
||||
593, // 260: tutorial.ReqPlayroomDressSet.DressSet:type_name -> tutorial.ReqPlayroomDressSet.DressSetEntry
|
||||
594, // 260: tutorial.ReqPlayroomDressSet.DressSet:type_name -> tutorial.ReqPlayroomDressSet.DressSetEntry
|
||||
2, // 261: tutorial.ResPlayroomDressSet.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 262: tutorial.ResPlayroomPetAirSet.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 263: tutorial.ResPlayroomWorkOutline.Code:type_name -> tutorial.RES_CODE
|
||||
171, // 264: tutorial.NotifyPlayroomLose.LoseItem:type_name -> tutorial.ItemInfo
|
||||
433, // 265: tutorial.NotifyPlayroomLose.Chip:type_name -> tutorial.ChipInfo
|
||||
594, // 266: tutorial.NotifyPlayroomMood.Mood:type_name -> tutorial.NotifyPlayroomMood.MoodEntry
|
||||
595, // 267: tutorial.NotifyPlayroomMood.Physiology:type_name -> tutorial.NotifyPlayroomMood.PhysiologyEntry
|
||||
595, // 266: tutorial.NotifyPlayroomMood.Mood:type_name -> tutorial.NotifyPlayroomMood.MoodEntry
|
||||
596, // 267: tutorial.NotifyPlayroomMood.Physiology:type_name -> tutorial.NotifyPlayroomMood.PhysiologyEntry
|
||||
435, // 268: tutorial.NotifyPlayroomMood.AdItem:type_name -> tutorial.AdItem
|
||||
596, // 269: tutorial.ResPlayroomInfo.Playroom:type_name -> tutorial.ResPlayroomInfo.PlayroomEntry
|
||||
597, // 270: tutorial.ResPlayroomInfo.Items:type_name -> tutorial.ResPlayroomInfo.ItemsEntry
|
||||
598, // 271: tutorial.ResPlayroomInfo.flip:type_name -> tutorial.ResPlayroomInfo.FlipEntry
|
||||
599, // 272: tutorial.ResPlayroomInfo.Emoji:type_name -> tutorial.ResPlayroomInfo.EmojiEntry
|
||||
600, // 273: tutorial.ResPlayroomInfo.DressSet:type_name -> tutorial.ResPlayroomInfo.DressSetEntry
|
||||
597, // 269: tutorial.ResPlayroomInfo.Playroom:type_name -> tutorial.ResPlayroomInfo.PlayroomEntry
|
||||
598, // 270: tutorial.ResPlayroomInfo.Items:type_name -> tutorial.ResPlayroomInfo.ItemsEntry
|
||||
599, // 271: tutorial.ResPlayroomInfo.flip:type_name -> tutorial.ResPlayroomInfo.FlipEntry
|
||||
600, // 272: tutorial.ResPlayroomInfo.Emoji:type_name -> tutorial.ResPlayroomInfo.EmojiEntry
|
||||
601, // 273: tutorial.ResPlayroomInfo.DressSet:type_name -> tutorial.ResPlayroomInfo.DressSetEntry
|
||||
2, // 274: tutorial.ResPlayroomFlip.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 275: tutorial.ResPlayroomGuide.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 276: tutorial.ResPlayroomFlipReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 277: tutorial.ResPlayroomGame.Code:type_name -> tutorial.RES_CODE
|
||||
601, // 278: tutorial.ResPlayroomGame.Items:type_name -> tutorial.ResPlayroomGame.ItemsEntry
|
||||
602, // 278: tutorial.ResPlayroomGame.Items:type_name -> tutorial.ResPlayroomGame.ItemsEntry
|
||||
171, // 279: tutorial.ResPlayroomGameShowReward.Items:type_name -> tutorial.ItemInfo
|
||||
2, // 280: tutorial.ResPlayroomInteract.Code:type_name -> tutorial.RES_CODE
|
||||
602, // 281: tutorial.ReqPlayroomSetRoom.Playroom:type_name -> tutorial.ReqPlayroomSetRoom.PlayroomEntry
|
||||
603, // 281: tutorial.ReqPlayroomSetRoom.Playroom:type_name -> tutorial.ReqPlayroomSetRoom.PlayroomEntry
|
||||
2, // 282: tutorial.ResPlayroomSetRoom.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 283: tutorial.ResPlayroomSelectReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 284: tutorial.ResPlayroomLose.Code:type_name -> tutorial.RES_CODE
|
||||
@ -33979,16 +34121,16 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
2, // 309: tutorial.ResCatnipGrandReward.Code:type_name -> tutorial.RES_CODE
|
||||
2, // 310: tutorial.ResCatnipEmoji.Code:type_name -> tutorial.RES_CODE
|
||||
171, // 311: tutorial.MiningCfg.itemCost:type_name -> tutorial.ItemInfo
|
||||
603, // 312: tutorial.MiningCfg.Gem:type_name -> tutorial.MiningCfg.GemEntry
|
||||
604, // 313: tutorial.MiningCfg.Jackpot:type_name -> tutorial.MiningCfg.JackpotEntry
|
||||
605, // 314: tutorial.MiningCfg.Pass:type_name -> tutorial.MiningCfg.PassEntry
|
||||
604, // 312: tutorial.MiningCfg.Gem:type_name -> tutorial.MiningCfg.GemEntry
|
||||
605, // 313: tutorial.MiningCfg.Jackpot:type_name -> tutorial.MiningCfg.JackpotEntry
|
||||
606, // 314: tutorial.MiningCfg.Pass:type_name -> tutorial.MiningCfg.PassEntry
|
||||
171, // 315: tutorial.MiningCfgJackpot.Items:type_name -> tutorial.ItemInfo
|
||||
171, // 316: tutorial.MiningCfgPass.Items:type_name -> tutorial.ItemInfo
|
||||
521, // 317: tutorial.ReqActivityCfgReload.List:type_name -> tutorial.ActivityCfg
|
||||
530, // 318: tutorial.ResUserDetail.info:type_name -> tutorial.ResUserDetailInfo
|
||||
529, // 319: tutorial.UserDetailOrderInfo.Chess:type_name -> tutorial.UserDetailOrderInfoChess
|
||||
529, // 320: tutorial.UserDetailOrderInfo.ChessId:type_name -> tutorial.UserDetailOrderInfoChess
|
||||
606, // 321: tutorial.ResUserDetailInfo.ChessMap:type_name -> tutorial.ResUserDetailInfo.ChessMapEntry
|
||||
607, // 321: tutorial.ResUserDetailInfo.ChessMap:type_name -> tutorial.ResUserDetailInfo.ChessMapEntry
|
||||
238, // 322: tutorial.ResUserDetailInfo.ActLog:type_name -> tutorial.ActLog
|
||||
527, // 323: tutorial.ResUserDetailInfo.FriendList:type_name -> tutorial.UserDetailFriendInfo
|
||||
528, // 324: tutorial.ResUserDetailInfo.Order:type_name -> tutorial.UserDetailOrderInfo
|
||||
@ -34015,11 +34157,13 @@ var file_proto_Gameapi_proto_depIdxs = []int32{
|
||||
520, // 345: tutorial.Backend.ReloadActivity:input_type -> tutorial.ReqActivityCfgReload
|
||||
523, // 346: tutorial.Backend.OrderShipping:input_type -> tutorial.ReqOrderShipping
|
||||
525, // 347: tutorial.Backend.UserDetail:input_type -> tutorial.UserDetailParam
|
||||
522, // 348: tutorial.Backend.ReloadActivity:output_type -> tutorial.ResActivityCfgReload
|
||||
524, // 349: tutorial.Backend.OrderShipping:output_type -> tutorial.ResOrderShipping
|
||||
526, // 350: tutorial.Backend.UserDetail:output_type -> tutorial.ResUserDetail
|
||||
348, // [348:351] is the sub-list for method output_type
|
||||
345, // [345:348] is the sub-list for method input_type
|
||||
515, // 348: tutorial.Backend.ServerInfo:input_type -> tutorial.ReqServerInfo
|
||||
522, // 349: tutorial.Backend.ReloadActivity:output_type -> tutorial.ResActivityCfgReload
|
||||
524, // 350: tutorial.Backend.OrderShipping:output_type -> tutorial.ResOrderShipping
|
||||
526, // 351: tutorial.Backend.UserDetail:output_type -> tutorial.ResUserDetail
|
||||
531, // 352: tutorial.Backend.ServerInfo:output_type -> tutorial.ResServerInfo
|
||||
349, // [349:353] is the sub-list for method output_type
|
||||
345, // [345:349] is the sub-list for method input_type
|
||||
345, // [345:345] is the sub-list for extension type_name
|
||||
345, // [345:345] is the sub-list for extension extendee
|
||||
0, // [0:345] is the sub-list for field type_name
|
||||
@ -34036,7 +34180,7 @@ func file_proto_Gameapi_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_Gameapi_proto_rawDesc), len(file_proto_Gameapi_proto_rawDesc)),
|
||||
NumEnums: 14,
|
||||
NumMessages: 593,
|
||||
NumMessages: 594,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@ -22,6 +22,7 @@ const (
|
||||
Backend_ReloadActivity_FullMethodName = "/tutorial.Backend/ReloadActivity"
|
||||
Backend_OrderShipping_FullMethodName = "/tutorial.Backend/OrderShipping"
|
||||
Backend_UserDetail_FullMethodName = "/tutorial.Backend/UserDetail"
|
||||
Backend_ServerInfo_FullMethodName = "/tutorial.Backend/ServerInfo"
|
||||
)
|
||||
|
||||
// BackendClient is the client API for Backend service.
|
||||
@ -31,6 +32,7 @@ type BackendClient interface {
|
||||
ReloadActivity(ctx context.Context, in *ReqActivityCfgReload, opts ...grpc.CallOption) (*ResActivityCfgReload, error)
|
||||
OrderShipping(ctx context.Context, in *ReqOrderShipping, opts ...grpc.CallOption) (*ResOrderShipping, error)
|
||||
UserDetail(ctx context.Context, in *UserDetailParam, opts ...grpc.CallOption) (*ResUserDetail, error)
|
||||
ServerInfo(ctx context.Context, in *ReqServerInfo, opts ...grpc.CallOption) (*ResServerInfo, error)
|
||||
}
|
||||
|
||||
type backendClient struct {
|
||||
@ -71,6 +73,16 @@ func (c *backendClient) UserDetail(ctx context.Context, in *UserDetailParam, opt
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backendClient) ServerInfo(ctx context.Context, in *ReqServerInfo, opts ...grpc.CallOption) (*ResServerInfo, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ResServerInfo)
|
||||
err := c.cc.Invoke(ctx, Backend_ServerInfo_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BackendServer is the server API for Backend service.
|
||||
// All implementations must embed UnimplementedBackendServer
|
||||
// for forward compatibility.
|
||||
@ -78,6 +90,7 @@ type BackendServer interface {
|
||||
ReloadActivity(context.Context, *ReqActivityCfgReload) (*ResActivityCfgReload, error)
|
||||
OrderShipping(context.Context, *ReqOrderShipping) (*ResOrderShipping, error)
|
||||
UserDetail(context.Context, *UserDetailParam) (*ResUserDetail, error)
|
||||
ServerInfo(context.Context, *ReqServerInfo) (*ResServerInfo, error)
|
||||
mustEmbedUnimplementedBackendServer()
|
||||
}
|
||||
|
||||
@ -97,6 +110,9 @@ func (UnimplementedBackendServer) OrderShipping(context.Context, *ReqOrderShippi
|
||||
func (UnimplementedBackendServer) UserDetail(context.Context, *UserDetailParam) (*ResUserDetail, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UserDetail not implemented")
|
||||
}
|
||||
func (UnimplementedBackendServer) ServerInfo(context.Context, *ReqServerInfo) (*ResServerInfo, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ServerInfo not implemented")
|
||||
}
|
||||
func (UnimplementedBackendServer) mustEmbedUnimplementedBackendServer() {}
|
||||
func (UnimplementedBackendServer) testEmbeddedByValue() {}
|
||||
|
||||
@ -172,6 +188,24 @@ func _Backend_UserDetail_Handler(srv interface{}, ctx context.Context, dec func(
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Backend_ServerInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ReqServerInfo)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackendServer).ServerInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Backend_ServerInfo_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackendServer).ServerInfo(ctx, req.(*ReqServerInfo))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Backend_ServiceDesc is the grpc.ServiceDesc for Backend service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -191,6 +225,10 @@ var Backend_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "UserDetail",
|
||||
Handler: _Backend_UserDetail_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ServerInfo",
|
||||
Handler: _Backend_ServerInfo_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "proto/Gameapi.proto",
|
||||
|
||||
77
unit_test.go
77
unit_test.go
@ -2,26 +2,59 @@ package main
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"backend/client"
|
||||
"backend/common"
|
||||
global_config "backend/global"
|
||||
"backend/middleware/alibaba"
|
||||
"backend/middleware/feishu"
|
||||
"backend/middleware/nacos"
|
||||
"backend/model"
|
||||
"backend/msg"
|
||||
"backend/sdk/ship/model/tuyou"
|
||||
"backend/util"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gitea.bywaystudios.com/pet_home/nacos"
|
||||
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
loadTestEnv()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func loadTestEnv() {
|
||||
workingDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for dir := workingDir; ; dir = filepath.Dir(dir) {
|
||||
envPath := filepath.Join(dir, ".env")
|
||||
if stat, statErr := os.Stat(envPath); statErr == nil && !stat.IsDir() {
|
||||
_ = godotenv.Load(envPath)
|
||||
return
|
||||
}
|
||||
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGolbalConfig(t *testing.T) {
|
||||
global_config.InitConfig()
|
||||
config := global_config.GetTestChargeUidList()
|
||||
@ -460,4 +493,46 @@ func TestNacos(t *testing.T) {
|
||||
}
|
||||
|
||||
fmt.Printf("Config data: %+v\n", res)
|
||||
|
||||
data := make(map[string]interface{})
|
||||
err = client.GetYAML("mysql", "server", &data)
|
||||
if err != nil {
|
||||
fmt.Println("Error getting YAML config from Nacos:", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("MySQL Config: %+v\n", data)
|
||||
}
|
||||
|
||||
func TestServerInfo(t *testing.T) {
|
||||
start := time.Now()
|
||||
resp, err := client.GetServerInfo(1, 0, &msg.ReqServerInfo{})
|
||||
if err != nil {
|
||||
fmt.Printf("获取服务器信息失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
latency := time.Since(start).Milliseconds()
|
||||
fmt.Printf("服务器响应时间: %d ms\n", latency)
|
||||
fmt.Printf("服务器信息: %+v\n", resp)
|
||||
}
|
||||
|
||||
func TestLoginCountByMonth(t *testing.T) {
|
||||
log := model.Log{
|
||||
AppId: 0,
|
||||
Uid: 132889,
|
||||
CurrentPage: 1,
|
||||
PageSize: 20,
|
||||
Month: "2026-04",
|
||||
}
|
||||
r, e := log.LoginCountByMonth()
|
||||
if e != nil {
|
||||
fmt.Print(e)
|
||||
}
|
||||
fmt.Print(r)
|
||||
}
|
||||
|
||||
func TestAlibabaOss(t *testing.T) {
|
||||
err := common.Init()
|
||||
if err != nil {
|
||||
fmt.Println("Error initializing common:", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,16 +142,16 @@ func init() {
|
||||
var MPool *MysqlPool
|
||||
|
||||
func connectToMySQLViaSSH(AppCnf *Type.App, ServerId int) (*sqlx.DB, *ssh.Client, error) {
|
||||
SshConfig, err := common.GetServerConfig(AppCnf.NodeName)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get SSH config: %v", err)
|
||||
}
|
||||
MysqlConfig, err := common.GetMysqlConfig(AppCnf.MysqlName)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get MySQL config: %v", err)
|
||||
}
|
||||
SP, _ := Decrypt(SshConfig.Password)
|
||||
if common.GetSsh() {
|
||||
SshConfig, err := common.GetServerConfig(AppCnf.NodeName)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get SSH config: %v", err)
|
||||
}
|
||||
SP, _ := Decrypt(SshConfig.Password)
|
||||
// 创建 SSH 客户端配置
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: SshConfig.Username,
|
||||
|
||||
162
util/es.go
162
util/es.go
@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/elastic/go-elasticsearch/v8"
|
||||
@ -301,6 +302,167 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam
|
||||
return assets, total, nil
|
||||
}
|
||||
|
||||
func SearchLoginCountByUidMonth(app, _uid int, month string) ([]*Type.LoginDailyCount, int64, error) {
|
||||
uid := Int(_uid)
|
||||
if uid <= 0 {
|
||||
return nil, 0, fmt.Errorf("invalid uid")
|
||||
}
|
||||
if month == "" {
|
||||
return nil, 0, fmt.Errorf("month is required")
|
||||
}
|
||||
|
||||
appConfig, err := GetAppConfig(app)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
loc := time.UTC
|
||||
if appConfig.Tz != "" {
|
||||
loc, err = time.LoadLocation(appConfig.Tz)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("invalid app timezone: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
monthTime, err := time.ParseInLocation("2006-01", month, loc)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("invalid month format, expected YYYY-MM: %w", err)
|
||||
}
|
||||
|
||||
monthStart := time.Date(monthTime.Year(), monthTime.Month(), 1, 0, 0, 0, 0, loc)
|
||||
monthEnd := monthStart.AddDate(0, 1, 0).Add(-time.Second)
|
||||
region := GetAppRegion(app)
|
||||
|
||||
dailyFilters := make(map[string]interface{})
|
||||
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{}{
|
||||
"gte": dayStart.Unix(),
|
||||
"lte": dayEnd.Unix(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
query := map[string]interface{}{
|
||||
"bool": map[string]interface{}{
|
||||
"must": []map[string]interface{}{
|
||||
{
|
||||
"term": map[string]interface{}{
|
||||
"game.#distinct_id.keyword": uid,
|
||||
},
|
||||
},
|
||||
{
|
||||
"term": map[string]interface{}{
|
||||
"fields.environment": region,
|
||||
},
|
||||
},
|
||||
{
|
||||
"term": map[string]interface{}{
|
||||
"game.#event_name.keyword": "Login_log",
|
||||
},
|
||||
},
|
||||
{
|
||||
"range": map[string]interface{}{
|
||||
"game.#timestamp": map[string]interface{}{
|
||||
"gte": monthStart.Unix(),
|
||||
"lte": monthEnd.Unix(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
client, err := GetEsClient()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
fullQuery := map[string]interface{}{
|
||||
"query": query,
|
||||
"size": 0,
|
||||
"aggs": map[string]interface{}{
|
||||
"daily_login": map[string]interface{}{
|
||||
"filters": map[string]interface{}{
|
||||
"filters": dailyFilters,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(fullQuery); err != nil {
|
||||
return nil, 0, fmt.Errorf("编码查询失败: %w", err)
|
||||
}
|
||||
|
||||
res, err := client.Search(
|
||||
client.Search.WithContext(context.Background()),
|
||||
client.Search.WithIndex("game-user-log*"),
|
||||
client.Search.WithBody(&buf),
|
||||
client.Search.WithTrackTotalHits(true),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("执行搜索失败: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.IsError() {
|
||||
bodyBytes, _ := io.ReadAll(res.Body)
|
||||
return nil, 0, fmt.Errorf("ES 搜索错误 [%s]: %s", res.Status(), string(bodyBytes))
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
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 value, ok := totalObj["value"].(float64); ok {
|
||||
total = int64(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
for day, bucket := range buckets {
|
||||
bucketMap, ok := bucket.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if docCount, ok := bucketMap["doc_count"].(float64); ok {
|
||||
counts[day] = int64(docCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dates := make([]string, 0, len(dailyFilters))
|
||||
for day := range dailyFilters {
|
||||
dates = append(dates, day)
|
||||
}
|
||||
sort.Strings(dates)
|
||||
|
||||
data := make([]*Type.LoginDailyCount, 0, len(dates))
|
||||
for _, day := range dates {
|
||||
data = append(data, &Type.LoginDailyCount{
|
||||
Date: day,
|
||||
Count: counts[day],
|
||||
})
|
||||
}
|
||||
|
||||
return data, total, nil
|
||||
}
|
||||
|
||||
// CountDistinctUidLastHour 查询一个小时前的 game-user-log 索引中 game.#distinct_id 的去重个数
|
||||
// 返回值:(当前小时的去重用户数, 一天前同一小时的去重用户数, error)
|
||||
func CountDistinctUidLastHour() (int64, int64, error) {
|
||||
|
||||
@ -248,7 +248,7 @@ func MonitorServerList() {
|
||||
func _initServerList() {
|
||||
Db := MPool.GetGameDB()
|
||||
defer Db.Close()
|
||||
rows, err := Db.Query("SELECT AppId, ServerId, Status, Host, Port, MaxOnline, Online, version, weight FROM server WHERE Status = 1 AND node_type = 1 ORDER BY ServerId")
|
||||
rows, err := Db.Query("SELECT AppId, ServerId, Status, Host, Port, MaxOnline, Online, version, weight FROM server WHERE Status = 1 ORDER BY ServerId")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
129
util/util.go
129
util/util.go
@ -13,6 +13,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@ -837,3 +838,131 @@ func FormatJson(v string) string {
|
||||
}
|
||||
return string(jsonBytes)
|
||||
}
|
||||
|
||||
func GetAddressLatency(Host string, Port int) (int64, error) {
|
||||
address := fmt.Sprintf("%s:%d", Host, Port)
|
||||
timeout := 3 * time.Second
|
||||
start := time.Now()
|
||||
conn, err := net.DialTimeout("tcp", address, timeout)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
conn.Close()
|
||||
latency := time.Since(start).Milliseconds()
|
||||
return latency, nil
|
||||
}
|
||||
|
||||
func Float(a interface{}) float64 {
|
||||
if a == nil {
|
||||
return 0
|
||||
}
|
||||
return toFloat64(a)
|
||||
}
|
||||
|
||||
func parseMemoryTextToMB(value string) float64 {
|
||||
s := strings.TrimSpace(strings.ToUpper(value))
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
multiplier := 1.0
|
||||
switch {
|
||||
case strings.HasSuffix(s, "TB"):
|
||||
multiplier = 1024 * 1024
|
||||
s = strings.TrimSuffix(s, "TB")
|
||||
case strings.HasSuffix(s, "GB"):
|
||||
multiplier = 1024
|
||||
s = strings.TrimSuffix(s, "GB")
|
||||
case strings.HasSuffix(s, "MB"):
|
||||
s = strings.TrimSuffix(s, "MB")
|
||||
case strings.HasSuffix(s, "KB"):
|
||||
multiplier = 1.0 / 1024
|
||||
s = strings.TrimSuffix(s, "KB")
|
||||
case strings.HasSuffix(s, "B"):
|
||||
multiplier = 1.0 / (1024 * 1024)
|
||||
s = strings.TrimSuffix(s, "B")
|
||||
}
|
||||
|
||||
numberText := strings.TrimSpace(s)
|
||||
if numberText == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
parsed, err := strconv.ParseFloat(numberText, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
if parsed < 0 {
|
||||
return 0
|
||||
}
|
||||
return parsed * multiplier
|
||||
}
|
||||
|
||||
func clampFloat(value, min, max float64) float64 {
|
||||
if value < min {
|
||||
return min
|
||||
}
|
||||
if value > max {
|
||||
return max
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func GetServerWeight(resp *msg.ResServerInfo) int {
|
||||
const (
|
||||
memCapMB = 16384.0
|
||||
playerSoftCap = 1500.0
|
||||
goroutineSoftCap = 20000.0
|
||||
gcSoftCap = 2000.0
|
||||
warmupSeconds = 600.0
|
||||
)
|
||||
|
||||
freeMemMB := float64(resp.FreeMem)
|
||||
if freeMemMB < 0 {
|
||||
freeMemMB = 0
|
||||
}
|
||||
|
||||
usagePercent := clampFloat(float64(resp.UsageMem), 0, 100)
|
||||
if usagePercent == 0 && resp.Sys > 0 {
|
||||
allocMB := parseMemoryTextToMB(resp.Alloc)
|
||||
sysMB := float64(resp.Sys) / 1024 / 1024
|
||||
if sysMB > 0 && allocMB > 0 {
|
||||
usagePercent = clampFloat(allocMB/sysMB*100, 0, 100)
|
||||
}
|
||||
}
|
||||
|
||||
memScore := clampFloat(freeMemMB/memCapMB*100, 0, 100)
|
||||
memPressureScore := 100 - usagePercent
|
||||
cpuScore := 100 - clampFloat(resp.CPU, 0, 100)
|
||||
playerScore := 100 - clampFloat(float64(resp.PlayerNum)/playerSoftCap*100, 0, 100)
|
||||
goroutineScore := 100 - clampFloat(float64(resp.NumGoroutine)/goroutineSoftCap*100, 0, 100)
|
||||
gcScore := 100 - clampFloat(float64(resp.NumGC)/gcSoftCap*100, 0, 100)
|
||||
|
||||
warmupScore := 100.0
|
||||
if resp.StartTime > 0 {
|
||||
uptime := float64(Now() - int64(resp.StartTime))
|
||||
if uptime < 0 {
|
||||
uptime = 0
|
||||
}
|
||||
warmupScore = clampFloat(uptime/warmupSeconds*100, 0, 100)
|
||||
}
|
||||
|
||||
allocRatioScore := 100.0
|
||||
totalAllocMB := parseMemoryTextToMB(resp.TotalAlloc)
|
||||
allocMB := parseMemoryTextToMB(resp.Alloc)
|
||||
if totalAllocMB > 0 && allocMB >= 0 {
|
||||
allocRatioScore = 100 - clampFloat(allocMB/totalAllocMB*100, 0, 100)
|
||||
}
|
||||
|
||||
weight :=
|
||||
memScore*0.22 +
|
||||
memPressureScore*0.23 +
|
||||
cpuScore*0.23 +
|
||||
playerScore*0.18 +
|
||||
goroutineScore*0.05 +
|
||||
gcScore*0.03 +
|
||||
warmupScore*0.03 +
|
||||
allocRatioScore*0.02
|
||||
|
||||
return int(clampFloat(weight, 1, 100))
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user