package api import ( "crypto/md5" "encoding/hex" "encoding/json" "fmt" "io" "mongo.games.com/game/webapi" "net/http" "sync" "sync/atomic" "time" "mongo.games.com/goserver/core" "mongo.games.com/goserver/core/admin" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/core/transact" "mongo.games.com/goserver/core/utils" "mongo.games.com/goserver/srvlib" "mongo.games.com/game/common" "mongo.games.com/game/model" "mongo.games.com/game/mq" ) // API // http://127.0.0.1:9595/api/Report/QueryOnlineReportList?ts=20141024000000&sign=41cc8cee8dd93f7dc70b6426cfd1029d const ( WEBAPI_TRANSACTE_EVENT int = iota WEBAPI_TRANSACTE_RESPONSE PLATFORMAPPKEY = "PLATFORMAPPKEYtest123" ) var WebApiStats = new(sync.Map) type ApiStats struct { RunTimes int64 //执行次数 TotalRuningTime int64 //总执行时间 MaxRuningTime int64 //最长执行时间 TimeoutTimes int64 //执行超时次数 UnreachTimes int64 //不可达次数 } func WorldSrvApi(rw http.ResponseWriter, req *http.Request) { defer utils.DumpStackIfPanic("api.WorldSrvApi") logger.Logger.Info("WorldSrvApi receive:", req.URL.Path, req.URL.RawQuery) if common.RequestCheck(req, model.GameParamData.WhiteHttpAddr) == false { logger.Logger.Info("RemoteAddr [%v] require api.", req.RemoteAddr) return } data, err := io.ReadAll(req.Body) if err != nil { logger.Logger.Info("Body err.", err) webApiResponse(rw, nil /*map[string]interface{}{webapi.RESPONSE_STATE: webapi.STATE_ERR, webapi.RESPONSE_ERRMSG: "Post data is null!"}*/) return } m := req.URL.Query() timestamp := m.Get("nano") if timestamp == "" { logger.Logger.Info(req.RemoteAddr, " WorldSrvApi param error: nano not allow null") return } sign := m.Get("sign") if sign == "" { logger.Logger.Info(req.RemoteAddr, " WorldSrvApi param error: sign not allow null") return } startTime := time.Now().UnixNano() args := fmt.Sprintf("%v;%v;%v;%v", common.Config.AppId, req.URL.Path, string(data), timestamp) h := md5.New() io.WriteString(h, args) realSign := hex.EncodeToString(h.Sum(nil)) if realSign != sign && !common.Config.IsDevMode { logger.Logger.Info(req.RemoteAddr, " srvCtrlMain sign error: expect ", realSign, " ; but get ", sign, " raw=", args) webApiResponse(rw, nil /*map[string]interface{}{webapi.RESPONSE_STATE: webapi.STATE_ERR, webapi.RESPONSE_ERRMSG: "Sign error!"}*/) return } var stats *ApiStats if v, exist := WebApiStats.Load(req.URL.Path); exist { stats = v.(*ApiStats) } else { stats = &ApiStats{} WebApiStats.Store(req.URL.Path, stats) } var rep []byte start := time.Now() res := make(chan []byte, 1) suc := core.CoreObject().SendCommand(&WebApiEvent{req: req, path: req.URL.Path, h: HandlerWrapper(func(event *WebApiEvent, data []byte) bool { logger.Logger.Trace("WorldSrvApi start transcate") tnp := &transact.TransNodeParam{ Tt: common.TransTypeWebApi, Ot: transact.TransOwnerType(common.GetSelfSrvType()), Oid: common.GetSelfSrvId(), AreaID: common.GetSelfAreaId(), } tNode := transact.DTCModule.StartTrans(tnp, event, transact.DefaultTransactTimeout) //超时时间30秒 if tNode != nil { tNode.TransEnv.SetField(WEBAPI_TRANSACTE_EVENT, event) tNode.Go(core.CoreObject()) } return true }), body: data, rawQuery: req.URL.RawQuery, res: res}, false) if suc { select { case rep = <-res: if rep != nil { webApiResponse(rw, rep) } case <-time.After(ApiDefaultTimeout): //rep = make(map[string]interface{}) //rep[webapi.RESPONSE_STATE] = webapi.STATE_ERR //rep[webapi.RESPONSE_ERRMSG] = "proccess timeout!" webApiResponse(rw, rep) if stats != nil { atomic.AddInt64(&stats.TimeoutTimes, 1) } } } else { webApiResponse(rw, nil) if stats != nil { atomic.AddInt64(&stats.UnreachTimes, 1) } } ps := int64(time.Now().Sub(start) / time.Millisecond) if stats != nil { atomic.AddInt64(&stats.RunTimes, 1) atomic.AddInt64(&stats.TotalRuningTime, ps) if atomic.LoadInt64(&stats.MaxRuningTime) < ps { atomic.StoreInt64(&stats.MaxRuningTime, ps) } } result, err := json.Marshal(rep) if err == nil { log := model.NewAPILog(req.URL.Path, req.URL.RawQuery, string(data[:]), req.RemoteAddr, string(result[:]), startTime, ps) mq.Write(log) } return } func PlatformSrvApi(rw http.ResponseWriter, req *http.Request) { defer utils.DumpStackIfPanic("api.PlatformSrvApi") logger.Logger.Info("PlatformSrvApi receive:", req.URL.Path, req.URL.RawQuery) if common.RequestCheck(req, model.GameParamData.WhiteHttpAddr) == false { logger.Logger.Info("RemoteAddr [%v] require api.", req.RemoteAddr) return } data, err := io.ReadAll(req.Body) if err != nil { logger.Logger.Info("Body err.", err) webApiResponse(rw, nil /*map[string]interface{}{webapi.RESPONSE_STATE: webapi.STATE_ERR, webapi.RESPONSE_ERRMSG: "Post data is null!"}*/) return } params := make(map[string]string) json.Unmarshal(data, ¶ms) realSign := webapi.MD5Params(params, PLATFORMAPPKEY, "sign") sign := params["sign"] if realSign != sign && !common.Config.IsDevMode { logger.Logger.Info(req.RemoteAddr, " srvCtrlMain sign error: expect ", realSign, " ; but get ", sign, " raw=", params) webApiResponse(rw, nil /*map[string]interface{}{webapi.RESPONSE_STATE: webapi.STATE_ERR, webapi.RESPONSE_ERRMSG: "Sign error!"}*/) return } startTime := time.Now().UnixNano() var stats *ApiStats if v, exist := WebApiStats.Load(req.URL.Path); exist { stats = v.(*ApiStats) } else { stats = &ApiStats{} WebApiStats.Store(req.URL.Path, stats) } var rep []byte start := time.Now() res := make(chan []byte, 1) suc := core.CoreObject().SendCommand(&WebApiEvent{req: req, path: req.URL.Path, h: HandlerWrapper(func(event *WebApiEvent, data []byte) bool { logger.Logger.Trace("WorldSrvApi start transcate") tnp := &transact.TransNodeParam{ Tt: common.TransTypeWebApi, Ot: transact.TransOwnerType(common.GetSelfSrvType()), Oid: common.GetSelfSrvId(), AreaID: common.GetSelfAreaId(), } tNode := transact.DTCModule.StartTrans(tnp, event, transact.DefaultTransactTimeout) //超时时间30秒 if tNode != nil { tNode.TransEnv.SetField(WEBAPI_TRANSACTE_EVENT, event) tNode.Go(core.CoreObject()) } return true }), body: data, rawQuery: req.URL.RawQuery, res: res}, false) if suc { select { case rep = <-res: if rep != nil { webApiResponse(rw, rep) } case <-time.After(ApiDefaultTimeout): //rep = make(map[string]interface{}) //rep[webapi.RESPONSE_STATE] = webapi.STATE_ERR //rep[webapi.RESPONSE_ERRMSG] = "proccess timeout!" webApiResponse(rw, rep) if stats != nil { atomic.AddInt64(&stats.TimeoutTimes, 1) } } } else { webApiResponse(rw, nil) if stats != nil { atomic.AddInt64(&stats.UnreachTimes, 1) } } ps := int64(time.Now().Sub(start) / time.Millisecond) if stats != nil { atomic.AddInt64(&stats.RunTimes, 1) atomic.AddInt64(&stats.TotalRuningTime, ps) if atomic.LoadInt64(&stats.MaxRuningTime) < ps { atomic.StoreInt64(&stats.MaxRuningTime, ps) } } log := model.NewAPILog(req.URL.Path, req.URL.RawQuery, string(data[:]), req.RemoteAddr, string(rep[:]), startTime, ps) mq.Write(log) return } // -------------------------------------------------------------------------------------- func init() { transact.RegisteHandler(common.TransTypeWebApi, &transact.TransHanderWrapper{ OnExecuteWrapper: transact.OnExecuteWrapper(func(tNode *transact.TransNode, ud interface{}) transact.TransExeResult { logger.Logger.Trace("WorldSrvApi start TransTypeWebApi OnExecuteWrapper ") tnp := &transact.TransNodeParam{ Tt: common.TransTypeWebApi, Ot: transact.TransOwnerType(srvlib.WorldServerType), Oid: common.GetWorldSrvId(), AreaID: common.GetSelfAreaId(), Tct: transact.TransactCommitPolicy_TwoPhase, } if event, ok := ud.(*WebApiEvent); ok { userData := &common.M2GWebApiRequest{Path: event.path, RawQuery: event.rawQuery, Body: event.body, ReqIp: event.req.RemoteAddr} tNode.StartChildTrans(tnp, userData, transact.DefaultTransactTimeout) pid := tNode.MyTnp.TId cid := tnp.TId logger.Logger.Tracef("WorldSrvApi start TransTypeWebApi OnExecuteWrapper tid:%x childid:%x", pid, cid) return transact.TransExeResult_Success } return transact.TransExeResult_Failed }), OnCommitWrapper: transact.OnCommitWrapper(func(tNode *transact.TransNode) transact.TransExeResult { logger.Logger.Trace("WorldSrvApi start TransTypeWebApi OnCommitWrapper") event := tNode.TransEnv.GetField(WEBAPI_TRANSACTE_EVENT).(*WebApiEvent) resp := tNode.TransEnv.GetField(WEBAPI_TRANSACTE_RESPONSE) if ud, ok := resp.([]byte); ok { event.Response(netlib.SkipHeaderGetRaw(ud)) return transact.TransExeResult_Success } event.Response(nil /*map[string]interface{}{webapi.RESPONSE_STATE: webapi.STATE_ERR, webapi.RESPONSE_ERRMSG: "execute failed!"}*/) return transact.TransExeResult_Success }), OnRollBackWrapper: transact.OnRollBackWrapper(func(tNode *transact.TransNode) transact.TransExeResult { logger.Logger.Trace("WorldSrvApi start TransTypeWebApi OnRollBackWrapper") event := tNode.TransEnv.GetField(WEBAPI_TRANSACTE_EVENT).(*WebApiEvent) resp := tNode.TransEnv.GetField(WEBAPI_TRANSACTE_RESPONSE) if ud, ok := resp.([]byte); ok { event.Response(netlib.SkipHeaderGetRaw(ud)) return transact.TransExeResult_Success } event.Response(nil /*map[string]interface{}{webapi.RESPONSE_STATE: webapi.STATE_ERR, webapi.RESPONSE_ERRMSG: "execute failed!"}*/) return transact.TransExeResult_Success }), OnChildRespWrapper: transact.OnChildRespWrapper(func(tNode *transact.TransNode, hChild transact.TransNodeID, retCode int, ud interface{}) transact.TransExeResult { logger.Logger.Tracef("WorldSrvApi start TransTypeWebApi OnChildRespWrapper ret:%v childid:%x", retCode, hChild) tNode.TransEnv.SetField(WEBAPI_TRANSACTE_RESPONSE, ud) return transact.TransExeResult(retCode) }), }) // 查询在线玩家列表,筛选,排序 admin.MyAdminApp.Route("/api/Report/QueryOnlineReportList", WorldSrvApi) // 在线统计 admin.MyAdminApp.Route("/api/Report/OnlineReportTotal", WorldSrvApi) // 加减金币钻石 admin.MyAdminApp.Route("/api/Game/AddCoinByIdAndPT", WorldSrvApi) // 查询玩家信息 admin.MyAdminApp.Route("/api/Player/PlayerData", WorldSrvApi) // 查询多个玩家信息 admin.MyAdminApp.Route("/api/Player/MorePlayerData", WorldSrvApi) // 踢下线 admin.MyAdminApp.Route("/api/Player/KickPlayer", WorldSrvApi) // 黑白名单调控 admin.MyAdminApp.Route("/api/Player/WhiteBlackControl", WorldSrvApi) // 设置黑名单 admin.MyAdminApp.Route("/api/Player/BlackBySnId", WorldSrvApi) // 修改玩家内存属性 admin.MyAdminApp.Route("/api/Cache/UpdatePlayerElement", WorldSrvApi) // 水池相关 admin.MyAdminApp.Route("/api/Game/QueryGamePoolByGameId", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/QueryAllGamePool", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/RefreshGamePool", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/UpdateGamePool", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/ResetGamePool", WorldSrvApi) // 邮箱相关 admin.MyAdminApp.Route("/api/Game/CreateShortMessage", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/QueryShortMessageList", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/DeleteShortMessage", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/DeleteAllShortMessage", WorldSrvApi) // 获取房间列表 admin.MyAdminApp.Route("/api/Cache/ListRoom", WorldSrvApi) // 获取房间信息 admin.MyAdminApp.Route("/api/Cache/GetRoom", WorldSrvApi) // 销毁房间 admin.MyAdminApp.Route("/api/Cache/DestroyRoom", WorldSrvApi) // 兑换物品 admin.MyAdminApp.Route("/api/Customer/UpExchangeStatus", WorldSrvApi) // 3方平台 admin.MyAdminApp.Route("/api/thd/UpdatePlayerCoin", WorldSrvApi) // 兑换卷 admin.MyAdminApp.Route("/api/Game/CreateJYB", WorldSrvApi) admin.MyAdminApp.Route("/api/Game/UpdateJYB", WorldSrvApi) // 支付回调 admin.MyAdminApp.Route("/api/pay/CallbackPayment", WorldSrvApi) // 资源变更(给所有玩家发送消息) admin.MyAdminApp.Route("/api/game/resource", WorldSrvApi) // 修改手机号 admin.MyAdminApp.Route("/api/player/update_tel", WorldSrvApi) // 删除账号 admin.MyAdminApp.Route("/api/player/delete", WorldSrvApi) // 添加道具 admin.MyAdminApp.Route("/api/player/AddItem", WorldSrvApi) // 获取收货地址 admin.MyAdminApp.Route("/api/player/address", WorldSrvApi) // 修改收货地址 admin.MyAdminApp.Route("/api/player/update_address", WorldSrvApi) // 修改竞技馆抽奖记录图片视频 admin.MyAdminApp.Route("/api/game/show_lottery", WorldSrvApi) // 发送手机验证码 admin.MyAdminApp.Route("/api/game/send_sms", WorldSrvApi) // 网页登录 admin.MyAdminApp.Route("/api/game/web_login", WorldSrvApi) // 兑换商品列表 admin.MyAdminApp.Route("/api/game/exchange_list", WorldSrvApi) // 创建兑换订单 admin.MyAdminApp.Route("/api/game/exchange_create", WorldSrvApi) // 兑换订单列表 admin.MyAdminApp.Route("/api/game/exchange_order", WorldSrvApi) // 平台玩家注册账号 admin.MyAdminApp.Route("/api/platform/createUser", PlatformSrvApi) } func Stats() map[string]ApiStats { stats := make(map[string]ApiStats) WebApiStats.Range(func(k, v interface{}) bool { if s, ok := v.(*ApiStats); ok { ss := *s //计数可能不精准 stats[k.(string)] = ss } return true }) return stats }