game_sync/mgrsrv/api/webapi_gamesrv.go

195 lines
6.7 KiB
Go

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/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)
LogChannelSington.WriteLog(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)
}