版本更新

This commit is contained in:
hahwu 2026-04-14 16:17:58 +08:00
parent dbaa303418
commit 1fe14680e6
22 changed files with 5858 additions and 2657 deletions

View File

@ -197,6 +197,7 @@ type AssetData struct {
ChangeType string `json:"change_type"`
ItemId int `json:"item_id"`
Timestamp int64 `json:"timestamp"`
ItemName string `json:"item_name"`
}
type EventData struct {

View File

@ -54,7 +54,6 @@ func ActivityCfgReload(AppId, ServerId int, req *msg.ReqActivityCfgReload) error
}
defer conn.Close()
client := msg.NewBackendClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
@ -68,3 +67,34 @@ func ActivityCfgReload(AppId, ServerId int, req *msg.ReqActivityCfgReload) error
}
return nil
}
func GetUserInfo(AppId, ServerId int, req *msg.UserDetailParam) (*msg.ResUserDetailInfo, 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.UserDetail(ctx, req)
if err != nil {
return nil, fmt.Errorf("GetUserInfo failed: %v", err)
}
if resp.GetCode() != 0 {
return nil, fmt.Errorf("GetUserInfo failed with code: %d, msg: %s", resp.GetCode(), resp.GetMsg())
}
return resp.GetInfo(), nil
}

View File

@ -36,6 +36,7 @@ type SystemConfig struct {
ClientChatId string `yaml:"client_chat_id"` // 客户端群id
Ssh bool `yaml:"ssh"` // 是否开启SSH连接
Env string `yaml:"env"` // 环境变量
RpcSwitch bool `yaml:"rpc_switch"` // 是否开启RPC调用
}
type Config struct {
@ -55,6 +56,12 @@ type TranlaterConfig struct {
User []TranlaterUser `yaml:"user"`
}
type LanguageLimit struct {
Key string `json:"key"`
Zh_CN int `json:"zh_CN"`
Latin int `json:"latin"`
}
var config *Config
var tranlaterConfig *TranlaterConfig
@ -148,6 +155,10 @@ func GetEnv() string {
return config.System.Env
}
func GetRpcSwitch() bool {
return config.System.RpcSwitch
}
func GetTranlaterConfig(account string) *TranlaterUser {
for _, user := range tranlaterConfig.User {
if user.Account == account {

View File

@ -8,21 +8,27 @@ import (
func ActivityList(c *gin.Context) {
activity := model.ActivityMod{}
c.BindJSON(&activity)
ActivityList, err := activity.ActivityList()
if err := c.ShouldBindJSON(&activity); err != nil {
failed(c, err.Error())
return
}
total, ActivityList, err := activity.ActivityList()
if err != nil {
failed(c, err.Error())
return
}
res := make(map[string]interface{})
res["data"] = ActivityList
res["total"] = len(ActivityList)
res["total"] = total
success(c, res)
}
func ActivityEdit(c *gin.Context) {
var activity model.ActivityMod
c.BindJSON(&activity)
if err := c.ShouldBindJSON(&activity); err != nil {
failed(c, err.Error())
return
}
err := activity.Edit()
if err != nil {
failed(c, err.Error())
@ -35,7 +41,10 @@ func ActivityEdit(c *gin.Context) {
func ActivityAdd(c *gin.Context) {
var activity model.ActivityMod
c.BindJSON(&activity)
if err := c.ShouldBindJSON(&activity); err != nil {
failed(c, err.Error())
return
}
err := activity.Add()
if err != nil {
failed(c, err.Error())
@ -48,7 +57,10 @@ func ActivityAdd(c *gin.Context) {
func ActivityDelete(c *gin.Context) {
var activity model.ActivityMod
c.BindJSON(&activity)
if err := c.ShouldBindJSON(&activity); err != nil {
failed(c, err.Error())
return
}
err := activity.Delete()
if err != nil {
failed(c, err.Error())
@ -56,3 +68,27 @@ func ActivityDelete(c *gin.Context) {
}
success(c, nil)
}
func ActivitySync(c *gin.Context) {
type ActivitySyncReq struct {
SrcAppId int `json:"SrcAppId"`
DestAppId int `json:"DstAppId"`
}
var req ActivitySyncReq
if err := c.ShouldBindJSON(&req); err != nil {
failed(c, err.Error())
return
}
activity := model.ActivityMod{
AppId: req.SrcAppId,
PageSize: 1<<31 - 1,
}
err := activity.Sync(req.DestAppId)
if err != nil {
failed(c, err.Error())
return
}
res := make(map[string]interface{})
res["code"] = 0
success(c, res)
}

View File

@ -1,8 +1,10 @@
package controller
import (
global_config "backend/global"
"backend/model"
"backend/util"
"encoding/json"
"github.com/gin-gonic/gin"
)
@ -72,3 +74,96 @@ func AdminLogList(c *gin.Context) {
Total: total,
})
}
func AdminConfigList(c *gin.Context) {
type param struct {
Page int `json:"page"`
PaseSize int `json:"pageSize"`
}
var p param
if err := c.ShouldBindJSON(&p); err != nil {
failed(c, "Invalid input: "+err.Error())
return
}
type Config struct {
ID int `json:"id" db:"id"`
Key string `json:"key" db:"config_key"`
Value string `json:"value" db:"config_value"`
Remark string `json:"remark" db:"remark"`
}
List := []*Config{}
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
failed(c, "Failed to get database connection")
return
}
err := db.Select(&List, "SELECT `id`, `config_key`, `config_value`, `remark` FROM config ORDER BY id DESC LIMIT ? OFFSET ?", p.PaseSize, (p.Page-1)*p.PaseSize)
if err != nil {
failed(c, "Failed to retrieve admin logs: "+err.Error())
return
}
var total int
db.Get(&total, "SELECT COUNT(*) FROM config")
success(c, &model.Result{
Data: List,
Total: total,
})
}
func AdminConfigAdd(c *gin.Context) {
type param struct {
Key string `json:"key"`
Value string `json:"value"`
Remark string `json:"remark"`
}
var p param
if err := c.ShouldBindJSON(&p); err != nil {
failed(c, "Invalid input: "+err.Error())
return
}
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
failed(c, "Failed to get database connection")
return
}
_, err := db.Exec("INSERT INTO config (`config_key`, `config_value`, `remark`) VALUES (?, ?, ?)", p.Key, p.Value, p.Remark)
if err != nil {
failed(c, "Failed to add config: "+err.Error())
return
}
var config map[string]interface{}
json.Unmarshal([]byte(p.Value), &config)
global_config.SetConfig(p.Key, config) // 更新全局配置
success(c, "Config added successfully")
}
func AdminConfigEdit(c *gin.Context) {
type param struct {
ID int `json:"id"`
Key string `json:"key"`
Value string `json:"value"`
Remark string `json:"remark"`
}
var p param
if err := c.ShouldBindJSON(&p); err != nil {
failed(c, "Invalid input: "+err.Error())
return
}
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
failed(c, "Failed to get database connection")
return
}
_, err := db.Exec("UPDATE config SET `config_key` = ?, `config_value` = ?, `remark` = ? WHERE id = ?", p.Key, p.Value, p.Remark, p.ID)
if err != nil {
failed(c, "Failed to edit config: "+err.Error())
return
}
var config map[string]interface{}
json.Unmarshal([]byte(p.Value), &config)
global_config.SetConfig(p.Key, config) // 更新全局配置
success(c, "Config updated successfully")
}

View File

@ -54,12 +54,18 @@ func CopyUserOperation(srcAppID, dstAppID, srcUid, dstUid int) error {
}
defer SrcDb.Close()
defer DstDb.Close()
srcTableName := "t_player_mod"
dstTableName := "t_player_mod"
newscrTableName := fmt.Sprintf("t_player_mod_%02d", srcUid%100)
// 复制 Mod 表
srcData := DbData{}
err = SrcDb.Get(&srcData, "SELECT dwUin, mData, updateTime FROM t_player_mod WHERE dwUin = ? LIMIT 1", srcUid)
err = SrcDb.Get(&srcData, fmt.Sprintf("SELECT dwUin, mData, updateTime FROM %s WHERE dwUin = ? LIMIT 1", newscrTableName), srcUid)
if err != nil {
err = SrcDb.Get(&srcData, fmt.Sprintf("SELECT dwUin, mData, updateTime FROM %s WHERE dwUin = ? LIMIT 1", srcTableName), srcUid)
if err != nil {
return err
}
}
type player_data struct {
DwUin int `db:"dwUin"`
Register int64 `db:"rolecreatetime"`
@ -92,7 +98,10 @@ func CopyUserOperation(srcAppID, dstAppID, srcUid, dstUid int) error {
if err != nil {
return err
}
_, err = DstDb.Exec("INSERT INTO t_player_mod (dwUin, mData, updateTime) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE mData = VALUES(mData), updateTime = VALUES(updateTime)", newUid, srcData.MData, srcData.UpdateTime)
if dstAppID == 1 {
dstTableName = fmt.Sprintf("t_player_mod_%02d", newUid%100)
}
_, err = DstDb.Exec(fmt.Sprintf("INSERT INTO %s (dwUin, mData, updateTime) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE mData = VALUES(mData), updateTime = VALUES(updateTime)", dstTableName), newUid, srcData.MData, srcData.UpdateTime)
if err != nil {
return err
}

View File

@ -2,6 +2,7 @@ package controller
import (
"backend/Type"
"backend/common"
"backend/model"
"backend/store"
"backend/util"
@ -76,6 +77,28 @@ 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{})
@ -104,9 +127,9 @@ func UserDetail(c *gin.Context) {
for k, v := range friendList {
info := v.(map[string]interface{})
face_url := util.GetFaceURL(util.Int(info["Avatar"]))
info["avatarUrl"] = face_url
info["AvatarUrl"] = face_url
friendList[k] = info
info["onlineStatus"] = util.Int(info["LoginTime"]) > util.Int(info["LogoutTime"])
info["OnlineStatus"] = util.Int(info["LoginTime"]) > util.Int(info["LogoutTime"])
}
user["FriendList"] = friendList
}

Binary file not shown.

93
global/config.go Normal file
View File

@ -0,0 +1,93 @@
package global_config
import (
"backend/common"
"backend/util"
"encoding/json"
)
var GlobalConfig map[string]interface{}
func InitConfig() {
GlobalConfig = make(map[string]interface{})
// 这里可以加载配置文件或从环境变量中读取配置
// 例如:
GlobalConfig["app_name"] = "MyApp"
GlobalConfig["debug"] = true
GlobalConfig["version"] = "1.0.0"
type Config struct {
ID int `json:"id" db:"id"`
Key string `json:"key" db:"config_key"`
Value string `json:"value" db:"config_value"`
Remark string `json:"remark" db:"remark"`
}
List := []*Config{}
db := util.MPool.GetGameDB()
defer db.Close()
if db == nil {
return
}
err := db.Select(&List, "SELECT `id`, `config_key`, `config_value`, `remark` FROM config")
if err != nil {
return
}
for _, config := range List {
configMap := make(map[string]interface{})
json.Unmarshal([]byte(config.Value), &configMap)
GlobalConfig[config.Key] = configMap
}
}
func GetConfig(key string) interface{} {
if value, ok := GlobalConfig[key]; ok {
return value
}
return nil
}
func SetConfig(key string, value interface{}) {
if GlobalConfig == nil {
GlobalConfig = make(map[string]interface{})
}
GlobalConfig[key] = value
}
func GetTranlaterConfig(user string) *common.TranlaterUser {
config := GetConfig("translater.config")
if config == nil {
return nil
}
configMap := config.(map[string]interface{})
userList := configMap["user"].([]interface{})
for _, item := range userList {
itemMap := item.(map[string]interface{})
if itemMap["account"] == user {
return &common.TranlaterUser{
Account: itemMap["account"].(string),
Colunm: itemMap["column"].(string),
Keys: itemMap["keys"].(string),
KeysType: itemMap["keysType"].(string),
}
}
}
return nil
}
func GetLanguageLimitConfig() []*common.LanguageLimit {
config := GetConfig("language.len_limit")
if config == nil {
return nil
}
list := config.(map[string]interface{})["list"].([]interface{})
result := make([]*common.LanguageLimit, 0)
for _, item := range list {
itemMap := item.(map[string]interface{})
result = append(result, &common.LanguageLimit{
Key: itemMap["key"].(string),
Zh_CN: int(itemMap["zh_CN"].(float64)),
Latin: int(itemMap["latin"].(float64)),
})
}
return result
}

View File

@ -4,6 +4,7 @@ import (
"backend/common"
"backend/controller"
"backend/feishu/server"
config "backend/global"
"backend/middleware"
"backend/model"
"backend/monitor"
@ -111,6 +112,9 @@ func main() {
api.POST("/admin/list", controller.AdminList)
api.POST("/admin/add", controller.AdminAdd)
api.POST("/admin/log/list", controller.AdminLogList)
api.POST("/admin/config/list", controller.AdminConfigList)
api.POST("/admin/config/add", controller.AdminConfigAdd)
api.POST("/admin/config/edit", controller.AdminConfigEdit)
// 玩家日志
api.POST("/log/user", controller.UserDetail)
api.POST("/log/asset", controller.Asset)
@ -146,6 +150,7 @@ func main() {
api.POST("/activity/edit", controller.ActivityEdit)
api.POST("/activity/add", controller.ActivityAdd)
api.POST("/activity/delete", controller.ActivityDelete)
api.POST("/activity/sync", controller.ActivitySync)
// 邮件
api.POST("/mail/send", controller.SendMail)
@ -168,6 +173,7 @@ func main() {
scripts.POST("/copywriting", controller.Copywriting) // 下载文案文件
scripts.POST("/copyonline", controller.CopyOnline) // 复制线上环境到QA
}
config.InitConfig()
//go util.ScheduleDailyTask()
go server.Server()
go model.InitToken() // 初始化 Token 列表

View File

@ -1,6 +1,7 @@
package model
import (
"backend/client"
"backend/msg"
util "backend/util"
"fmt"
@ -53,17 +54,28 @@ func GetUserList(AppId, ServerId, PageSize, CurrentPage, Uid, StartTime, EndTime
return users, total, nil
}
func UserDetail(AppId, Uid, Node int) (map[string]interface{}, error) {
req := &msg.ReqAdminInfo{
Uid: int64(Uid),
func UserDetail2(appId, uid, node int) (*msg.ResUserDetailInfo, error) {
r, err := client.GetUserInfo(appId, node, &msg.UserDetailParam{
Uid: int64(uid),
})
if err != nil {
return nil, fmt.Errorf("failed to send admin message: %v", err)
}
ws, err := util.GetWebsocket(AppId, Node)
return r, nil
}
func UserDetail(appId, uid, node int) (map[string]interface{}, error) {
req := &msg.ReqAdminInfo{
Uid: int64(uid),
}
ws, err := util.GetWebsocket(appId, node)
if err != nil {
return nil, fmt.Errorf("failed to get websocket: %v", err)
}
defer ws.Close()
r, err := util.SendAdminMsg(ws, req)
if err != nil {
return nil, fmt.Errorf("failed to send admin message: %v", err)
}
@ -96,7 +108,6 @@ func UserGM(AppId, ServerId, Uid int, Command string) (interface{}, error) {
func UserBan(AppId, ServerId, Uid int, Day int, Reason string) (interface{}, error) {
Now := util.Now()
req := &msg.ReqAdminBan{
Uid: int64(Uid),
Time: Now + int64(Day*24*3600),

View File

@ -2,19 +2,17 @@ package model
import (
"backend/client"
"backend/msg"
"backend/util"
"fmt"
"log"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
type ActivityMod struct {
AppId int `json:"AppId" db:"AppId"`
ActivityType int `json:"activityType" db:"activityType"`
Cfg *Activity `json:"Cfg" db:"-"`
Page int `json:"CurrentPage" db:"-"`
PageSize int `json:"PageSize" db:"-"`
}
type Activity struct {
@ -29,29 +27,35 @@ type Activity struct {
Cfg string `json:"cfg" db:"cfg"`
CfgBuf []byte `json:"-" db:"cfg_buf"`
Extra string `json:"extra" db:"extra"`
Interval int `json:"interval" db:"interval"`
}
func (a *ActivityMod) ActivityList() ([]Activity, error) {
func (a *ActivityMod) ActivityList() (int, []Activity, error) {
var activityList []Activity
// do something
AppCfg, err := util.GetAppConfig(a.AppId)
if err != nil {
return nil, err
return 0, nil, err
}
Db := util.MPool.GetMysqlDB(AppCfg, 1)
if Db == nil {
return nil, fmt.Errorf("failed to get mysql db")
return 0, nil, fmt.Errorf("failed to get mysql db")
}
defer Db.Close()
where := ""
if a.ActivityType != 0 {
where = fmt.Sprintf("WHERE `type`=%d", a.ActivityType)
}
err = Db.Select(&activityList, fmt.Sprintf("SELECT id, `type`, start_time, end_time, level_limit, title, mail_title, mail_content, cfg, extra FROM t_activity_mod %s order by id desc", where))
var total int
err = Db.Get(&total, fmt.Sprintf("SELECT COUNT(*) FROM t_activity_mod %s", where))
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %v", err)
return 0, nil, fmt.Errorf("failed to get total count: %v", err)
}
return activityList, nil
err = Db.Select(&activityList, fmt.Sprintf("SELECT id, `type`, `start_time`, `end_time`, `level_limit`, `title`, `mail_title`, `mail_content`, `cfg`, `extra`, `interval` FROM t_activity_mod %s order by id desc limit %d, %d", where, (a.Page-1)*a.PageSize, a.PageSize))
if err != nil {
return 0, nil, fmt.Errorf("failed to scan rows: %v", err)
}
return total, activityList, nil
}
func (a *ActivityMod) Edit() error {
@ -68,8 +72,8 @@ func (a *ActivityMod) Edit() error {
return fmt.Errorf("failed to get mysql db")
}
defer Db.Close()
_, err = Db.Exec("UPDATE t_activity_mod SET type=?, start_time=?, end_time=?, level_limit=?, title=?, mail_title=?, mail_content=?, cfg=?, cfg_buf=?, extra=? WHERE id=?",
a.Cfg.Type, a.Cfg.StartTime, a.Cfg.EndTime, a.Cfg.Level, a.Cfg.Title, a.Cfg.MailTitle, a.Cfg.MailContent, a.Cfg.Cfg, a.Cfg.CfgBuf, a.Cfg.Extra, a.Cfg.Id)
_, err = Db.Exec("UPDATE t_activity_mod SET type=?, start_time=?, end_time=?, level_limit=?, title=?, mail_title=?, mail_content=?, cfg=?, cfg_buf=?, extra=?, `interval`=? WHERE id=?",
a.Cfg.Type, a.Cfg.StartTime, a.Cfg.EndTime, a.Cfg.Level, a.Cfg.Title, a.Cfg.MailTitle, a.Cfg.MailContent, a.Cfg.Cfg, a.Cfg.CfgBuf, a.Cfg.Extra, a.Cfg.Interval, a.Cfg.Id)
if err != nil {
return fmt.Errorf("failed to update activity: %v", err)
}
@ -95,8 +99,8 @@ func (a *ActivityMod) Add() error {
return fmt.Errorf("failed to get mysql db")
}
defer Db.Close()
_, err = Db.Exec("INSERT INTO t_activity_mod (type, start_time, end_time, level_limit, title, mail_title, mail_content, cfg, cfg_buf, extra) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
a.Cfg.Type, a.Cfg.StartTime, a.Cfg.EndTime, a.Cfg.Level, a.Cfg.Title, a.Cfg.MailTitle, a.Cfg.MailContent, a.Cfg.Cfg, a.Cfg.CfgBuf, a.Cfg.Extra)
_, err = Db.Exec("INSERT INTO t_activity_mod (type, start_time, end_time, level_limit, title, mail_title, mail_content, cfg, cfg_buf, extra, `interval`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
a.Cfg.Type, a.Cfg.StartTime, a.Cfg.EndTime, a.Cfg.Level, a.Cfg.Title, a.Cfg.MailTitle, a.Cfg.MailContent, a.Cfg.Cfg, a.Cfg.CfgBuf, a.Cfg.Extra, a.Cfg.Interval)
if err != nil {
return fmt.Errorf("failed to insert activity: %v", err)
}
@ -131,22 +135,6 @@ func (a *ActivityMod) Delete() error {
}
func (a *Activity) Mashal() error {
switch a.Type {
case 1:
m := &msg.MiningCfg{}
err := protojson.Unmarshal([]byte(a.Cfg), m)
if err != nil {
return fmt.Errorf("failed to unmarshal proto message: %v", err)
}
binaryData, err := proto.Marshal(m)
if err != nil {
return fmt.Errorf("failed to marshal proto message: %v", err)
}
a.CfgBuf = binaryData
return nil
default:
//return fmt.Errorf("unknown activity type: %d", a.Type)
}
return nil
}
@ -156,10 +144,35 @@ func (a *ActivityMod) reloadCfg() error {
go func(serverInfo util.ServerConfig) {
err := client.ActivityCfgReload(serverInfo.AppId, serverInfo.ServerId, nil)
if err != nil {
log.Printf("failed to send admin message: %v", err)
log.Printf("failed to sync activity cfg: %v", err)
}
log.Printf("sent reload mail message to server %d", server.ServerId)
log.Printf("sent reload activity cfg message to server %d", server.ServerId)
}(server)
}
return nil
}
func (a *ActivityMod) Sync(dest int) error {
_, list, err := a.ActivityList()
if err != nil {
return err
}
AppCfg, err := util.GetAppConfig(dest)
if err != nil {
return err
}
Db := util.MPool.GetMysqlDB(AppCfg, 1)
if Db == nil {
return fmt.Errorf("failed to get mysql db")
}
defer Db.Close()
for _, activity := range list {
_, err = Db.Exec("INSERT INTO t_activity_mod (id, type, start_time, end_time, level_limit, title, mail_title, mail_content, cfg, cfg_buf, extra, `interval`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE type=?, start_time=?, end_time=?, level_limit=?, title=?, mail_title=?, mail_content=?, cfg=?, cfg_buf=?, extra=?, `interval`=?",
activity.Id, activity.Type, activity.StartTime, activity.EndTime, activity.Level, activity.Title, activity.MailTitle, activity.MailContent, activity.Cfg, activity.CfgBuf, activity.Extra, activity.Interval,
activity.Type, activity.StartTime, activity.EndTime, activity.Level, activity.Title, activity.MailTitle, activity.MailContent, activity.Cfg, activity.CfgBuf, activity.Extra, activity.Interval)
if err != nil {
return fmt.Errorf("failed to sync activity: %v", err)
}
}
return nil
}

View File

@ -1,7 +1,7 @@
package model
import (
"backend/common"
global_config "backend/global"
"backend/util"
"fmt"
"os"
@ -15,19 +15,23 @@ import (
)
var lenCfg_zh_cn = map[string]int{
`^UI_MergeData_(\d+)$`: 10,
`^UI_MergeData_(\d+)$`: 20,
`UI_MainLevelPanel_title`: 16,
}
var lenCfg_en_us = map[string]int{
`^UI_MergeData_(\d+)$`: 16,
`^UI_MergeData_(\d+)$`: 20,
`UI_MainLevelPanel_title`: 16,
}
var lenCfg_pt_br = map[string]int{
`^UI_MergeData_(\d+)$`: 16,
`^UI_MergeData_(\d+)$`: 20,
`UI_MainLevelPanel_title`: 16,
}
var lenCfg_es_latam = map[string]int{
`^UI_MergeData_(\d+)$`: 16,
`^UI_MergeData_(\d+)$`: 20,
`UI_MainLevelPanel_title`: 16,
}
type Language struct {
@ -38,6 +42,7 @@ type Language struct {
PT_BR string `json:"pt_BR" db:"pt_BR"`
ES_LATAM string `json:"es_LATAM" db:"es_LATAM"`
Url string `json:"url"`
LenLimit int `json:"len_limit"`
}
type LanguageOp struct {
@ -75,7 +80,8 @@ func (l *LanguageMod) LanguageList(account string) (map[string]interface{}, erro
}
}
AccountConfig := common.GetTranlaterConfig(account)
AccountConfig := global_config.GetTranlaterConfig(account)
LanguageLimitConfig := global_config.GetLanguageLimitConfig()
if AccountConfig != nil {
column = AccountConfig.Colunm
keysArr := strings.Split(AccountConfig.Keys, ",")
@ -122,23 +128,12 @@ func (l *LanguageMod) LanguageList(account string) (map[string]interface{}, erro
languages[i].Url = url
}
newlanguages := make([]*Language, 0)
var len_limit_cfg map[string]int
switch l.LenLimit {
case "zh_CN":
len_limit_cfg = lenCfg_zh_cn
case "en_US":
len_limit_cfg = lenCfg_en_us
case "pt_BR":
len_limit_cfg = lenCfg_pt_br
case "es_LATAM":
len_limit_cfg = lenCfg_es_latam
}
if l.LenLimit != "" {
for _, i := range languages {
for pattern, maxLen := range len_limit_cfg {
re := regexp.MustCompile(pattern)
for _, info := range LanguageLimitConfig {
re := regexp.MustCompile(info.Key)
m := re.FindStringSubmatch(i.Key)
if len(m) == 2 {
if len(m) >= 1 {
var zhlen int
switch l.LenLimit {
case "zh_CN":
@ -150,13 +145,16 @@ func (l *LanguageMod) LanguageList(account string) (map[string]interface{}, erro
case "es_LATAM":
zhlen = util.CountDisplayLen(i.ES_LATAM)
}
if zhlen > maxLen {
if l.LenLimit == "zh_CN" && zhlen > info.Zh_CN {
newlanguages = append(newlanguages, i)
} else if l.LenLimit != "zh_CN" && zhlen > info.Latin {
newlanguages = append(newlanguages, i)
}
}
}
}
}
if l.LenLimit != "" {
languages = newlanguages
}
@ -165,6 +163,7 @@ func (l *LanguageMod) LanguageList(account string) (map[string]interface{}, erro
"op": languageOp,
"total": total,
"column": column,
"language_len_limit": LanguageLimitConfig,
}, nil
}

View File

@ -88,6 +88,8 @@ func (m *Log) Asset() (*ResAsset, error) {
} else {
NSum += asset.ChangeNum
}
asset.ItemName = util.GetItemName(asset.ItemId)
}
return &ResAsset{
Total: int(total),

File diff suppressed because it is too large Load Diff

197
msg/Gameapi_grpc.pb.go Normal file
View File

@ -0,0 +1,197 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.1
// - protoc v5.28.2
// source: proto/Gameapi.proto
package msg
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Backend_ReloadActivity_FullMethodName = "/tutorial.Backend/ReloadActivity"
Backend_OrderShipping_FullMethodName = "/tutorial.Backend/OrderShipping"
Backend_UserDetail_FullMethodName = "/tutorial.Backend/UserDetail"
)
// BackendClient is the client API for Backend service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
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)
}
type backendClient struct {
cc grpc.ClientConnInterface
}
func NewBackendClient(cc grpc.ClientConnInterface) BackendClient {
return &backendClient{cc}
}
func (c *backendClient) ReloadActivity(ctx context.Context, in *ReqActivityCfgReload, opts ...grpc.CallOption) (*ResActivityCfgReload, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ResActivityCfgReload)
err := c.cc.Invoke(ctx, Backend_ReloadActivity_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *backendClient) OrderShipping(ctx context.Context, in *ReqOrderShipping, opts ...grpc.CallOption) (*ResOrderShipping, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ResOrderShipping)
err := c.cc.Invoke(ctx, Backend_OrderShipping_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *backendClient) UserDetail(ctx context.Context, in *UserDetailParam, opts ...grpc.CallOption) (*ResUserDetail, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ResUserDetail)
err := c.cc.Invoke(ctx, Backend_UserDetail_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.
type BackendServer interface {
ReloadActivity(context.Context, *ReqActivityCfgReload) (*ResActivityCfgReload, error)
OrderShipping(context.Context, *ReqOrderShipping) (*ResOrderShipping, error)
UserDetail(context.Context, *UserDetailParam) (*ResUserDetail, error)
mustEmbedUnimplementedBackendServer()
}
// UnimplementedBackendServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedBackendServer struct{}
func (UnimplementedBackendServer) ReloadActivity(context.Context, *ReqActivityCfgReload) (*ResActivityCfgReload, error) {
return nil, status.Error(codes.Unimplemented, "method ReloadActivity not implemented")
}
func (UnimplementedBackendServer) OrderShipping(context.Context, *ReqOrderShipping) (*ResOrderShipping, error) {
return nil, status.Error(codes.Unimplemented, "method OrderShipping not implemented")
}
func (UnimplementedBackendServer) UserDetail(context.Context, *UserDetailParam) (*ResUserDetail, error) {
return nil, status.Error(codes.Unimplemented, "method UserDetail not implemented")
}
func (UnimplementedBackendServer) mustEmbedUnimplementedBackendServer() {}
func (UnimplementedBackendServer) testEmbeddedByValue() {}
// UnsafeBackendServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to BackendServer will
// result in compilation errors.
type UnsafeBackendServer interface {
mustEmbedUnimplementedBackendServer()
}
func RegisterBackendServer(s grpc.ServiceRegistrar, srv BackendServer) {
// If the following call panics, it indicates UnimplementedBackendServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Backend_ServiceDesc, srv)
}
func _Backend_ReloadActivity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReqActivityCfgReload)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendServer).ReloadActivity(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Backend_ReloadActivity_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendServer).ReloadActivity(ctx, req.(*ReqActivityCfgReload))
}
return interceptor(ctx, in, info, handler)
}
func _Backend_OrderShipping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReqOrderShipping)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendServer).OrderShipping(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Backend_OrderShipping_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendServer).OrderShipping(ctx, req.(*ReqOrderShipping))
}
return interceptor(ctx, in, info, handler)
}
func _Backend_UserDetail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UserDetailParam)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BackendServer).UserDetail(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Backend_UserDetail_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BackendServer).UserDetail(ctx, req.(*UserDetailParam))
}
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)
var Backend_ServiceDesc = grpc.ServiceDesc{
ServiceName: "tutorial.Backend",
HandlerType: (*BackendServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ReloadActivity",
Handler: _Backend_ReloadActivity_Handler,
},
{
MethodName: "OrderShipping",
Handler: _Backend_OrderShipping_Handler,
},
{
MethodName: "UserDetail",
Handler: _Backend_UserDetail_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "proto/Gameapi.proto",
}

View File

@ -1,59 +0,0 @@
package main
import (
"backend/msg"
"backend/util"
"fmt"
"net/http"
"os"
"strconv"
"time"
"github.com/gorilla/websocket"
)
func main() {
// 获取命令行参数
args := os.Args
Status := 0
if len(args) < 2 {
fmt.Print(Status)
return
}
Host := args[1]
Port, err := strconv.Atoi(args[2])
if err != nil {
fmt.Print(Status)
return
}
ws, err := getwebsocket(Host, Port)
if err != nil {
fmt.Print(Status)
return
}
ws.SetReadDeadline(time.Now().Add(2 * time.Second))
req := &msg.ReqServerInfo{}
_, err = util.SendAdminMsg(ws, req)
if err != nil {
//log.Printf("failed to send admin message: %v", err)
fmt.Print(Status)
return
}
Status = 1
fmt.Print(Status)
}
func getwebsocket(Host string, Port int) (*websocket.Conn, error) {
url := fmt.Sprintf("ws://%s:%d/", Host, Port)
dialer := &websocket.Dialer{
HandshakeTimeout: 5 * time.Second,
}
header := http.Header{}
header.Set("Origin", "http://localhost/")
ws, _, err := dialer.Dial(url, header)
if err != nil {
return nil, fmt.Errorf("failed to connect to websocket: %v", err)
}
return ws, nil
}

Binary file not shown.

View File

@ -73,6 +73,6 @@ func main() {
ChargeApi.POST("test/charge", test.Charge)
ChargeApi.POST("tuyou/charge", tuyou.Charge)
}
log.Printf("Ship SDK started on port %d", shipcommon.AppConf.Port)
log.Printf("Ship SDK started on port %d version : 1.1.0", shipcommon.AppConf.Port)
r.Run(fmt.Sprintf(":%d", shipcommon.AppConf.Port))
}

View File

@ -122,6 +122,10 @@ func Charge(c *gin.Context) {
c.JSON(400, gin.H{"error": "invalid AppInfo"})
return
}
if AppInfo.Uid != 100001 {
log.Printf("test debug error request %v", AppInfo)
return
}
AppInfo.ChannelOrderId = req.PlatformOrder
err := AppInfo.ChangeOrderStatus("test", req.ProdPrice)
if err != nil {

View File

@ -4,26 +4,18 @@ import (
"backend/Type"
"backend/alibaba"
"backend/feishu"
"backend/gen-go/backend"
"backend/model"
"backend/msg"
"backend/sdk/ship/model/tuyou"
"backend/util"
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"regexp"
"sort"
"strings"
"testing"
"time"
"unicode"
"github.com/apache/thrift/lib/go/thrift"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func TestXxx1(t *testing.T) {
@ -282,81 +274,6 @@ func TestRegister(t *testing.T) {
defer res.Body.Close()
}
func TestThriftClient(t *testing.T) {
addr := "localhost:9090"
transport := thrift.NewTSocketConf(addr, &thrift.TConfiguration{})
transportFactory := thrift.NewTBufferedTransportFactory(8192)
protocolFactory := thrift.NewTBinaryProtocolFactoryConf(&thrift.TConfiguration{})
useTransport, err := transportFactory.GetTransport(transport)
if err != nil {
fmt.Println("Error creating transport:", err)
return
}
defer useTransport.Close()
if err := useTransport.Open(); err != nil {
fmt.Println("Error opening transport:", err)
return
}
client := backend.NewGameAdminServiceClientFactory(useTransport, protocolFactory)
//测试连接
ctx := context.Background()
res, err := client.ReqPlayerInfo(ctx, 100001)
if err != nil {
fmt.Println("Error requesting player info:", err)
return
}
fmt.Println("Player info response:", res)
}
func TestRegrex(t *testing.T) {
re := regexp.MustCompile(`^SB.*?`)
fmt.Println(re.MatchString("SB123"))
fmt.Println(re.MatchString("AB123"))
}
func TestRpcClient(t *testing.T) {
conn, err := grpc.NewClient("game-test.bywaystudios.com:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("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.ReloadActivity(ctx, &msg.ReqActivityCfgReload{})
if err != nil {
log.Fatalf("ReloadActivity failed: %v", err)
}
fmt.Printf("server replied: %s", resp.GetMsg())
}
func TestRpcClient2(t *testing.T) {
conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("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.OrderShipping(ctx, &msg.ReqOrderShipping{
OrderSn: "order_100001_20250911115944x9XzV2",
ChannelOrderSn: "e50b32601160423c7f",
})
if err != nil {
log.Fatalf("OrderShipping failed: %v", err)
}
fmt.Printf("server replied: %s", resp.GetMsg())
}
func TestMonitor(t *testing.T) {
curCount, yCount, err := util.CountDistinctUidLastHour()
if err != nil {

View File

@ -1,7 +1,6 @@
package util
import (
"backend/gen-go/backend"
"backend/msg"
"bytes"
"crypto/aes"
@ -25,7 +24,6 @@ import (
"time"
"unicode"
"github.com/apache/thrift/lib/go/thrift"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"google.golang.org/protobuf/proto"
@ -106,6 +104,17 @@ func init() {
}
}
func GetItemName(itemId int) string {
id := strconv.Itoa(itemId)
if v, ok := ItemData[id]; ok && v != nil {
entry, ok := v.(map[string]interface{})
if ok {
return String(entry["Name"])
}
}
return id
}
// 获取结构体名称
func GetStructName(v interface{}) string {
t := reflect.TypeOf(v)
@ -802,44 +811,6 @@ func GetNetAssetURL(Key string) string {
return ""
}
var RPCClient *backend.GameAdminServiceClient
func GetRPCClient(AppId, ServerId int) (*backend.GameAdminServiceClient, error) {
if RPCClient != nil {
return RPCClient, nil
}
return initRPCClient(AppId, ServerId)
}
func initRPCClient(AppId, ServerId int) (*backend.GameAdminServiceClient, error) {
ServerConfig, err := 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)
}
//nodeConfig := GetNodeById(ServerConfig.ECS)
// addr := fmt.Sprintf("%s:%d", nodeConfig.Host, 9090+ServerId)
addr := "localhost:9090"
transport := thrift.NewTSocketConf(addr, &thrift.TConfiguration{
ConnectTimeout: 5 * time.Second,
SocketTimeout: 10 * time.Second,
})
transportFactory := thrift.NewTBufferedTransportFactory(8192)
protocolFactory := thrift.NewTBinaryProtocolFactoryConf(&thrift.TConfiguration{})
useTransport, err := transportFactory.GetTransport(transport)
if err != nil {
fmt.Println("Error creating transport:", err)
return nil, fmt.Errorf("failed to create transport: %v", err)
}
if err := useTransport.Open(); err != nil {
fmt.Println("Error opening transport:", err)
return nil, fmt.Errorf("failed to open transport: %v", err)
}
client := backend.NewGameAdminServiceClientFactory(useTransport, protocolFactory)
return client, nil
}
func CountDisplayLen(s string) int {
total := 0
for _, r := range s {
@ -851,3 +822,18 @@ func CountDisplayLen(s string) int {
}
return total
}
func FormatJson(v string) string {
var data interface{}
err := json.Unmarshal([]byte(v), &data)
if err != nil {
log.Printf("failed to unmarshal JSON: %v", err)
return ""
}
jsonBytes, err := json.Marshal(data)
if err != nil {
log.Printf("failed to marshal JSON: %v", err)
return ""
}
return string(jsonBytes)
}