版本更新

This commit is contained in:
hahwu 2026-02-25 10:16:35 +08:00
parent 1a66367ca9
commit 630c5ebd77
22 changed files with 343 additions and 127 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ log/*.log
*.log
runtime/*.db
config/*
unit/config/*

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 MiB

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}

View File

@ -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,
})

View File

@ -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)

View File

@ -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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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))

View File

@ -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 {

17
unit/config_test.go Normal file
View File

@ -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)
}

View File

@ -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()
}

View File

@ -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 {

23
util/geoip.go Normal file
View File

@ -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 // 返回国家代码或地理位置信息
}

View File

@ -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
}

View File

@ -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 ""
}

View File

@ -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,
}