flowerpig 1 год назад
Родитель
Сommit
c145e59ee9

Разница между файлами не показана из-за своего большого размера
+ 3734 - 1
webServer/package-lock.json


+ 3 - 1
webServer/package.json

@@ -24,11 +24,13 @@
     "mysql2": "^3.11.0",
     "node-schedule": "^2.1.1",
     "redis": "^4.7.0",
+    "ts-md5": "^1.3.1",
     "typescript": "^5.5.4",
     "utf-8-validate": "^6.0.3",
     "winston": "^3.13.0",
     "winston-daily-rotate-file": "^5.0.0",
-    "ws": "^8.16.0"
+    "ws": "^8.16.0",
+    "xml2js": "^0.6.2"
   },
   "devDependencies": {
     "terser-webpack-plugin": "^5.3.10",

+ 142 - 0
webServer/src/controller/ApiController.ts

@@ -1,4 +1,6 @@
 import Msg from '../utils/msg'; // 确保路径是正确的
+import QuickAsy from '../utils/quickAsy';
+import { parseString } from 'xml2js';
 import {
     RefreshToken,
     PackageName,
@@ -386,6 +388,114 @@ const appleCallPay = async (ctx) => {
     });
 }
 
+//qucik发货
+//扩展参数格式为${serverId};${productId}
+const CallPayQucik = async (ctx) => {
+    let ret = {
+        code: 0,
+        msg: '发货失败'
+    }
+    //sdk参数
+    let md5Key = "gaug5awijz5kdqfkzdmikjfrt4jbpv5f"
+    let callbackKey = "19404462610366331550315911887318"
+
+    let data = ctx.request.body
+    logger.info("qucik 回调参数",{"data":data})
+    let md5Sign = data.md5Sign
+    let ntData = data.nt_data
+    let verifySignData = QuickAsy.getSign(data,md5Key)
+    if(verifySignData != md5Sign){
+        logger.error("quick 调用md5Sign错误",{'$verifySignData':verifySignData,'md5Sign':md5Sign})
+        return ret
+    }
+    let xmlData = QuickAsy.decode(ntData,callbackKey)
+    const result = await new Promise((resolve, reject) => {
+          parseString(xmlData, (err, result) => {
+            if (err) {
+              return reject(err);
+            }
+            resolve(result);
+          });
+        });
+    const message = result.quicksdk_message.message[0];
+    const channel = message.channel[0];
+    const orgMemId = message.channel_uid[0];
+    const channelOrder = message.channel_order[0];
+    const orderId = message.game_order[0];//cp单号
+    const orderNo = message.order_no[0];//sdk订单号
+    const payTime = message.pay_time[0];
+    const orgProductPrice = message.amount[0]; //充值成功的金额
+    const status = message.status[0];//0成功
+    const extrasParams = message.extras_params[0];
+    if(status == 1){
+        return
+    }
+    let extrasArr = extrasParams.split(";")
+    let serverId = extrasArr[0] //区服id
+    let orgProductId = extrasArr[1]//商品id
+
+
+    const orderInfo = (await Order.getOrder(orderId))[0]
+
+    if (!orderInfo) {
+        logger.info(`订单${orderId}不存在`)
+        ret.msg = `订单${orderId}不存在`
+        return ret
+    }
+
+    if (orderInfo.status == 2) {
+        logger.info(`订单${orderId}已经重复发货`)
+        ret.code = 1
+        ret.msg = `订单${orderId}已经重复发货`
+        return ret
+    }
+    let url = await getServerList(serverId, 'default')
+    if (!url) {
+        logger.info(`区服id错误: serverId ${serverId}`)
+        ret.msg = `区服id错误: serverId ${serverId}`
+        return ret
+    }
+    return ///=========
+   //发货
+    // 使用 Msg 类的 connect 方法连接到 WebSocket 服务器
+    let sendMsg = new Msg()
+    sendMsg.connect(url, Account);
+    logger.info(`订单${orderId} ${url}`)
+    // 在适当的时机,调用 CG_ASK_LOGIN 方法
+    let params = `{"account":"${orgMemId}","order":"${orgOderId}","id":${orgProductId},"cnt":100,"money":${orgProductPrice}}`
+    return new Promise((resolve) => {
+        setTimeout(async () => {
+            console.log("这个消息将在3秒后打印出来");
+            const send_res = sendMsg.CG_ASK_LOGIN(Account, 0, "", 'cn', 'CN', ctx.request.ip, params);
+            if (!send_res) {
+                resolve(ret);
+                return;
+            }
+
+            const update_time = formatDate(new Date())
+            const res = await Order.updateOrderStats(
+                orderId,
+                2,
+                out_trade_no,
+                update_time
+            );
+
+            if (res.affectedRows <= 0) {
+                logger.info(`订单${orderId} 发货失败`)
+                ret.msg = '发货失败'
+                resolve(ret);
+                return;
+            }
+
+            ret.code = 1
+            ret.msg = '发货成功'
+            resolve(ret);
+
+        }, 1000);
+    });
+
+}
+
 const CallPay360 = async (ctx) => {
     let ret = {
         code: 0,
@@ -629,6 +739,7 @@ const checkVersion = async (ctx) => {
 const checkUserToken = async (ctx) => {
 }
 
+
 class ApiController {
     async createOrder(ctx) {
         let {
@@ -681,7 +792,33 @@ class ApiController {
         // ctx.body = data
     }
 
+    //quick登陆
+    async quickUserLogin(ctx){
+        //sdk参数
+        let productCode = "68402796563185068148745974229755"
+
+        let data = ctx.request.body
+        let uid = data.uid
+        let token = data.token
+        let reqUrl = "http://checkuser.quickapi.net/v2/checkUserInfo?token="+token+"&uid="+uid+"product_code="+productCode
+        logger.info("quick登陆验证请求",{'params':data,'url':reqUrl})
+        const res = await axios.get(reqUrl)
+        logger.info("quick req",{"res":res.data})
+        if(res.data == '1'){
+            ctx.body = {
+                    code: 200,
+                    msg: 'success'
+                }
+        }else{
+             ctx.body = {
+                    code: 0,
+                    msg: 'fail'
+                }
+        }
+    }
+
     async callPay(ctx) {
+        console.log(234234234)
         let data = ctx.request.body
         let platform = '360'  // 默认360
 
@@ -714,6 +851,11 @@ class ApiController {
             // console.log('发货结果', result)
             // ctx.body = result
             // break;
+            case 'quick':
+                var result = await CallPayQucik(ctx)
+                console.log('发货结果', result)
+                ctx.body = result
+                break;
             default:
                 ctx.body = {
                     code: 0,

+ 3 - 0
webServer/src/router/index.ts

@@ -10,6 +10,9 @@ router.post('/callback', ApiController.callPay)
 //登陆验证
 router.post('/checkUserToken', ApiController.checkUserToken)
 
+//quick登陆
+router.post('/quickUserLogin',ApiController.quickUserLogin)
+
 //获取区服列表
 router.get('/serverList', ApiController.getServerList)
 

+ 120 - 0
webServer/src/utils/quickAsy.ts

@@ -0,0 +1,120 @@
+import { parseString } from 'xml2js';
+import { Md5 } from 'ts-md5';
+
+export default class QuickAsy {
+
+    /**
+     * 解码函数
+     * @param strEncode 加密字符串
+     * @param keys 解密密钥 (在游戏中通常是 callback_key)
+     * @returns 解码后的字符串
+     */
+    static decode(strEncode: string, keys: string): string {
+        if (!strEncode) {
+            return strEncode;
+        }
+
+        const list = strEncode.match(/\d+/g);
+        if (list && list.length > 0) {
+            const keyBytes = QuickAsy.getBytes(keys);
+            const data: number[] = [];
+
+            for (let i = 0; i < list.length; i++) {
+                const keyVar = keyBytes[i % keyBytes.length];
+                data[i] = parseInt(list[i]) - (0xff & keyVar);
+            }
+
+            return QuickAsy.toStr(data);
+        } else {
+            return strEncode;
+        }
+    }
+
+    /**
+     * 生成游戏同步签名
+     * @param params 参数对象
+     * @param callbackKey 回调密钥
+     * @returns 签名字符串
+     */
+    static getSign(params: { nt_data: string, sign: string }, callbackKey: string): string {
+        return QuickAsy.md5(params.nt_data + params.sign + callbackKey);
+    }
+
+    /**
+     * 替换MD5
+     * @param md5 传入的MD5值
+     * @returns 替换后的MD5值
+     */
+    static replaceMD5(md5: string): string {
+        md5 = md5.toLowerCase();
+        const bytes = QuickAsy.getBytes(md5);
+        const len = bytes.length;
+
+        if (len >= 23) {
+            let change = bytes[1];
+            bytes[1] = bytes[13];
+            bytes[13] = change;
+
+            let change2 = bytes[5];
+            bytes[5] = bytes[17];
+            bytes[17] = change2;
+
+            let change3 = bytes[7];
+            bytes[7] = bytes[23];
+            bytes[23] = change3;
+        } else {
+            return md5;
+        }
+
+        return QuickAsy.toStr(bytes);
+    }
+
+    /**
+     * 将字符串转换为字节数组
+     * @param string 字符串
+     * @returns 字节数组
+     */
+    private static getBytes(string: string): number[] {
+        const bytes: number[] = [];
+        for (let i = 0; i < string.length; i++) {
+            bytes.push(string.charCodeAt(i));
+        }
+        return bytes;
+    }
+
+    /**
+     * 将字节数组转换为字符串
+     * @param bytes 字节数组
+     * @returns 转换后的字符串
+     */
+    private static toStr(bytes: number[]): string {
+        return String.fromCharCode(...bytes);
+    }
+
+    /**
+     * 计算 MD5 哈希值 (假设我们有一个 md5 函数)
+     * @param str 输入字符串
+     * @returns MD5 哈希值
+     */
+    private static md5(str: string): string {
+        // 假设有一个全局的 `md5` 函数可以使用
+        return Md5.hashStr(str);
+    }
+
+    static parseXmlToObject<T>(xml: string): T {
+    let result: T;
+    parseString(xml, (err, parsedResult) => {
+        if (err) {
+            console.error('Error parsing XML:', err);
+            throw err;
+        }
+        result = parsedResult as T;
+    });
+
+    // 由于 parseString 是异步回调的,所以需要在这里做等待处理
+    if (!result) {
+        throw new Error('Parsing failed');
+    }
+    return result;
+    }
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов