diff --git a/.gitignore b/.gitignore index 6888a08..5aca4af 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ log/*.log *.exe* *.log runtime/*.db -config/* \ No newline at end of file +config/* +unit/config/* \ No newline at end of file diff --git a/GeoLite2-Country/GeoLite2-City.mmdb b/GeoLite2-Country/GeoLite2-City.mmdb new file mode 100644 index 0000000..c42ad92 Binary files /dev/null and b/GeoLite2-Country/GeoLite2-City.mmdb differ diff --git a/Type/t.go b/Type/t.go index e44946d..7fc525a 100644 --- a/Type/t.go +++ b/Type/t.go @@ -92,6 +92,7 @@ type ServerInfo struct { CreateTime int `json:"CreateTime" db:"CreateTime"` OpenServerTime int `json:"OpenServerTime" db:"OpenServerTime"` WsPort int `json:"WsPort" db:"ws_port"` + Port int `json:"Port" db:"Port"` Host string `json:"Host" db:"Host"` StartTime int64 `json:"StartTime"` PlayerNum int `json:"PlayerNum" db:"Online"` @@ -101,6 +102,7 @@ type ServerInfo struct { NodeTags string `json:"-" db:"node_tags"` Tags []string `json:"Tags" db:"-"` ECS int `json:"ECS" db:"ecs"` + Latency int `json:"Latency" db:"latency"` } type Server struct { diff --git a/alibaba/card.go b/alibaba/card.go index 91a438f..5460049 100644 --- a/alibaba/card.go +++ b/alibaba/card.go @@ -193,6 +193,9 @@ func SendZabbixMsg(data *Type.NotifyData) (_err error) { // 卡片接收人 Recipients: []*string{}, } + if data.Severity != "Disaster" && data.Severity != "High" { + return nil + } if data.Severity == "Disaster" || data.Severity == "High" { imGroupOpenDeliverModel.Recipients = []*string{tea.String("035105216620273488")} imGroupOpenDeliverModel.AtUserIds = map[string]*string{ @@ -292,6 +295,9 @@ func SendZabbixRecoveryMsg(data *Type.NotifyRecoveryData) (_err error) { // 卡片接收人 Recipients: []*string{}, } + if data.Severity != "Disaster" && data.Severity != "High" { + return nil + } imGroupOpenSpaceModelLastMessageI18n := map[string]*string{ "ZH_CN": tea.String(lastMessage), } @@ -458,6 +464,100 @@ func SendStandardMsg(title, content, color string) (_err error) { return _err } +func SendStandardMsg2(title, content, color string) (_err error) { + client, _err := createCardClient() + if _err != nil { + return _err + } + + accessToken, _ := GetToken() + robotCode := "dingrmgtodzxaik76jpc" + userId := "" + openConversationId := "cidivmW+tO/JGyIFM/XHNeQcA==" + templateId := "843a23ff-29d2-4efc-b7f4-2dea2766d7db.schema" + lastMessage := title + searchIcon := "" + searchDesc := "" + + createAndDeliverHeaders := &dingtalkcard_1_0.CreateAndDeliverHeaders{} + createAndDeliverHeaders.XAcsDingtalkAccessToken = tea.String(accessToken) + + imGroupOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{ + RobotCode: tea.String(robotCode), + // 卡片接收人 + Recipients: []*string{}, + AtUserIds: map[string]*string{ + "@ALL": tea.String("@ALL"), + }, + } + imGroupOpenSpaceModelLastMessageI18n := map[string]*string{ + "ZH_CN": tea.String(lastMessage), + } + imGroupOpenSpaceModelSearchSupport := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModelSearchSupport{ + SearchIcon: tea.String(searchIcon), + SearchDesc: tea.String(searchDesc), + } + imGroupOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{ + SupportForward: tea.Bool(true), + LastMessageI18n: imGroupOpenSpaceModelLastMessageI18n, + SearchSupport: imGroupOpenSpaceModelSearchSupport, + } + + // 此处使用了 MockData 作为测试数据,请结合真实场景设置卡片公有数据 + cardDataCardParamMap := map[string]any{ + "title": title, + "markdown": content, + "color": color, + "config": map[string]any{ + "autoLayout": true, + }, + } + cardDataError := error(nil) + _ = cardDataError + cardData := &dingtalkcard_1_0.CreateAndDeliverRequestCardData{ + CardParamMap: convertJSONValuesToString(cardDataCardParamMap), + } + createAndDeliverRequest := &dingtalkcard_1_0.CreateAndDeliverRequest{ + UserId: tea.String(userId), + CardTemplateId: tea.String(templateId), + // 用于标识卡片的唯一 ID,业务需自行建立关联关系,用于后续的卡片更新 + OutTrackId: tea.String(fmt.Sprintf("standard-out-track-id-%d", time.Now().Unix())), + CallbackType: tea.String("STREAM"), + CardData: cardData, + ImGroupOpenSpaceModel: imGroupOpenSpaceModel, + ImGroupOpenDeliverModel: imGroupOpenDeliverModel, + OpenSpaceId: tea.String(fmt.Sprintf("dtv1.card//im_group.%s", openConversationId)), + UserIdType: tea.Int32(1), + // CardAtUserIds: []*string{tea.String("all")}, + } + tryErr := func() (_e error) { + defer func() { + if r := tea.Recover(recover()); r != nil { + _e = r + } + }() + _, _err = client.CreateAndDeliverWithOptions(createAndDeliverRequest, createAndDeliverHeaders, &util.RuntimeOptions{}) + if _err != nil { + return _err + } + + return nil + }() + + if tryErr != nil { + var err = &tea.SDKError{} + if _t, ok := tryErr.(*tea.SDKError); ok { + err = _t + } else { + err.Message = tea.String(tryErr.Error()) + } + if !tea.BoolValue(util.Empty(err.Code)) && !tea.BoolValue(util.Empty(err.Message)) { + // err 中含有 code 和 message 属性,可帮助开发定位问题 + } + } + return _err +} + func SendAliveMsg(title, content, color string) (_err error) { client, _err := createCardClient() if _err != nil { diff --git a/common/yaml.go b/common/yaml.go index 089d214..3eae302 100644 --- a/common/yaml.go +++ b/common/yaml.go @@ -35,6 +35,7 @@ type SystemConfig struct { USOperationChatId string `yaml:"us_operation_chat_id"` // US运营群id ClientChatId string `yaml:"client_chat_id"` // 客户端群id Ssh bool `yaml:"ssh"` // 是否开启SSH连接 + Env string `yaml:"env"` // 环境变量 } type Config struct { @@ -143,6 +144,10 @@ func GetSsh() bool { return config.System.Ssh } +func GetEnv() string { + return config.System.Env +} + func GetTranlaterConfig(account string) *TranlaterUser { for _, user := range tranlaterConfig.User { if user.Account == account { diff --git a/controller/alibaba.go b/controller/alibaba.go index ca789cd..ee98dac 100644 --- a/controller/alibaba.go +++ b/controller/alibaba.go @@ -30,7 +30,7 @@ func AlibabaGameNotify(c *gin.Context) { return } content := util.ParseTmpl("./template/alibaba_notify.tmpl", r) - err := alibaba.SendStandardMsg("游戏服务报警通知", content, "red") + err := alibaba.SendStandardMsg2("游戏服务报警通知", content, "red") if err != nil { log.Printf("failed to send notify message: %v", err) } diff --git a/controller/scripts.go b/controller/scripts.go index 2b1b248..63cbe71 100644 --- a/controller/scripts.go +++ b/controller/scripts.go @@ -241,7 +241,7 @@ func CopyOnline(c *gin.Context) { case 0: success(c, map[string]interface{}{ "step": 1, - "label": "关闭QA环境服务", + "label": "复制数据库", "tips": []string{}, "code": 0, }) @@ -259,7 +259,7 @@ func CopyOnline(c *gin.Context) { util.AddAdminLog(c, "文案自动化脚本", request) } -func CopyOnlineStep1(c *gin.Context) { +func CopyOnlineStep2(c *gin.Context) { // 关闭QA环境服务 time.Sleep(time.Second) servers := util.GetAllServersByAppId(2) // AppId=2 QA环境 @@ -278,14 +278,14 @@ func CopyOnlineStep1(c *gin.Context) { } } success(c, map[string]interface{}{ - "step": 2, - "label": "复制数据库", + "step": 3, + "label": "写入数据到QA环境", "tips": []string{}, "code": 0, }) } -func CopyOnlineStep2(c *gin.Context) { +func CopyOnlineStep1(c *gin.Context) { // mysqldump 复制数据库 nodeInfo := util.GetNodeByName("devops") SshClient, err := util.NewSshClient(nodeInfo) @@ -303,8 +303,8 @@ func CopyOnlineStep2(c *gin.Context) { time.Sleep(time.Second) success(c, map[string]interface{}{ - "step": 3, - "label": "写入数据到QA环境", + "step": 2, + "label": "关闭QA环境服务", "tips": []string{}, "code": 0, }) diff --git a/controller/user.go b/controller/user.go index 4e5e092..897f455 100644 --- a/controller/user.go +++ b/controller/user.go @@ -98,6 +98,18 @@ func UserDetail(c *gin.Context) { 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 + } heat, _ := log.Heat() if err != nil { fmt.Print(err) diff --git a/main.go b/main.go index 848907f..2e72683 100644 --- a/main.go +++ b/main.go @@ -164,8 +164,10 @@ func main() { //go util.ScheduleDailyTask() go server.Server() go model.InitToken() // 初始化 Token 列表 - go util.MonitorServerList() // 启动定时任务发送信息 - go monitor.UserAliveMonitor(0) // 用户存活监控 + if common.GetEnv() == "prod" { // 生产环境才启动监控 + go monitor.UserAliveMonitor(0) // 用户存活监控 + go util.MonitorServerList() // 启动定时任务发送信息 + } go monitor.ServerInfoMonitor() // 服务器信息监控 defer func() { if err := recover(); err != nil { diff --git a/model/Statistics.go b/model/Statistics.go index 6d7e229..9f16fd8 100644 --- a/model/Statistics.go +++ b/model/Statistics.go @@ -66,54 +66,12 @@ func (s *Statistics) StatisticsInfo() (interface{}, error) { if LogDb == nil { return nil, fmt.Errorf("failed to get mysql database") } - StartTime, _ := util.GetZeroTimestamp(AppConfig.Tz, 0) - EndTime, _ := util.GetZeroTimestamp(AppConfig.Tz, 1) + var Register int var TotalRegistger int var Recharge float64 var TotalRecharge float64 var RechargeUser int - err = LogDb.Get(&Register, "select count(*) as sum from log_login where Event = 'register' and Timestamp >= ? and Timestamp <= ?", StartTime, EndTime) - if err != nil { - return nil, fmt.Errorf("failed to get register count: %v", err) - } - - err = LogDb.Get(&TotalRegistger, "select count(*) as sum from log_login where Event = 'register'") - if err != nil { - return nil, fmt.Errorf("failed to get total register count: %v", err) - } - - err = LogDb.Get(&Recharge, "select IFNULL(SUM(Price), 0) as sum from log_order where Timestamp >= ? and Timestamp <= ?", StartTime, EndTime) - if err != nil { - return nil, fmt.Errorf("failed to get recharge count: %v", err) - } - - err = LogDb.Get(&TotalRecharge, "select IFNULL(SUM(Price), 0) as sum from log_order") - if err != nil { - return nil, fmt.Errorf("failed to get total recharge count: %v", err) - } - // 充值人数统计 - err = LogDb.Get(&RechargeUser, "select count(distinct Uid) as sum from log_order where Timestamp >= ? and Timestamp <= ?", StartTime, EndTime) - if err != nil { - return nil, fmt.Errorf("failed to get recharge count: %v", err) - } - - var TotalRechargeUser int - // 充值总人数统计 - err = LogDb.Get(&TotalRechargeUser, "select count(distinct Uid) as sum from log_order") - if err != nil { - return nil, fmt.Errorf("failed to get total recharge count: %v", err) - } - - type RemainCount struct { - Register int `db:"register"` - SecondRemain int `db:"SecondRemain"` - } - var rc RemainCount - err = LogDb.Get(&rc, "select sum(`Register`) as register, sum(`SecondRemain`) as SecondRemain from remain") - if err != nil { - return nil, fmt.Errorf("failed to get recharge count: %v", err) - } rechargeFloat, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", Recharge), 64) totalRechargeFloat, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", TotalRecharge), 64) @@ -123,8 +81,8 @@ func (s *Statistics) StatisticsInfo() (interface{}, error) { "recharge": rechargeFloat, "totalRecharge": totalRechargeFloat, "rechargeUser": RechargeUser, - "totalRechargeUser": TotalRechargeUser, - "remain": util.FloatDecimals(100*float64(rc.SecondRemain)/float64(rc.Register), 2), + "totalRechargeUser": 0, + "remain": 0, }, nil } diff --git a/model/mail.go b/model/mail.go index 73eee8d..1e793ad 100644 --- a/model/mail.go +++ b/model/mail.go @@ -27,7 +27,7 @@ type Mail struct { ContentPtBr string `json:"content_ptbr" db:"content_ptbr"` TitleEsLatam string `json:"title_es_latam" db:"title_es_latam"` - SubTitleEsLatam string `json:"subtitle_es_latam" db:"subTitle_es_latam"` + SubTitleEsLatam string `json:"subtitle_es_latam" db:"subtitle_es_latam"` ContentEsLatam string `json:"content_es_latam" db:"content_es_latam"` StartTime int64 `json:"start_time" db:"start_time"` @@ -53,6 +53,9 @@ func (m *Mail) MailList() (*Result, error) { return nil, err } Db := util.MPool.GetMysqlDB(AppCfg, m.ServerId) + if Db == nil { + return nil, fmt.Errorf("failed to get mysql db") + } defer Db.Close() var mail []*Mail err = Db.Select(&mail, "SELECT `mail_id`, `title`, `content`, `start_time`, `end_time`, `items`, `register_time`, `mail_type`,`send_type`, `to_uids`, `create_time`, `subTitle`, `subTitle_en`, `content_en`, `title_en`, `title_ptbr`,`subTitle_ptbr`, `content_ptbr`, `title_es_latam`, `subtitle_es_latam`, `content_es_latam` FROM system_mail_info") @@ -80,14 +83,17 @@ func (m *Mail) SendMail() error { return err } Db := util.MPool.GetMysqlDB(AppCfg, m.ServerId) + if Db == nil { + 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`) 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) + _, 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) if err != nil { return fmt.Errorf("failed to insert mail: %v", err) } ServerList := util.GetServerInfo(m.AppId, 0) for _, server := range ServerList { - go func() { + go func(serverInfo util.ServerConfig) { ws, err := util.GetWebsocket(m.AppId, server.ServerId) if err != nil { log.Printf("failed to get websocket: %v", err) @@ -99,7 +105,8 @@ func (m *Mail) SendMail() error { if err != nil { log.Printf("failed to send admin message: %v", err) } - }() + log.Printf("sent reload mail message to server %d", server.ServerId) + }(server) } return nil @@ -111,6 +118,9 @@ func (m *Mail) DeleteMail() error { return err } Db := util.MPool.GetMysqlDB(AppCfg, m.ServerId) + if Db == nil { + return fmt.Errorf("failed to get mysql db") + } defer Db.Close() _, err = Db.Exec("DELETE FROM system_mail_info WHERE `mail_id` = ?", m.MailId) if err != nil { diff --git a/model/server.go b/model/server.go index 5cfc61b..814d760 100644 --- a/model/server.go +++ b/model/server.go @@ -48,7 +48,7 @@ func (s *Server) ServerList() ([]*Type.ServerInfo, error) { Db := util.MPool.GetGameDB() var server []*Type.ServerInfo defer Db.Close() - err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Online`, `cpu`, `free_mem`, `version`, `node_tags` FROM server where AppId = ? order by `ServerId`", s.AppId) + err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Online`, `cpu`, `free_mem`, `version`, `node_tags`, `latency` FROM server where AppId = ? order by `ServerId`", s.AppId) if err != nil { return nil, fmt.Errorf("failed to scan rows: %v", err) } diff --git a/monitor/Monitor.go b/monitor/Monitor.go index eb8793f..caff619 100644 --- a/monitor/Monitor.go +++ b/monitor/Monitor.go @@ -6,6 +6,7 @@ import ( "backend/model" "backend/util" "fmt" + "net" "time" ) @@ -66,7 +67,7 @@ func monitorServerInfo() { Db := util.MPool.GetGameDB() var server []*Type.ServerInfo defer Db.Close() - err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime` FROM server ") + err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Host`, `Port` FROM server ") if err != nil { return } @@ -77,9 +78,21 @@ func monitorServerInfo() { go func(v *Type.ServerInfo) { tmpDb := util.MPool.GetGameDB() defer tmpDb.Close() + // TCP ping test for server connectivity + address := fmt.Sprintf("%s:%d", v.Host, v.Port) // adjust port as needed + timeout := 3 * time.Second + start := time.Now() + conn, err := net.DialTimeout("tcp", address, timeout) + latency := time.Since(start).Milliseconds() + if err != nil { + // Connection failed, mark server as offline + tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId) + return + } + conn.Close() res, err := model.GetServerInfo(v.AppId, v.ServerId) if err != nil { - tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId) + //tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId) return } serverInfo := res.(map[string]interface{}) @@ -119,7 +132,7 @@ func monitorServerInfo() { // optionally store/update weight serverInfo["Weight"] = weight // Process serverInfo as needed - tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=? where AppId=? and ServerId=?", util.Int(serverInfo["PlayerNum"]), usage_mem, cpu, weight, v.AppId, v.ServerId) + tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=?,latency=? where AppId=? and ServerId=?", util.Int(serverInfo["PlayerNum"]), usage_mem, cpu, weight, latency, v.AppId, v.ServerId) }(v) } } diff --git a/sdk/ship/main.go b/sdk/ship/main.go index 20a3c8d..7b6aa1e 100644 --- a/sdk/ship/main.go +++ b/sdk/ship/main.go @@ -72,7 +72,6 @@ func main() { // 充值发货 ChargeApi.POST("test/charge", test.Charge) ChargeApi.POST("tuyou/charge", tuyou.Charge) - ChargeApi.GET("tuyou/charge", tuyou.Charge) } log.Printf("Ship SDK started on port %d", shipcommon.AppConf.Port) r.Run(fmt.Sprintf(":%d", shipcommon.AppConf.Port)) diff --git a/sdk/ship/model/base/base.go b/sdk/ship/model/base/base.go index f2f7864..16aacfc 100644 --- a/sdk/ship/model/base/base.go +++ b/sdk/ship/model/base/base.go @@ -37,15 +37,6 @@ func (p *Param) ChangeOrderStatus(Platform string, prodprice string) error { return err } if fmt.Sprintf("%.2f", price) != prodprice { - // str := ` - // # 订单金额不匹配报警 - // - 项目名称: %s - // - 订单ID: %s - // - 数据库金额: %.2f - // - 回调金额: %s - // - 渠道订单ID: %s - // - 充值ID: %d - // ` return fmt.Errorf("订单金额不匹配,数据库金额:%.2f,回调金额:%s; 订单id:%s, chargeid:%d", price, prodprice, p.OrderId, chargeId) } if paystatus != 0 { diff --git a/unit/config_test.go b/unit/config_test.go new file mode 100644 index 0000000..10c47df --- /dev/null +++ b/unit/config_test.go @@ -0,0 +1,17 @@ +package unit + +import ( + "backend/util" + "fmt" + "testing" +) + +func TestEmojiUrl(t *testing.T) { + url := util.GetEmojiURL(1) + fmt.Println("emoji url:", url) +} + +func TestFaceUrl(t *testing.T) { + url := util.GetFaceURL(1) + fmt.Println("face url:", url) +} diff --git a/unit_test.go b/unit_test.go index 4214e00..314c2ba 100644 --- a/unit_test.go +++ b/unit_test.go @@ -234,3 +234,41 @@ func TestEs2(t *testing.T) { fmt.Println("服务器启动成功") } } + +func TestIP(t *testing.T) { + country, city, err := util.GetGeoInfo("58.23.48.244") + if err != nil { + fmt.Println("获取地理位置信息失败:", err) + } else { + fmt.Printf("国家代码: %s, 城市: %s\n", country, city) + } +} + +func TestRegister(t *testing.T) { + ctx := context.Background() + client, _ := util.GetEsClient() + var buf bytes.Buffer + query := map[string]interface{}{ + "query": map[string]interface{}{ + "term": map[string]interface{}{ + "game.#event_name": map[string]interface{}{ + "value": "register", + }, + }, + }, + "size": 10000, + } + if err := json.NewEncoder(&buf).Encode(query); err != nil { + return + } + res, err := client.Search( + client.Search.WithContext(ctx), + client.Search.WithIndex(".ds-game-node-log*"), + client.Search.WithBody(&buf), + client.Search.WithTrackTotalHits(true), + ) + if err != nil { + fmt.Print(err) + } + defer res.Body.Close() +} diff --git a/util/es.go b/util/es.go index 9f2acea..db8b9d7 100644 --- a/util/es.go +++ b/util/es.go @@ -66,7 +66,7 @@ func DSlSearch(ctx context.Context, index string, query map[string]interface{}, if err := json.NewEncoder(&buf).Encode(fullQuery); err != nil { return nil, fmt.Errorf("编码查询失败: %w", err) } - + fmt.Printf("%s", buf.String()) res, err := client.Search( client.Search.WithContext(ctx), client.Search.WithIndex(index), @@ -123,12 +123,12 @@ func SearchAssetByUid(app, _uid int, from, size int, start, end int64, itemid in mustCondition := []map[string]interface{}{ { "term": map[string]interface{}{ - "game.#distinct_id": uid, + "game.#distinct_id.keyword": uid, }, }, { "term": map[string]interface{}{ - "fields.region": region, + "fields.environment": region, }, }, { @@ -218,12 +218,12 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam mustConditions := []map[string]interface{}{ { "term": map[string]interface{}{ - "game.#distinct_id": uid, + "game.#distinct_id.keyword": uid, }, }, { "term": map[string]interface{}{ - "fields.region": region, + "fields.environment": region, }, }, { @@ -265,7 +265,6 @@ func SearchEventByUid(app, _uid int, from, size int, start, end int64, event_nam }, }, } - result, err := DSlSearch(ctx, "game-user-log*", query, from, size, sort) if err != nil { return nil, 0, err @@ -328,7 +327,7 @@ func CountDistinctUidLastHour() (int64, int64, error) { "must": []map[string]interface{}{ { "term": map[string]interface{}{ - "fields.region": "us-newyork", + "fields.region.keyword": "us-newyork", }, }, }, @@ -367,7 +366,7 @@ func CountDistinctUidLastHour() (int64, int64, error) { "aggs": map[string]interface{}{ "unique_users": map[string]interface{}{ "cardinality": map[string]interface{}{ - "field": "game.#distinct_id", + "field": "game.#distinct_id.keyword", }, }, }, @@ -384,7 +383,7 @@ func CountDistinctUidLastHour() (int64, int64, error) { "aggs": map[string]interface{}{ "unique_users": map[string]interface{}{ "cardinality": map[string]interface{}{ - "field": "game.#distinct_id", + "field": "game.#distinct_id.keyword", }, }, }, @@ -396,9 +395,11 @@ func CountDistinctUidLastHour() (int64, int64, error) { if err := json.NewEncoder(&buf).Encode(query); err != nil { return 0, 0, fmt.Errorf("编码查询失败: %w", err) } + fmt.Printf("%s", buf.String()) res, err := client.Search( client.Search.WithContext(ctx), client.Search.WithIndex("game-user-log*"), + client.Search.WithTrackTotalHits(true), client.Search.WithBody(&buf), ) if err != nil { diff --git a/util/geoip.go b/util/geoip.go new file mode 100644 index 0000000..31be96b --- /dev/null +++ b/util/geoip.go @@ -0,0 +1,23 @@ +package util + +import ( + "net" + + "github.com/oschwald/geoip2-golang" +) + +func GetGeoInfo(ip string) (string, string, error) { + // 这里可以使用第三方库或服务来获取地理位置信息 + // 例如,使用 "github.com/oschwald/geoip2-golang" 库读取 MaxMind 的 GeoIP 数据库 + // 或者调用第三方 API,如 ipinfo.io、ipstack.com 等 + db, err := geoip2.Open("./GeoLite2-Country/GeoLite2-City.mmdb") + if err != nil { + return "", "", err + } + defer db.Close() + city, err := db.City(net.ParseIP(ip)) + if err != nil { + return "", "", err + } + return city.Country.Names["zh-CN"], city.City.Names["zh-CN"], nil // 返回国家代码或地理位置信息 +} diff --git a/util/login.go b/util/login.go index 176620f..7807f87 100644 --- a/util/login.go +++ b/util/login.go @@ -2,7 +2,6 @@ package util import ( "fmt" - "log" "math/rand" "sync" "time" @@ -35,7 +34,7 @@ func LoginResponse(c *gin.Context, AppId, AreaCode int, Version string) { } func GetUserInfo(AppId, AreaCode int, Uid, Version string) (int, string, int) { - now := time.Now().UnixMilli() + // now := time.Now().UnixMilli() lockUid(Uid) defer unlockUid(Uid) // Db := MPool.GetGameDB() @@ -48,14 +47,6 @@ func GetUserInfo(AppId, AreaCode int, Uid, Version string) (int, string, int) { if len(ServerList) == 0 || Uid == "" || Version == "" { return 0, "", 0 } - // appConf, _ := GetAppConfig(AppId) - // PlayerDb := MPool.GetMysqlDB(appConf, 1) - // defer PlayerDb.Close() - // var node int - // err := PlayerDb.QueryRow("SELECT node FROM t_player_baseinfo WHERE user_name = ?", Uid).Scan(&node) - // if err != nil { - // fmt.Printf("GetUserInfo query node error: %v\n", err) - // } node, err := GetUserConnectNode(Uid) if err != nil { node = 0 @@ -126,7 +117,7 @@ func GetUserInfo(AppId, AreaCode int, Uid, Version string) (int, string, int) { if err == nil { SaveUserConnectNode(Uid, ServerId) } - log.Printf("GetUserInfo selected server %d for uid %s, cost time %dms\n", ServerId, Uid, time.Now().UnixMilli()-now) + //log.Printf("GetUserInfo selected server %d for uid %s, cost time %dms\n", ServerId, Uid, time.Now().UnixMilli()-now) return Port, Host, ServerId } diff --git a/util/util.go b/util/util.go index 19194f4..8971adc 100644 --- a/util/util.go +++ b/util/util.go @@ -34,6 +34,7 @@ var FrameData = make(map[string]interface{}) var CardData = make(map[string]interface{}) var CardCollectData = make(map[string]interface{}) var NetAssetData = make(map[string]interface{}) +var ItemData = make(map[string]interface{}) func init() { data, err := os.ReadFile("config/MergeData.json") @@ -91,6 +92,15 @@ func init() { NetAssetData = m } } + data, err = os.ReadFile("config/Item.json") + if err == nil { + var m map[string]interface{} + if err := json.Unmarshal(data, &m); err != nil { + log.Printf("failed to unmarshal ItemData.json: %v", err) + } else { + ItemData = m + } + } } // 获取结构体名称 @@ -605,35 +615,19 @@ func GetLanguageImageURL(key string) string { // 头像 reHead := regexp.MustCompile(`^Data_HeadName_(\d+)$`) if m := reHead.FindStringSubmatch(key); len(m) == 2 { - if n, err := strconv.Atoi(m[1]); err == nil { - pad := fmt.Sprintf("%03d", n) - return fmt.Sprintf("UI/UISprites/Head/DefaultHead/head_pic_circle%s.png", pad) - } + id := Int(m[1]) + return GetFaceURL(id) } // 头像框 reFrame := regexp.MustCompile(`^Data_HeadFrameName_(\d+)$`) if m := reFrame.FindStringSubmatch(key); len(m) == 2 { - nameKey := m[0] - for _, v := range FrameData { - if v == nil { - continue - } - entry, ok := v.(map[string]interface{}) - if !ok { - continue - } - if String(entry["NameKey"]) == nameKey { - icon := String(entry["Icon"]) - if icon != "" { - return fmt.Sprintf("UI/UISprites/Head/Kuang_new/%s.png", icon) - } - } - } + id := Int(m[1]) + return GetFrameURL(id) } // Emoji reEmoji := regexp.MustCompile(`^Data_EmojiName_(\d+)$`) if m := reEmoji.FindStringSubmatch(key); len(m) == 2 { - return fmt.Sprintf("UI/UISprites/Head/Emoji/cat_biaoqing_%s.png", m[1]) + return GetEmojiURL(Int(m[1])) } // 卡牌 reCard := regexp.MustCompile(`^UI_MainCardPanel_cardName_`) @@ -661,7 +655,7 @@ func GetLanguageImageURL(key string) string { if reCardCollect.MatchString(key) { parts := strings.Split(key, "_") name := strings.TrimSpace(parts[len(parts)-1]) - for k, v := range CardCollectData { + for _, v := range CardCollectData { if v == nil { continue } @@ -670,10 +664,7 @@ func GetLanguageImageURL(key string) string { continue } if String(entry["Name"]) == name { - icon := "Card/Collect_icon_pethome" + k - if icon != "" { - return fmt.Sprintf("UI/UISprites/%s.png", icon) - } + return String(entry["ResourcesPath"]) } } } @@ -724,8 +715,72 @@ func GetAppName(AppId int) string { func GetAppRegion(AppId int) string { switch AppId { case 0: - return "us-newyork" + return "prod" default: - return "cn-shanghai" + return "test" } } + +func GetEmojiURL(EmojiId int) string { + return _GetURL(EmojiId, 109) +} + +func GetFaceURL(HeadId int) string { + return _GetURL(HeadId, 110) +} + +func GetFrameURL(FrameId int) string { + return _GetURL(FrameId, 105) +} + +func _GetURL(Id, Type int) string { + for _, v := range ItemData { + info, ok := v.(map[string]interface{}) + if !ok { + continue + } + if Int(info["IType"]) == Type { + effect := String(info["Effect"]) + effectList := strings.Split(effect, ",") + if Id == Int(effectList[0]) && len(effectList) > 0 { + return info["FullResourcePath"].(string) + } + } + } + return "" +} + +func GetCardURL(CardId string) string { + info, ok := CardData[CardId] + if ok && info != nil { + entry, ok := info.(map[string]interface{}) + if ok { + return String(entry["ResourcesPath"]) + } + } + return "" +} + +func GetCardCollectURL(name string) string { + for _, v := range CardCollectData { + info, ok := v.(map[string]interface{}) + if !ok { + continue + } + if String(info["Name"]) == name { + return String(info["ResourcesPath"]) + } + } + return "" +} + +func GetNetAssetURL(Key string) string { + info, ok := NetAssetData[Key] + if ok && info != nil { + entry, ok := info.(map[string]interface{}) + if ok { + return String(entry["Picture"]) + } + } + return "" +} diff --git a/util/websocket.go b/util/websocket.go index 6523583..4a3491b 100644 --- a/util/websocket.go +++ b/util/websocket.go @@ -16,13 +16,11 @@ func GetWebsocket(AppId, ServerId int) (*websocket.Conn, error) { if ServerConfig == nil { return nil, fmt.Errorf("server config not found for AppId %d and ServerId %d", AppId, ServerId) } - - // if AppId == 0 { - // ServerConfig.Host = "google.bywaystudios.com" - // } nodeConfig := GetNodeById(ServerConfig.ECS) url := fmt.Sprintf("ws://%s:%d/", nodeConfig.Host, ServerConfig.WsPort) - + // if common.GetEnv() == "dev" { + // url = "ws://127.0.0.1:3567/" // 本地调试使用内网地址 + // } dialer := &websocket.Dialer{ HandshakeTimeout: 5 * time.Second, }