package api import ( "crypto/md5" "encoding/hex" "encoding/json" "fmt" "io" "net/http" "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" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/webapi" ) const ( GAMESRVAPI_TRANSACTE_EVENT = "GAMESRVAPI_TRANSACTE_EVENT" GAMESRVAPI_TRANSACTE_RESPONSE = "GAMESRVAPI_TRANSACTE_RESPONSE" ) // type ResponseData struct { // State int // Data string // } func GameSrvWebAPI(rw http.ResponseWriter, req *http.Request) { defer utils.DumpStackIfPanic("api.GameSrvApi") logger.Logger.Info("GameSrvApi 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 { webApiResponse(rw, nil) return } m := req.URL.Query() timestamp := m.Get("nano") if timestamp == "" { logger.Logger.Info(req.RemoteAddr, " GameSrvApi param error: nano not allow null") return } sign := m.Get("sign") if sign == "" { logger.Logger.Info(req.RemoteAddr, " GameSrvApi 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) webApiResponse(rw, nil) 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("GameSrvApi start transcate") tnp := &transact.TransNodeParam{ Tt: common.TransTypeGameSrvWebApi, Ot: transact.TransOwnerType(common.GetSelfSrvType()), Oid: common.GetSelfSrvId(), AreaID: common.GetSelfAreaId(), } tNode := transact.DTCModule.StartTrans(tnp, event, transact.DefaultTransactTimeout) if tNode != nil { tNode.TransEnv.SetField(GAMESRVAPI_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): 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 init() { transact.RegisteHandler(common.TransTypeGameSrvWebApi, &transact.TransHanderWrapper{ OnExecuteWrapper: transact.OnExecuteWrapper(func(tNode *transact.TransNode, ud interface{}) transact.TransExeResult { logger.Logger.Trace("GameSrvApi start TransTypeGameSrvWebApi OnExecuteWrapper") gameSrvIds := common.GetGameSrvIds() logger.Logger.Trace("Current game id:", gameSrvIds) for _, value := range gameSrvIds { tnp := &transact.TransNodeParam{ Tt: common.TransTypeGameSrvWebApi, Ot: transact.TransOwnerType(srvlib.GameServerType), Oid: value, 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} ter := tNode.StartChildTrans(tnp, userData, transact.DefaultTransactTimeout) if ter != transact.TransExeResult_Success { logger.Logger.Tracef("StartChildTrans %v game server failed.", value) } } else { logger.Logger.Trace("Conver ud to WebApiEvent failed OnExecuteWrapper") } } return transact.TransExeResult_Success }), OnCommitWrapper: transact.OnCommitWrapper(func(tNode *transact.TransNode) transact.TransExeResult { logger.Logger.Trace("GameSrvApi start TransTypeGameSrvWebApi OnCommitWrapper") event := tNode.TransEnv.GetField(GAMESRVAPI_TRANSACTE_EVENT).(*WebApiEvent) resp := tNode.TransEnv.GetField(GAMESRVAPI_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("GameSrvApi start TransTypeGameSrvWebApi OnRollBackWrapper") event := tNode.TransEnv.GetField(GAMESRVAPI_TRANSACTE_EVENT).(*WebApiEvent) resp := tNode.TransEnv.GetField(GAMESRVAPI_TRANSACTE_RESPONSE) if ud, ok := resp.([]byte); ok { event.Response(netlib.SkipHeaderGetRaw(ud)) return transact.TransExeResult_Success } event.Response(nil) return transact.TransExeResult_Success }), OnChildRespWrapper: transact.OnChildRespWrapper(func(tNode *transact.TransNode, hChild transact.TransNodeID, retCode int, ud interface{}) transact.TransExeResult { logger.Logger.Tracef("GameSrvApi OnChildRespWrapper %v:%v", hChild, ud) if v, ok := ud.([]byte); ok { var msg webapi.SARoomInfo err := proto.Unmarshal(netlib.SkipHeaderGetRaw(v), &msg) if err == nil && msg.GetTag() == webapi.TagCode_SUCCESS { tNode.TransEnv.SetField(GAMESRVAPI_TRANSACTE_RESPONSE, ud) } else if err != nil { logger.Logger.Errorf("GameSrvApi OnChildRespWrapper unmarshal err %v", err) } } return transact.TransExeResult(retCode) }), }) // 对局详情 admin.MyAdminApp.Route("/api/game/room_info", GameSrvWebAPI) }