using System; using System.Linq; using System.Text; using System.Text.Encodings.Web; using LitJson; using Sog; using ProtoCSStruct; using SimpleHttpServer; using System.Text.Json; using System.Web; using System.Net.Http; using System.Collections.Generic; namespace HttpProxyPay { public static class MessageTaskHandler { public static void HandlerPacket(uint remoteAppID, StructPacket packet) { switch (packet.MsgID) { case (int)SSGameMsgID.PayGoogleRes: OnPayGoogleRes(remoteAppID, packet); break; case (int)SSGameMsgID.PayGoogleSuccessReq: OnPayGoogleSuccReq(remoteAppID, packet); break; case (int)SSGameMsgID.PayGoogleSuccessRes: OnPayGoogleSuccRes(remoteAppID, packet); break; case (int)SSGameMsgID.PaySendDbRefundRes: OnPaySendDBRefundRes(remoteAppID, packet); break; case (int)SSGameMsgID.PayHeroSaveHttpContentRes: OnSaveHttpContentRes(remoteAppID, packet); break; case (int)SSGameMsgID.PayHeroSelectHttpContentRes: OnSelectHttpContentRes(remoteAppID, packet); break; case (int)CSGameMsgID.PayWsjsapiReq: WXHandler.PayWsjsapiReq(remoteAppID, packet); break; default: TraceLog.Error("MessageTaskHandler.HandlerPacket unknow MsgID {0}", packet.MsgID); break; } } private static void OnPayGoogleRes(uint remoteAppID, StructPacket packet) { ref var res = ref packet.GetMessage(); TraceLog.Trace("MessageTaskHandler.OnPayGoogleRes orderId {0} httpCtx {1} uid {2} ret {3}" , res.OrderId, res.HttpCtxId, res.Uid, res.Ret); var httpCtx = HttpContextCache.GetContext(res.HttpCtxId); if (httpCtx == null) { TraceLog.Error("MessageTaskHandler.OnPayGoogleRes httpContext {0} is null", res.HttpCtxId); return; } var args = httpCtx.callbackArgs as HeroPayCallbackArgs; if (args == null) { TraceLog.Error("MessageTaskHandler.OnPayGoogleRes httpContext {0} callbackArgs is null", res.HttpCtxId); return; } string orderId = args.orderId; if (! res.OrderId.Equals(orderId)) { TraceLog.Error("MessageTaskHandler.OnPayGoogleRes res orderId {0} httpCtx {1} orderId {2} not same" , res.OrderId, res.HttpCtxId, orderId); return; } if (args.status != HeroPayCallbackStatus.order) { TraceLog.Error("MessageTaskHandler.OnPayGoogleRes httpContext {0} invalid status {1}" , res.HttpCtxId, args.status); return; } var httpRes = new HeroWebPayGoogleRes(); if (res.Ret == 0) { httpRes.code = 0; httpRes.data = new HeroWebPayData { roleId = res.Uid.ToString(), cpOrderNo = orderId, cpSku = res.PaymentId.GetString() }; var urls = HttpProxyPayServerUtils.GetServerConfig().heroWebPaySuccCallbackUrls; if (urls != null) { TraceLog.Trace("MessageTaskHandler.OnPayGoogleRes urls count {0} http ctx pcode {1}" , urls.Count, args.pcode); foreach (HeroWebPayCallbackUrl item in urls) { if (args.pcode.Equals(item.pcode)) { httpRes.data.cpNotifyUrl = item.url; break; } } } if (res.WorldId > 0) { var msg = new HeroPayCpCustomMsg { worldId = res.WorldId}; var msgByte = Encoding.ASCII.GetBytes(JsonSerializer.Serialize(msg)); httpRes.data.cpCustomMsg = HttpUtility.UrlDecode(Convert.ToBase64String(msgByte)); } } else { httpRes.code = -1; httpRes.msg = "order failed"; } string ret = JsonSerializer.Serialize(httpRes); TraceLog.Trace("MessageTaskHandler.OnPayGoogleRes httpContext {0} res {1}", res.HttpCtxId, ret); httpCtx.httpResponse = new HttpResponse { StatusCode = "200", Content = Encoding.UTF8.GetBytes(ret) }; HttpServer.SendResponse(httpCtx); HttpContextCache.RemoveContext(httpCtx); } private static void OnPayGoogleSuccReq(uint remoteAppID, StructPacket packet) { ref var req = ref packet.GetMessage(); if (req.PayType == (int)PayType.Huawei) { SendToHuaweiCheckPayToken(remoteAppID, ref req); } else { TraceLog.Error("MessageTaskHandler.OnPayGoogleSuccReq pay type {0} not handle", req.PayType); } } private static void SendToHuaweiCheckPayToken(uint remoteAppID, ref SSPayGoogleSuccessReq req) { int ret = SendToHuaweiCheckPayToken(ref req); if (ret != 0) { var res = new SSPayGoogleSuccessRes { Ret = -1, Uid = req.Uid, PayType = req.PayType, PayParam1 = req.PayParam1, PayParam2 = req.PayParam2, PayTime3rd = req.PayTime3rd, GmTestPay = req.GmTestPay, Sandbox = req.Sandbox, }; res.ItemID = req.ItemID; res.OrderId.SetString(req.OrderId.GetPtr()); res.OrderId3rd.SetString(req.OrderId3rd.GetPtr()); HttpProxyPayServerUtils.GetPacketSender().SendToServerByID( remoteAppID, (int)SSGameMsgID.PayGoogleSuccessRes, ref res, req.Uid); } } private static int SendToHuaweiCheckPayToken(ref SSPayGoogleSuccessReq req) { string reqOrderId = req.OrderId.GetString(); TraceLog.Trace("MessageTaskHandler.SendToHuaweiCheckPayToken uid {0} req orderId {1}", req.Uid, reqOrderId); string purchaseData = req.PurchaseData.GetString(); JsonData purchaseJson = JsonMapper.ToObject(purchaseData); if (purchaseJson == null) { TraceLog.Error("MessageTaskHandler.SendToHuaweiCheckPayToken uid {0} PurchaseData to Json error", req.Uid); return -1; } JsonData tokenData = purchaseJson["purchaseToken"]; if (tokenData == null) { TraceLog.Error("MessageTaskHandler.SendToHuaweiCheckPayToken uid {0} no [purchaseToken]", req.Uid); return -1; } JsonData productIdData = purchaseJson["productId"]; if (productIdData == null) { TraceLog.Error("MessageTaskHandler.SendToHuaweiCheckPayToken uid {0} no [productId]", req.Uid); return -1; } string purchaseToken = tokenData.ToString(); string productId = productIdData.ToString(); JsonData jsonData = null; // 发送到华为服务器校验payToken是否存在 int ret = HuaweiPaySvc.HttpPostCheckPayTokenInner(purchaseToken, productId, out jsonData); // 401代表token过期, 过期时重新获取新的token后再试一次 // 注意这里是多线程处理http请求, 存在多个线程同时刷新token的情况!!! // 华为的客服回复: accessToken在有效期内无论申请几次都是同一个token, 所以同时刷新也没关系 if (ret == 401) { var svrData = HttpProxyPayServerUtils.GetHttpProxyServerData(); svrData.huaweiAppAccessToken = HuaweiPaySvc.GetAppAccessToken(); ret = HuaweiPaySvc.HttpPostCheckPayTokenInner(purchaseToken, productId, out jsonData); } // token校验失败, 或者没有返回购买数据 if (ret != 0 || jsonData == null) { TraceLog.Error("HuaweiPaySvc.SendToHuaweiCheckPayToken uid {0} item {1} check fail {2}" , req.Uid, reqOrderId, ret); return -1; } // 游戏内部自己的订单号 JsonData payload = jsonData["developerPayload"]; if (payload == null) { TraceLog.Error("HuaweiPaySvc.SendToHuaweiCheckPayToken uid {0} no [developerPayload]", req.Uid); return -1; } // 校验华为服务器传回的订单号和客户端上报的订单号是否一致 string resOrderId = payload.ToString(); if (string.IsNullOrEmpty(resOrderId) || ! resOrderId.Equals(reqOrderId)) { TraceLog.Error("HuaweiPaySvc.SendToHuaweiCheckPayToken uid {0} req order {1} res order {2} not same" , req.Uid, reqOrderId, resOrderId); return -1; } int payState = -1; JsonData payStateJson = jsonData["purchaseState"]; if (payStateJson != null && int.TryParse(payStateJson.ToString(), out payState)) { TraceLog.Trace("HuaweiPaySvc.OnPaySuccessReq orderId {0} purchaseState {1}", resOrderId, payState); } else { payState = -1; } // 订单不是已购买状态 if (payState != 0) { TraceLog.Error("HuaweiPaySvc.OnPaySuccessReq orderId {0} purchaseState {1} not pay", resOrderId, payState); return -1; } // uid-time-orderIdSeq-serverId-payitemId-payParam1-payParam2-paymentId-payUrlId string[] split = resOrderId.Split('-'); if (split.Length < 9) { TraceLog.Error("HuaweiPaySvc.OnPaySuccessReq invalid orderId {0}, need >= 9 params", resOrderId); return -1; } JsonData productIdJson = jsonData["productId"]; if (productIdJson == null) { TraceLog.Error("HuaweiPaySvc.OnPaySuccessReq uid {0} no [productId]", req.Uid); return -1; } string goodsId = split[7]; productId = productIdJson.ToString(); // 商品id不是同一个 if (string.IsNullOrEmpty(productId) || !goodsId.Equals(productId)) { TraceLog.Error("HuaweiPaySvc.OnPaySuccessReq itemId svr {0} clt {1} not same", productId, goodsId); return -1; } JsonData currencyJson = jsonData["currency"]; if (currencyJson == null) { TraceLog.Error("HuaweiPaySvc.OnPaySuccessReq uid {0} no [currency]", req.Uid); return -1; } JsonData priceJson = jsonData["price"]; if (priceJson == null) { TraceLog.Error("HuaweiPaySvc.OnPaySuccessReq uid {0} no [price]", req.Uid); return -1; } // 钱相关的字段还是用华为服务器返回的数据赋值 req.PurchaseToken.SetString(purchaseToken); req.Currency.SetString(currencyJson.ToString()); if (long.TryParse(priceJson.ToString(), out long amount)) { req.Amount = (uint)amount; } // 校验成功将req发到DBServer uint dbServerID = DBServerSelect.GetDBServerID(req.Uid); HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(dbServerID, (int)SSGameMsgID.PayGoogleSuccessReq, ref req, req.Uid); return 0; } private static void OnPayGoogleSuccRes(uint remoteAppID, StructPacket packet) { ref var res = ref packet.GetMessage(); TraceLog.Trace("MessageTaskHandler.OnPayGoogleSuccRes orderId {0} httpCtx {1} uid {2} ret {3}" , res.OrderId, res.HttpCtxId, res.Uid, res.Ret); if (res.Ret == 0 && res.HttpCtxId != 0) { var httpCtx = HttpContextCache.GetContext(res.HttpCtxId); if (httpCtx == null) { // 找不到没关系, SDK会重试, 只要服务器的逻辑保证不重复加钱就行 TraceLog.Error("MessageTaskHandler.OnPayGoogleSuccRes httpContext {0} is null", res.HttpCtxId); return; } var args = httpCtx.callbackArgs as HeroPayCallbackArgs; if (args == null) { TraceLog.Error("MessageTaskHandler.OnPayGoogleSuccRes httpContext {0} callbackArgs is null", res.HttpCtxId); return; } string orderId = args.orderId; if (!res.OrderId.Equals(orderId)) { TraceLog.Error("MessageTaskHandler.OnPayGoogleSuccRes res orderId {0} httpCtx {1} orderId {2}" , res.OrderId, res.HttpCtxId, orderId); return; } if (args.status != HeroPayCallbackStatus.paySucc) { TraceLog.Error("MessageTaskHandler.OnPayGoogleSuccRes httpContext {0} invalid status {1}" , res.HttpCtxId, args.status); return; } if (res.PayType == (int)PayType.MiniPay) { httpCtx.httpResponse = new HttpResponse { StatusCode = "200", Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}") }; } else { httpCtx.httpResponse = new HttpResponse { StatusCode = "200", Content = Encoding.UTF8.GetBytes("SUCCESS") }; } HttpServer.SendResponse(httpCtx); HttpContextCache.RemoveContext(httpCtx); } } private static void OnPaySendDBRefundRes(uint remoteAppID, StructPacket packet) { ref var res = ref packet.GetMessage(); TraceLog.Trace("MessageTaskHandler.OnPaySendDBRefundRes orderId {0} httpCtx {1} uid {2} ret {3}" , res.OrderId, res.HttpCtxId, res.Uid, res.Ret); var httpCtx = HttpContextCache.GetContext(res.HttpCtxId); if (httpCtx == null) { TraceLog.Error("MessageTaskHandler.OnPaySendDBRefundRes httpContext {0} is null", res.HttpCtxId); return; } var args = httpCtx.callbackArgs as HeroPayCallbackArgs; if (args == null) { TraceLog.Error("MessageTaskHandler.OnPaySendDBRefundRes httpContext {0} callbackArgs is null", res.HttpCtxId); return; } string orderId = args.orderId; if (!res.OrderId.Equals(orderId)) { TraceLog.Error("MessageTaskHandler.OnPaySendDBRefundRes res orderId {0} httpCtx {1} orderId {2} not same" , res.OrderId, res.HttpCtxId, orderId); return; } if (args.status != HeroPayCallbackStatus.refund) { TraceLog.Error("MessageTaskHandler.OnPaySendDBRefundRes httpContext {0} invalid status {1}" , res.HttpCtxId, args.status); return; } if (res.Ret == 0) { httpCtx.httpResponse = new HttpResponse { StatusCode = "200", Content = Encoding.UTF8.GetBytes("SUCCESS") }; HttpServer.SendResponse(httpCtx); } HttpContextCache.RemoveContext(httpCtx); } private static void OnSaveHttpContentRes(uint remoteAppID, StructPacket packet) { ref var res = ref packet.GetMessage(); HeroUSDKSvc.PostHttpRequest(ref res.Http); } private static void OnSelectHttpContentRes(uint remoteAppID, StructPacket packet) { ref var res = ref packet.GetMessage(); for (int i = 0; i < res.Http.Count; i++) { HeroUSDKSvc.PostHttpRequest(ref res.Http[i]); } } } }