You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
966 lines
40 KiB
966 lines
40 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.Http;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Web;
|
|
using LitJson;
|
|
using ProtoCSStruct;
|
|
using SimpleHttpServer;
|
|
using Sog;
|
|
using Sog.Crypto;
|
|
using System.Text.Json;
|
|
using System.Security.Cryptography;
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Org.BouncyCastle.Bcpg;
|
|
using Newtonsoft.Json.Linq;
|
|
using TencentCloud.Ecm.V20190719.Models;
|
|
|
|
namespace HttpProxyPay
|
|
{
|
|
// 英雄支付回调状态类型
|
|
public enum HeroPayCallbackStatus
|
|
{
|
|
order = 1, // 下单
|
|
paySucc = 2, // 支付成功
|
|
refund = 3, // 退款
|
|
}
|
|
|
|
// 英雄支付回调结构
|
|
public class HeroPayCallbackArgs
|
|
{
|
|
public string orderId;
|
|
public HeroPayCallbackStatus status;
|
|
public string pcode;
|
|
}
|
|
|
|
public class HeroWebPayData
|
|
{
|
|
public string roleId { get; set; }
|
|
public string cpOrderNo { get; set; }
|
|
public string cpNotifyUrl { get; set; }
|
|
public string cpCustomMsg { get; set; }
|
|
public string cpSku { get; set; }
|
|
}
|
|
|
|
public class HeroWebPayGoogleRes
|
|
{
|
|
public int code { get; set; }
|
|
public HeroWebPayData data { get; set; }
|
|
public string msg { get; set; }
|
|
}
|
|
|
|
public static class HttpParamsUtils
|
|
{
|
|
// 解析k1=v1&k2=v2&k3=v3...格式的字符串
|
|
public static Dictionary<string, string> ParseByKeyValue(string str)
|
|
{
|
|
str = str.Trim();
|
|
if (string.IsNullOrEmpty(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
int idx = str.IndexOf('?');
|
|
if (idx != -1)
|
|
{
|
|
str = str.Substring(idx + 1);
|
|
}
|
|
|
|
var map = new Dictionary<string, string>();
|
|
|
|
string[] allParams = str.Split('&');
|
|
foreach (var param in allParams)
|
|
{
|
|
string[] namevalue = param.Split('=');
|
|
if (namevalue != null && namevalue.Length == 2)
|
|
{
|
|
map[namevalue[0]] = namevalue[1];
|
|
}
|
|
}
|
|
|
|
return map;
|
|
}
|
|
}
|
|
|
|
|
|
public static class HttpContextCache
|
|
{
|
|
private static object httpCtxCacheLocker = new object();
|
|
private static Dictionary<uint, HttpContext> httpCtxCache = new Dictionary<uint, HttpContext>();
|
|
private static List<HttpContext> waitDeleteCtx = new List<HttpContext>();
|
|
|
|
public static bool AddContext(HttpContext httpCtx)
|
|
{
|
|
lock (httpCtxCacheLocker)
|
|
{
|
|
if (httpCtxCache.ContainsKey(httpCtx.id))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.AddContext fail, id {0} already exist", httpCtx.id);
|
|
return false;
|
|
}
|
|
|
|
httpCtx.CreateTime = HttpProxyPayServerUtils.GetTimeSecond();
|
|
|
|
httpCtxCache.Add(httpCtx.id, httpCtx);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool RemoveContext(HttpContext httpCtx)
|
|
{
|
|
lock (httpCtxCacheLocker)
|
|
{
|
|
waitDeleteCtx.Add(httpCtx);
|
|
return httpCtxCache.Remove(httpCtx.id);
|
|
}
|
|
}
|
|
|
|
public static HttpContext GetContext(uint id)
|
|
{
|
|
lock (httpCtxCacheLocker)
|
|
{
|
|
if (httpCtxCache.TryGetValue(id, out HttpContext ctx))
|
|
{
|
|
return ctx;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static void TickTimeoutClient(long nowSec)
|
|
{
|
|
//30秒超时
|
|
lock (httpCtxCacheLocker)
|
|
{
|
|
List<HttpContext> timeoutList = new List<HttpContext>();
|
|
foreach(var hc in httpCtxCache)
|
|
{
|
|
if(nowSec - hc.Value.CreateTime > 30)
|
|
{
|
|
timeoutList.Add(hc.Value);
|
|
}
|
|
}
|
|
|
|
// 等待删除的队列
|
|
for (int i = waitDeleteCtx.Count - 1; i >= 0; i--)
|
|
{
|
|
if (nowSec - waitDeleteCtx[i].CreateTime > 30)
|
|
{
|
|
timeoutList.Add(waitDeleteCtx[i]);
|
|
waitDeleteCtx.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
foreach (var hc in timeoutList)
|
|
{
|
|
try
|
|
{
|
|
hc.client.Close();
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
}
|
|
|
|
httpCtxCache.Remove(hc.id);
|
|
}
|
|
|
|
timeoutList.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static class HeroPayHttpHandler
|
|
{
|
|
// 网页支付查询使用的key
|
|
private static string _WebPayKey = "4os5dyf7z39b66i9fxz7";
|
|
|
|
|
|
public static void Init(HttpProxyPayServerConfig config)
|
|
{
|
|
if (! string.IsNullOrEmpty(config.heroWebPayKey))
|
|
{
|
|
_WebPayKey = config.heroWebPayKey;
|
|
}
|
|
|
|
TraceLog.Trace("HeroPayHttpHandler.Init web pay key {0}", _WebPayKey);
|
|
}
|
|
|
|
public static void HeroPayCallback_SEA(HttpContext httpCtx)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback_SEA {0}", httpCtx.id);
|
|
HeroPayCallback(httpCtx, HeroUSDKSvc._CALLBACK_KEY[(int)HeroUSDKProj.SEA], HeroUSDKProj.SEA);
|
|
}
|
|
|
|
public static void HeroPayCallback_JP(HttpContext httpCtx)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback_JP {0}", httpCtx.id);
|
|
HeroPayCallback(httpCtx, HeroUSDKSvc._CALLBACK_KEY[(int)HeroUSDKProj.JP], HeroUSDKProj.JP);
|
|
}
|
|
public static void HeroPayCallback_KR(HttpContext httpCtx)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback_KR {0}", httpCtx.id);
|
|
HeroPayCallback(httpCtx, HeroUSDKSvc._CALLBACK_KEY[(int)HeroUSDKProj.KR], HeroUSDKProj.KR);
|
|
}
|
|
public static void HeroPayCallback_ZH(HttpContext httpCtx)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback_ZH {0}", httpCtx.id);
|
|
HeroPayCallback(httpCtx, HeroUSDKSvc._CALLBACK_KEY[(int)HeroUSDKProj.ZH], HeroUSDKProj.ZH);
|
|
}
|
|
public static void HeroPayCallback_JP2(HttpContext httpCtx)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback_JP2 {0}", httpCtx.id);
|
|
HeroPayCallback(httpCtx, HeroUSDKSvc._CALLBACK_KEY[(int)HeroUSDKProj.JP2], HeroUSDKProj.JP2);
|
|
}
|
|
public static void HeroPayCallback_EN(HttpContext httpCtx)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback_EN {0}", httpCtx.id);
|
|
HeroPayCallback(httpCtx, HeroUSDKSvc._CALLBACK_KEY[(int)HeroUSDKProj.EN], HeroUSDKProj.EN);
|
|
}
|
|
/* 可以用postman 发送http post请求来处理出错的订单,前提是日志里有之前callback的记录
|
|
POST url 为 http://ip:31006/heropay/
|
|
注意不能在url里多填内容,只能是上面那个,参数填在body里
|
|
参数类型为x-www-form-urlencoded,2个参数,一个data,一个sign
|
|
data里注意转义,日志里打印的 %3D 要改成 =
|
|
*/
|
|
public static void HeroPayCallback(HttpContext httpCtx, string cbKey, HeroUSDKProj proj)
|
|
{
|
|
if (httpCtx.httpRequest == null)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback ctx id {0} httpRequest is null", httpCtx.id);
|
|
return;
|
|
}
|
|
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback ctx id {0} content {1}", httpCtx.id, httpCtx.httpRequest.Content);
|
|
|
|
var postParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Content);
|
|
if (! postParams.TryGetValue("data", out string recvPayData))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback 'data' is null");
|
|
return;
|
|
}
|
|
|
|
if (! postParams.TryGetValue("sign", out string sign))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback 'sign' is null");
|
|
return;
|
|
}
|
|
|
|
// url解码
|
|
string payData = HttpUtility.UrlDecode(recvPayData);
|
|
|
|
// 校验签名
|
|
var allParams = new Dictionary<string, string>();
|
|
allParams["data"] = payData;
|
|
|
|
string calcSign = HeroUSDKSecurity.CalcSign(cbKey, allParams);
|
|
if (calcSign != sign)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback sign not same, calc {0} req {1}", calcSign, sign);
|
|
return;
|
|
}
|
|
|
|
// base64解码
|
|
byte[] tmp = Convert.FromBase64String(payData);
|
|
var payStr = Encoding.UTF8.GetString(tmp);
|
|
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback {0}", payStr);
|
|
|
|
JsonData payDataJson = JsonMapper.ToObject(payStr);
|
|
string orderId = payDataJson["gameOrder"].ToString();
|
|
string[] split = orderId.Split('-');
|
|
|
|
// uid-time-orderIdSeq-serverId-payitemId-payParam1-payParam2-paymentId-payUrlId
|
|
if (split.Length < 8)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid orderId {0}, need >= 8 params", orderId);
|
|
return;
|
|
}
|
|
|
|
int payUrlId = 0;
|
|
if (split.Length >= 9)
|
|
{
|
|
string strpayUrlId = split[8];
|
|
if (!string.IsNullOrEmpty(strpayUrlId))
|
|
{
|
|
if (!int.TryParse(strpayUrlId, out payUrlId))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid payUrlId {0}", strpayUrlId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 打印错误log方便查询所有请求
|
|
string orderId3rd = payDataJson["orderNo"].ToString();
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback orderId {0} order3rd {1}", orderId, orderId3rd);
|
|
|
|
var svrData = HttpProxyPayServerUtils.GetHttpProxyServerData();
|
|
if (payUrlId > 0 && payUrlId != svrData.selfPayId)
|
|
{
|
|
if (payUrlId < svrData.payUrlCfg.Length && svrData.payUrlCfg[payUrlId] != null)
|
|
{
|
|
string url = svrData.payUrlCfg[payUrlId].url;
|
|
if (proj == HeroUSDKProj.JP)
|
|
{
|
|
url = url.Replace("heropay_sea", "heropay_jp");
|
|
}else if (proj == HeroUSDKProj.KR)
|
|
{
|
|
url = url.Replace("heropay_sea", "heropay_kr");
|
|
}
|
|
|
|
// 支付转发是正常情况, 打印错误log方便查询转发到内网的请求
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback orderId {0} order3rd {1} trans to {2}",
|
|
orderId, payDataJson["orderNo"].ToString(), url);
|
|
|
|
var trans = new Dictionary<string, string>();
|
|
// 这里要使用urldecode之后的数据, 否则转发的时候又会再次被urlencode
|
|
trans["data"] = payData;
|
|
trans["sign"] = sign;
|
|
|
|
var content = new FormUrlEncodedContent(trans);
|
|
string ret = HttpUtils.HttpPost(url, content, out bool exception);
|
|
if (string.IsNullOrEmpty(ret))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback trans fail, HttpPost return null");
|
|
}
|
|
else if (ret == "SUCCESS")
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback trans succ, remote paysvr res 'SUCCESS'", ret);
|
|
// 转发给英雄的支付服务器
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = "200", Content = Encoding.UTF8.GetBytes("SUCCESS") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
}
|
|
else
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback remote paysvr res fail {0}", ret);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback orderId {0} payUrlId {1} no url", orderId, payUrlId);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (! long.TryParse(split[0], out long uid))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid uid {0}", split[0]);
|
|
return;
|
|
}
|
|
|
|
if (! HttpContextCache.AddContext(httpCtx))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback add httpContext failed, ctx id {0}", httpCtx.id);
|
|
return;
|
|
}
|
|
|
|
if (! int.TryParse(split[5], out int payParam1))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid payParam1 {0}", split[5]);
|
|
|
|
payParam1 = (int)PayUtils.GetParam1FromOrderId(orderId);
|
|
if (payParam1 >= 0)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid payParam1 {0} {1}", split[5], payParam1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( !int.TryParse(split[6], out int payParam2))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid payParam2 {0}", split[6]);
|
|
return;
|
|
}
|
|
|
|
// 英雄支付的子类型
|
|
int subPayType = 0;
|
|
if (payDataJson.ContainsKey("payType"))
|
|
{
|
|
int.TryParse(payDataJson["payType"].ToString(), out subPayType);
|
|
}
|
|
|
|
string currency = null;
|
|
// 英雄不保证回调中的币种currency字段是否存在
|
|
if (payDataJson.ContainsKey("currency"))
|
|
{
|
|
currency = payDataJson["currency"].ToString();
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(currency))
|
|
{
|
|
currency = ((Currency)((int)proj)).ToString(); // 对方空就填0, 后面好算账
|
|
}
|
|
|
|
string am = payDataJson["amount"].ToString();
|
|
if (!double.TryParse(am, out double amount))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid amount {0}", am);
|
|
return;
|
|
}
|
|
|
|
// 英雄支付的子类型
|
|
int sandbox = 0;
|
|
if (payDataJson.ContainsKey("sandbox"))
|
|
{
|
|
int.TryParse(payDataJson["sandbox"].ToString(), out sandbox);
|
|
}
|
|
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroPayCallback amount str {0} double {1}", am, amount);
|
|
|
|
// 支付id不一致, 说明订单请求金额跟实际支付的金额不一致
|
|
string goodsId = payDataJson["goodsId"].ToString();
|
|
|
|
if (! goodsId.Equals(split[7]))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid paymentId, req {0} res {1}", goodsId, split[7]);
|
|
|
|
SSPayGoogleSuccessRes res = new SSPayGoogleSuccessRes {Uid = uid, PayType = (int)PayType.Hero };
|
|
res.Ret = (int) CSErrCode.PayMoneyNotEqual;
|
|
res.OrderId.SetString(orderId);
|
|
res.OrderId3rd.SetString(orderId3rd);
|
|
res.ItemID = int.Parse(split[4]);
|
|
res.PayParam1 = payParam1;
|
|
res.PayParam2 = payParam2;
|
|
res.PayTime3rd = ConfigStringTimeParse.ParseConfigTime(payDataJson["payTime"].ToString());
|
|
res.GmTestPay = payDataJson["channelUid"].ToString().Equals("0");
|
|
res.Currency.SetString(currency);
|
|
res.Amount = Convert.ToUInt32(amount * 100);
|
|
|
|
if (!uint.TryParse(split[3], out uint serverId))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid uid {0}", split[0]);
|
|
return;
|
|
}
|
|
|
|
// 发给world处理, 注意serverId是gamesvr的id
|
|
var worldId = ServerIDUtils.GetLevel1ServerIDByType(serverId, (int)ServerType.World, 1);
|
|
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(worldId, (int)SSGameMsgID.PayGoogleSuccessRes, ref res, uid);
|
|
return;
|
|
}
|
|
|
|
// 保存回调上下文
|
|
httpCtx.callbackArgs = new HeroPayCallbackArgs {orderId = orderId, status = HeroPayCallbackStatus.paySucc};
|
|
|
|
var req = new SSPayGoogleSuccessReq {Uid = uid, PayType = (int) PayType.Hero, CheckSuccess3rd = 1};
|
|
req.HttpCtxId = httpCtx.id;
|
|
req.ItemID = int.Parse(split[4]);
|
|
req.PurchaseData.SetString(payData);
|
|
req.Signature.SetString(sign);
|
|
req.OrderId.SetString(orderId);
|
|
req.OrderId3rd.SetString(payDataJson["orderNo"].ToString());
|
|
req.PayParam1 = payParam1;
|
|
req.PayParam2 = payParam2;
|
|
req.GmTestPay = payDataJson["channelUid"].ToString().Equals("0");
|
|
req.Amount = Convert.ToUInt32(amount * 100);
|
|
req.Currency.SetString(currency); // 币种
|
|
req.SubPayType = subPayType;
|
|
req.PayTime3rd = ConfigStringTimeParse.ParseConfigTime(payDataJson["payTime"].ToString());
|
|
req.Sandbox = sandbox;
|
|
// 如果第三方时间解析不出来就用服务器当前时间
|
|
if (req.PayTime3rd == 0)
|
|
{
|
|
req.PayTime3rd = HttpProxyPayServerUtils.GetTimeSecond();
|
|
}
|
|
|
|
var desc = PayDiamondDescMgr.Instance.GetConfig(int.Parse(split[4]));
|
|
|
|
|
|
uint dbServerID = DBServerSelect.GetDBServerID(uid);
|
|
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(dbServerID, (int)SSGameMsgID.PayGoogleSuccessReq, ref req, uid);
|
|
}
|
|
|
|
public static void HeroRefundCallback(HttpContext httpCtx, string cbKey)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HeroRefundCallback content {0}", httpCtx.httpRequest.Content);
|
|
|
|
var postParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Content);
|
|
if (!postParams.TryGetValue("data", out string payData))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroRefundCallback 'data' is null");
|
|
return;
|
|
}
|
|
|
|
if (!postParams.TryGetValue("sign", out string sign))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroRefundCallback 'sign' is null");
|
|
return;
|
|
}
|
|
|
|
// url解码
|
|
payData = HttpUtility.UrlDecode(payData);
|
|
|
|
// 校验签名
|
|
var allParams = new Dictionary<string, string>();
|
|
allParams["data"] = payData;
|
|
|
|
string calcSign = HeroUSDKSecurity.CalcSign(cbKey, allParams);
|
|
if (calcSign != sign)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroRefundCallback sign not same, calc {0} req {1}", calcSign, sign);
|
|
return;
|
|
}
|
|
|
|
// base64解码
|
|
byte[] tmp = Convert.FromBase64String(payData);
|
|
JsonData payDataJson = JsonMapper.ToObject(Encoding.UTF8.GetString(tmp));
|
|
|
|
string orderId = payDataJson["gameOrder"].ToString();
|
|
string[] split = orderId.Split('-');
|
|
|
|
// uid-time-orderIdSeq-serverId-payitemId-payParam1-payParam2
|
|
if (split.Length != 7)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroRefundCallback invalid orderId {0}", orderId);
|
|
return;
|
|
}
|
|
|
|
if (!long.TryParse(split[0], out long uid))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroRefundCallback invalid uid {0}", split[0]);
|
|
return;
|
|
}
|
|
|
|
if (! HttpContextCache.AddContext(httpCtx))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroRefundCallback add httpContext failed, ctx id {0}", httpCtx.id);
|
|
return;
|
|
}
|
|
|
|
// 保存订单号
|
|
httpCtx.callbackArgs = new HeroPayCallbackArgs { orderId = orderId, status = HeroPayCallbackStatus.refund };
|
|
|
|
var req = new SSPaySendDBRefundReq { Uid = uid, HttpCtxId = httpCtx.id};
|
|
req.OrderId.SetString(orderId);
|
|
req.OrderId3rd.SetString(payDataJson["orderNo"].ToString());
|
|
req.RefundTime = ConfigStringTimeParse.ParseConfigTime(payDataJson["refund_time"].ToString());
|
|
|
|
uint dbServerID = DBServerSelect.GetDBServerID(uid);
|
|
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(dbServerID, (int)SSGameMsgID.PaySendDbRefundReq, ref req, uid);
|
|
}
|
|
|
|
|
|
public static string HeroPayDecode(string str, byte[] keys)
|
|
{
|
|
if (string.IsNullOrEmpty(str) || keys == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// 需要url_decode
|
|
if (str[0] == '%')
|
|
{
|
|
str = HttpUtility.UrlDecode(str, Encoding.UTF8);
|
|
}
|
|
|
|
List<byte> data_enc = new List<byte>();
|
|
|
|
Match m = Regex.Match(str, "\\d+");
|
|
while (m.Success)
|
|
{
|
|
data_enc.Add(Convert.ToByte(m.Value));
|
|
m = m.NextMatch();
|
|
}
|
|
|
|
byte[] data = new byte[data_enc.Count];
|
|
for (int i = 0; i < data_enc.Count; i++)
|
|
{
|
|
data[i] = (byte) (data_enc[i] - (0xff & keys[i % keys.Length]));
|
|
}
|
|
|
|
return Encoding.UTF8.GetString(data);
|
|
}
|
|
|
|
|
|
public static void HomeAdCallBack(HttpContext httpCtx)
|
|
{
|
|
if (httpCtx.httpRequest == null)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeAdCallBack ctx id {0} httpRequest is null", httpCtx.id);
|
|
return;
|
|
}
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeAdCallBack Url:{0} Content:{1}", httpCtx.httpRequest.Url, httpCtx.httpRequest.Content);
|
|
|
|
Dictionary<string, string> allParams = null;
|
|
if (httpCtx.httpRequest.Url.IndexOf('?') >= 0)
|
|
{
|
|
allParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Url);
|
|
}
|
|
else
|
|
{
|
|
allParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Content);
|
|
}
|
|
// url解码
|
|
foreach (var kv in allParams)
|
|
{
|
|
allParams[kv.Key] = HttpUtility.UrlDecode(kv.Value);
|
|
}
|
|
|
|
var errorFlag = false;
|
|
|
|
//获取玩家uid
|
|
long userId = 0;
|
|
if (!allParams.TryGetValue("user_id", out string user_id))
|
|
{
|
|
errorFlag = true;
|
|
}
|
|
else
|
|
{
|
|
userId = Convert.ToInt64(user_id);
|
|
if (userId <= 0) errorFlag = true;
|
|
}
|
|
|
|
var player = HttpProxyPayServerUtils.GetPlayerTableOp().GetPlayer(userId);
|
|
if (player == null)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeAdCallBack get player is null! player:{0}", userId);
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.OtherError).ToString(), Content = Encoding.UTF8.GetBytes("ERROR") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
return;
|
|
}
|
|
|
|
if (!allParams.TryGetValue("trans_id", out string trans_id)) errorFlag = true;
|
|
if (!allParams.TryGetValue("extra_data", out string extra_data)) errorFlag = true;
|
|
if (!allParams.TryGetValue("placement_id", out string placement_id)) errorFlag = true;
|
|
if (!allParams.TryGetValue("adsource_id", out string adsource_id)) errorFlag = true;
|
|
if (!allParams.TryGetValue("reward_amount", out string reward_amount)) errorFlag = true;
|
|
if (!allParams.TryGetValue("reward_name", out string reward_name)) errorFlag = true;
|
|
if (!allParams.TryGetValue("sign", out string sign)) errorFlag = true;
|
|
allParams.TryGetValue("ilrd", out string ilrd);
|
|
if (errorFlag)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeAdCallBack info error!");
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.OtherError).ToString(), Content = Encoding.UTF8.GetBytes("ERROR")};
|
|
HttpServer.SendResponse(httpCtx);
|
|
return;
|
|
}
|
|
string sec_key = HttpProxyPayServerUtils.GetServerConfig().adkey;
|
|
|
|
string signStr;
|
|
if (string.IsNullOrEmpty(ilrd))
|
|
{
|
|
signStr = "trans_id=" + trans_id + "&placement_id=" + placement_id + "&adsource_id=" + adsource_id + "&reward_amount=" + reward_amount + "&reward_name=" + reward_name + "&sec_key=" + sec_key;
|
|
}
|
|
else
|
|
{
|
|
signStr = "trans_id=" + trans_id + "&placement_id=" + placement_id + "&adsource_id=" + adsource_id + "&reward_amount=" + reward_amount + "&reward_name=" + reward_name + "&sec_key=" + sec_key + "&ilrd=" + ilrd;
|
|
}
|
|
var md5sign = HashHelper.MD5Utf8String(signStr);
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeAdCallBack sign key:{0} sign:{1} md5Sign:{2}", sec_key, sign, md5sign);
|
|
if (sign != md5sign)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeAdCallBack sign error sign:{0} md5Sign:{1}", sign, md5sign);
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.SignError).ToString(), Content = Encoding.UTF8.GetBytes("ERROR") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
return;
|
|
}
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("SUCCESS") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
//将信息发送给所有的逻辑服
|
|
SSHomeAdSendAwardSyn syn = new SSHomeAdSendAwardSyn();
|
|
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(player.worldSvrId, (int)SSGameMsgID.HomeAdSendAwardSyn, ref syn, userId);
|
|
}
|
|
|
|
private static void SendWebPayErrorMsg(HttpContext httpCtx, string errorMsg)
|
|
{
|
|
var httpRes = new HeroWebPayGoogleRes{code = -1, msg = errorMsg};
|
|
|
|
string ret = JsonSerializer.Serialize(httpRes);
|
|
TraceLog.Trace("HeroPayHttpHandler.SendWebPayErrorMsg httpContext {0} msg {1}", httpCtx.id, errorMsg);
|
|
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = "200", Content = Encoding.UTF8.GetBytes(ret) };
|
|
HttpServer.SendResponse(httpCtx);
|
|
}
|
|
public static void HomeMiniMsgBack(HttpContext httpCtx)
|
|
{
|
|
if (httpCtx.httpRequest == null)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniMsgBack ctx id {0} httpRequest is null", httpCtx.id);
|
|
return;
|
|
}
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("SUCCESS") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 小程序支付的单独接口
|
|
/// </summary>
|
|
/// <param name="httpCtx"></param>
|
|
public static void HomeMiniCallBack(HttpContext httpCtx)
|
|
{
|
|
if (httpCtx.httpRequest == null)
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack ctx id {0} httpRequest is null", httpCtx.id);
|
|
return;
|
|
}
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack ctx id {0} content {1}, url {2}, path={3}, header{4}", httpCtx.id, httpCtx.httpRequest.Content,
|
|
httpCtx.httpRequest.Url, httpCtx.httpRequest.Path, httpCtx.httpRequest.Headers);
|
|
|
|
var postParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Path);
|
|
if (!postParams.TryGetValue("signature", out string signature))
|
|
{
|
|
//TraceLog.Error("HeroPayHttpHandler.HomeMiniMsgBack 'signature' is null");
|
|
//jsapi回调
|
|
WXHandler.HomeMiniJSAPICallBack(httpCtx);
|
|
return;
|
|
|
|
}
|
|
if (!postParams.TryGetValue("msg_signature", out string msg_signature))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack 'msg_signature' is null");
|
|
//return;
|
|
}
|
|
if (!postParams.TryGetValue("timestamp", out string timestamp))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack 'timestamp' is null");
|
|
return;
|
|
}
|
|
if (!postParams.TryGetValue("nonce", out string nonce))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack 'nonce' is null");
|
|
return;
|
|
}
|
|
if (httpCtx.httpRequest.Method == "GET")
|
|
{
|
|
var getParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Path);
|
|
getParams.TryGetValue("echostr", out string echostr);
|
|
var list = new List<string>();
|
|
list.Add(timestamp);
|
|
list.Add(nonce);
|
|
list.Add(HttpProxyPayServerUtils.GetServerConfig().wxPayToken);
|
|
list.Sort((x, y) => string.Compare(x, y));
|
|
var str = string.Join("", list);
|
|
var sig = HashHelper.SHA1String(str);
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack signature {0} sig {1}", signature, sig);
|
|
if(signature == sig)
|
|
{
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes(echostr) };
|
|
HttpServer.SendResponse(httpCtx);
|
|
return;
|
|
}
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("Verify fail") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
Tencent.WXBizMsgCrypt wxcpt = new Tencent.WXBizMsgCrypt(HttpProxyPayServerUtils.GetServerConfig().wxPayToken,
|
|
HttpProxyPayServerUtils.GetServerConfig().wxPayAesKey, HttpProxyPayServerUtils.GetServerConfig().wxAppId);
|
|
string sMsg = ""; //解析之后的明文
|
|
int wxret = 0;
|
|
JsonData reqJson = JsonMapper.ToObject(httpCtx.httpRequest.Content);
|
|
wxret = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, reqJson["Encrypt"].ToString(), ref sMsg);
|
|
if (wxret != 0)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack: Decrypt fail, ret: " + wxret);
|
|
return;
|
|
}
|
|
TraceLog.Trace("{0}", sMsg);
|
|
JsonData jsonData = JsonMapper.ToObject(sMsg);
|
|
JsonData MiniGame = jsonData["MiniGame"];
|
|
long CreateTime = long.Parse(jsonData["CreateTime"].ToString());
|
|
JsonData Payload = MiniGame["Payload"];
|
|
string PayEventSig = MiniGame["PayEventSig"].ToString();
|
|
bool IsMock = bool.Parse(MiniGame["IsMock"].ToString());
|
|
if (IsMock)
|
|
{
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
return;
|
|
}
|
|
|
|
//小程序解码验证
|
|
//var paySig = HashHelper.GetHMACSHA256(HttpProxyPayServerUtils.GetServerConfig().appkey, "event" + "&" + Payload);
|
|
//if (paySig != PayEventSig)
|
|
//{
|
|
// TraceLog.Error("HeroPayHttpHandler.HeroPayCallback sign error paySig:{0} PayEventSig:{1}", paySig, PayEventSig);
|
|
// httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.MiniPayError).ToString(), Content = Encoding.UTF8.GetBytes("internal error") };
|
|
// HttpServer.SendResponse(httpCtx);
|
|
// return;
|
|
//}
|
|
|
|
JObject PayJson = JObject.Parse(Payload.ToString());
|
|
TraceLog.Trace("GoodsInfo {0}", PayJson.ToString());
|
|
Payload = JsonMapper.ToObject(PayJson.ToString());
|
|
JsonData GoodsInfo = Payload["GoodsInfo"];
|
|
JsonData WeChatPayInfo = Payload["WeChatPayInfo"];
|
|
|
|
string orderId = Payload["OutTradeNo"].ToString();
|
|
|
|
string orderId3rd = WeChatPayInfo["TransactionId"].ToString();
|
|
string[] split = orderId.Split('-');
|
|
|
|
// uid-time-orderIdSeq-serverId-payitemId-payParam1-payParam2-paymentId-payUrlId
|
|
if (split.Length < 8)
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack invalid orderId {0}, need >= 8 params", orderId);
|
|
return;
|
|
}
|
|
|
|
int payUrlId = 0;
|
|
if (split.Length >= 9)
|
|
{
|
|
string strpayUrlId = split[8];
|
|
if (!string.IsNullOrEmpty(strpayUrlId))
|
|
{
|
|
if (!int.TryParse(strpayUrlId, out payUrlId))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack invalid payUrlId {0}", strpayUrlId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//WeChatPayInfo 中是微信第三方的订单号码
|
|
|
|
// 打印错误log方便查询所有请求
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack orderId {0}", orderId);
|
|
|
|
var svrData = HttpProxyPayServerUtils.GetHttpProxyServerData();
|
|
if (payUrlId > 0 && payUrlId != svrData.selfPayId)
|
|
{
|
|
if (payUrlId < svrData.payUrlCfg.Length && svrData.payUrlCfg[payUrlId] != null)
|
|
{
|
|
string url = svrData.payUrlCfg[payUrlId].url;
|
|
url = url +"?"+ "signature=" + signature+"×tamp="+timestamp +"&nonce="+nonce+"&encrypt_type=aes&msg_signature=" + msg_signature;
|
|
// 支付转发是正常情况,
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack orderId {0} trans to {1}", orderId, url);
|
|
|
|
HttpContent content = new StringContent(httpCtx.httpRequest.Content); ;
|
|
string ret = HttpUtils.HttpPost(url, content, out bool exception);
|
|
if (string.IsNullOrEmpty(ret))
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack trans fail, HttpPost return null");
|
|
}
|
|
else if (ret == "{\"ErrCode\":0,\"ErrMsg\":\"Success\"}")
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack trans succ, remote paysvr res 'SUCCESS'", ret);
|
|
// 转发给英雄的支付服务器
|
|
httpCtx.httpResponse = new HttpResponse { StatusCode = "0", Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}") };
|
|
HttpServer.SendResponse(httpCtx);
|
|
}
|
|
else
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack remote paysvr res fail {0}", ret);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack orderId {0} payUrlId {1} no url", orderId, payUrlId);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!long.TryParse(split[0], out long uid))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack invalid uid {0}", split[0]);
|
|
return;
|
|
}
|
|
|
|
if (!HttpContextCache.AddContext(httpCtx))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack add httpContext failed, ctx id {0}", httpCtx.id);
|
|
return;
|
|
}
|
|
|
|
//if (!int.TryParse(split[5], out int payParam1))
|
|
//{
|
|
// TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack invalid payParam1 {0}", split[5]);
|
|
|
|
// payParam1 = (int)PayUtils.GetParam1FromOrderId(orderId);
|
|
// if (payParam1 >= 0)
|
|
// {
|
|
// TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack invalid payParam1 {0} {1}", split[5], payParam1);
|
|
// return;
|
|
// }
|
|
//}
|
|
|
|
//if (!int.TryParse(split[6], out int payParam2))
|
|
//{
|
|
// TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack invalid payParam2 {0}", split[6]);
|
|
// return;
|
|
//}
|
|
|
|
//
|
|
int subPayType = (int)PayType.MiniPay;
|
|
string currency = null;
|
|
//
|
|
if (string.IsNullOrEmpty(currency))
|
|
{
|
|
currency = ((int)Currency.CNY).ToString(); // 对方空就填0, 后面好算账
|
|
}
|
|
|
|
// 环境
|
|
int sandbox = 0;
|
|
if (Payload.ContainsKey("Env"))
|
|
{
|
|
sandbox = int.Parse(Payload["Env"].ToString());
|
|
}
|
|
string amount = GoodsInfo["ActualPrice"].ToString();
|
|
|
|
/* 没有相关参数 只能在穿透里加
|
|
// 支付id不一致, 说明订单请求金额跟实际支付的金额不一致
|
|
string goodsId = GoodsInfoMap["ProductId"].ToString();
|
|
|
|
if (!goodsId.Equals(split[7]))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid paymentId, req {0} res {1}", goodsId, split[7]);
|
|
|
|
SSPayGoogleSuccessRes res = new SSPayGoogleSuccessRes { Uid = uid, PayType = (int)PayType.Hero };
|
|
res.Ret = (int)CSErrCode.PayMoneyNotEqual;
|
|
res.OrderId.SetString(orderId);
|
|
res.OrderId3rd.SetString(orderId3rd);
|
|
res.ItemID = int.Parse(split[4]);
|
|
res.PayParam1 = payParam1;
|
|
res.PayParam2 = payParam2;
|
|
res.PayTime3rd = Convert.ToInt64(CreateTime);
|
|
res.GmTestPay = false;
|
|
res.Currency.SetString(currency);
|
|
res.Amount = Convert.ToUInt32(amount * 100);
|
|
|
|
if (!uint.TryParse(split[3], out uint serverId))
|
|
{
|
|
TraceLog.Error("HeroPayHttpHandler.HeroPayCallback invalid uid {0}", split[0]);
|
|
return;
|
|
}
|
|
|
|
// 发给world处理, 注意serverId是gamesvr的id
|
|
var worldId = ServerIDUtils.GetLevel1ServerIDByType(serverId, (int)ServerType.World, 1);
|
|
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(worldId, (int)SSGameMsgID.PayGoogleSuccessRes, ref res, uid);
|
|
return;
|
|
}
|
|
*/
|
|
|
|
// 保存回调上下文
|
|
httpCtx.callbackArgs = new HeroPayCallbackArgs { orderId = orderId, status = HeroPayCallbackStatus.paySucc };
|
|
|
|
var req = new SSPayGoogleSuccessReq { Uid = uid, PayType = (int)PayType.MiniPay, CheckSuccess3rd = 1 };
|
|
req.HttpCtxId = httpCtx.id;
|
|
req.ItemID = int.Parse(split[4]);
|
|
req.PurchaseData.SetString(Payload.ToJson());
|
|
req.Signature.SetString(PayEventSig);
|
|
req.OrderId.SetString(orderId);
|
|
req.OrderId3rd.SetString(orderId3rd);
|
|
req.PayParam1 = 0;
|
|
req.PayParam2 = 0;
|
|
req.GmTestPay = false;
|
|
req.Amount = Convert.ToUInt32(amount);//分
|
|
req.Currency.SetString("CNY"); // 币种
|
|
req.SubPayType = subPayType;
|
|
req.PayTime3rd = Convert.ToInt64(CreateTime);
|
|
req.Sandbox = sandbox;
|
|
// 如果第三方时间解析不出来就用服务器当前时间
|
|
if (req.PayTime3rd == 0)
|
|
{
|
|
req.PayTime3rd = HttpProxyPayServerUtils.GetTimeSecond();
|
|
}
|
|
uint dbServerID = DBServerSelect.GetDBServerID(uid);
|
|
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(dbServerID, (int)SSGameMsgID.PayGoogleSuccessReq, ref req, uid);
|
|
|
|
}
|
|
}
|
|
}
|
|
|