import Msg from '../utils/msg'; // 确保路径是正确的 import { RefreshToken, PackageName, ProductId, IosUrl, SandboxIosUrl, Account, ClientSecret, ClientId } from '../config/thirdParams' import { compareVersions, generateOrderNumber, formatDate, getServerList } from '../utils/common' const CryptoJS = require("crypto-js"); const Order = require('../model/OrderModel') const Server = require('../model/ServerModel') const Version = require('../model/VersionModel') const CDK = require("../model/CDK") const notice = require("../json/notice.json") const logger = require('../utils/log') const axios = require('axios'); const googleCallPay = async (ctx) => { let ret = { code: 0, msg: '发货失败' } let data = ctx.request.body logger.info("pay callback params:", { "url": ctx.href, "params": data }) const redisClient = ctx.redis.client; let access_token = await redisClient.get('access_token'); if (!access_token) { console.log('请求api获取token') const apiData = { "grant_type": "refresh_token", "client_id": ClientId, "client_secret": ClientSecret, "refresh_token": RefreshToken } const response = await axios.post('https://accounts.google.com/o/oauth2/token', apiData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); logger.info("token params:", { "data": response.data, "params": apiData }) if (!response.data.access_token) { return ret } access_token = response.data.access_token await redisClient.set('access_token', response.data.access_token); await redisClient.expire('access_token', 1800); } if (!access_token) { return ret; } let orderId = data.orderId let googleToken = data.purchaseToken let out_trade_no = '' 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(orderInfo.server_id, 'default') if (!url) { logger.info(`区服id错误: serverId ${orderInfo.server_id}`) ret.msg = `区服id错误: serverId ${orderInfo.server_id}` return ret } const productId = ProductId + orderInfo.product_id let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}` let maxRetries = 5; let currentRetry = 0; let isCheck = false; // 使用 while 循环进行重试 while (currentRetry < maxRetries) { try { // // 尝试执行的操作 const googleRes = await axios.get(apiUrl, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) console.log(googleRes.data) // 如果操作成功,退出循环 if (googleRes.data.purchaseState == 0) { out_trade_no = googleRes.data.orderId isCheck = true break; } } catch (error) { // 如果操作失败,记录错误并继续尝试 console.log(error) } currentRetry++; } if (!isCheck) { return ret; } Msg.connect(url, Account); let orgMemId = orderInfo.uid let orgOderId = orderId let orgProductId = orderInfo.product_id let orgProductPrice = orderInfo.amount // 在适当的时机,调用 CG_ASK_LOGIN 方法 let params = `{"account":"${orgMemId}","order":"${orgOderId}","id":${orgProductId},"cnt":100,"money":${orgProductPrice}}` return new Promise((resolve) => { setTimeout(async () => { const send_res = Msg.CG_ASK_LOGIN(Account, 0, "", 'cn', 'CN', ctx.request.ip, params); if (!send_res) { resolve(ret); return; } let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}` console.log(acknowledgeUrl) const acknowledgeRes = await axios.post(acknowledgeUrl, { developerPayload: "" } , { headers: { 'Content-Type': 'application/json' } }) let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}` const consumeRes = await axios.post(consumeUrl, { developerPayload: "" } , { headers: { 'Content-Type': 'application/json' } }) logger.info("check :", { "orderId": orderId, "consumeRes": consumeRes, "acknowledgeRes": acknowledgeRes }) 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 appleCallPay = async (ctx) => { let ret = { code: 0, msg: '发货失败' } let data = ctx.request.body logger.info("pay callback params:", { "url": ctx.href, "params": data }) if (!data.purchaseToken || !data.orderId) { return ret; } let receipt_data = data.purchaseToken.replace(/ /g, '+') let orderId = data.orderId let maxRetries = 5; let currentRetry = 0; let isCheck = false; let out_trade_no = orderId // 使用 while 循环进行重试 while (currentRetry < maxRetries) { try { const apiData = { "receipt-data": receipt_data, } const response = await axios.post(SandboxIosUrl, apiData, { headers: { 'Content-Type': 'application/json' } }); logger.info(`苹果返回的状态:${response.data.status}`) // 如果操作成功,退出循环 if (response.data.status == 0) { isCheck = true break; } } catch (error) { // 如果操作失败,记录错误并继续尝试 console.log(error) } currentRetry++; } if (!isCheck) { logger.info(`票据验证失败!`) ret.msg = `票据验证失败!` return ret; } 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(orderInfo.server_id, 'default') if (!url) { logger.info(`区服id错误: serverId ${orderInfo.server_id}`) ret.msg = `区服id错误: serverId ${orderInfo.server_id}` return ret } Msg.connect(url, Account); let orgMemId = orderInfo.uid let orgOderId = orderId let orgProductId = orderInfo.product_id let orgProductPrice = orderInfo.amount // 在适当的时机,调用 CG_ASK_LOGIN 方法 let params = `{"account":"${orgMemId}","order":"${orgOderId}","id":${orgProductId},"cnt":100,"money":${orgProductPrice}}` return new Promise((resolve) => { setTimeout(async () => { logger.info(`订单${orderId}通知游戏发货开始`) const send_res = Msg.CG_ASK_LOGIN(Account, 0, "", 'cn', 'CN', ctx.request.ip, params); if (!send_res) { resolve(ret); return; } logger.info(`订单${orderId}通知游戏发货结束`) 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 testGoogleCallPay = async (ctx) => { let ret = { code: 0, msg: '消费失败' } let data = ctx.request.body logger.info("pay callback params:", { "url": ctx.href, "params": data }) const redisClient = ctx.redis.client; let access_token = await redisClient.get('access_token'); if (!access_token) { console.log('请求api获取token') const apiData = { "grant_type": "refresh_token", "client_id": ClientId, "client_secret": ClientSecret, "refresh_token": RefreshToken } const response = await axios.post('https://accounts.google.com/o/oauth2/token', apiData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); logger.info("token params:", { "data": response.data, "params": apiData }) if (!response.data.access_token) { return ret } access_token = response.data.access_token await redisClient.set('access_token', response.data.access_token); await redisClient.expire('access_token', 1800); } if (!access_token) { return ret; } let googleToken = data.purchaseToken let product_id = data.orderId const productId = ProductId + product_id let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}` let maxRetries = 5; let currentRetry = 0; let isCheck = false; // 使用 while 循环进行重试 while (currentRetry < maxRetries) { try { // // 尝试执行的操作 const googleRes = await axios.get(apiUrl, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) console.log(googleRes.data) // 如果操作成功,退出循环 if (googleRes.data.purchaseState == 0) { isCheck = true break; } } catch (error) { // 如果操作失败,记录错误并继续尝试 console.log(error) } currentRetry++; } if (!isCheck) { return ret; } return new Promise(async (resolve) => { let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}` console.log(acknowledgeUrl) const acknowledgeRes = await axios.post(acknowledgeUrl, { developerPayload: "" } , { headers: { 'Content-Type': 'application/json' } }) let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}` const consumeRes = await axios.post(consumeUrl, { developerPayload: "" } , { headers: { 'Content-Type': 'application/json' } }) ret.code = 1 ret.msg = '发货成功' resolve(ret); }); } const checkVersion = async (ctx) => { let ret = { code: 0, msg: '无需更新', url: '', } let data = ctx.request.body let version = data.version let tag = data.tag || 'default' logger.info("checkVersion params:", { "url": ctx.href, "params": data }) const versionInfo = (await Version.getGameVersion(tag))[0] if (!versionInfo) { return ret } if (compareVersions(versionInfo.version, version) === 1) { if (versionInfo.download_url) { ret.code = 1 ret.msg = '需要更新' ret.url = versionInfo.download_url } } return ret } //验证账号 const checkUserToken = async (ctx) => { } class ApiController { async createOrder(ctx) { let { uid, level, amount, role_id, role_name, product_id, server_id } = ctx.request.body logger.info("create params:", { "params": ctx.request.body }) if (!product_id || !server_id || !role_name || !role_id || !amount || !uid) { ctx.body = { code: -1, message: '参数错误,创建订单失败!!', data: '' } return } const orderId = generateOrderNumber(); // 生成一个长度为8的订单号 const create_time = formatDate(new Date()) const res = await Order.createOrder( orderId, uid, level, amount, role_id, role_name, product_id, server_id, create_time ); if (res.affectedRows > 0) { ctx.body = { code: 0, message: '创建订单成功', data: orderId } } else { ctx.body = { code: -1, message: '创建订单失败', data: '' } } logger.info("创建订单返回结果:", { "params": ctx.body }) } async checkUserToken(ctx) { // const result = await checkUserToken(ctx); // let data = { "status": false, "sign": "" } // if (result) { // data.status = true // data.sign = result // } // ctx.body = data } async callPay(ctx) { let data = ctx.request.body let platform = data.platform || 'google' switch (platform) { case 'google': var result = await googleCallPay(ctx) console.log('发货结果', result) ctx.body = result break; case 'apple': var result = await appleCallPay(ctx) console.log('发货结果', result) ctx.body = result break; // case 'testGoogle': // var result = await testGoogleCallPay(ctx) // console.log('发货结果', result) // ctx.body = result // break; default: ctx.body = { code: 0, msg: '渠道错误' } } } async checkVersion(ctx) { var result = await checkVersion(ctx) console.log('校验版本', result) ctx.body = result } async getServerList(ctx) { let tag = ctx.query.tag || 'default' const servers = (await Server.getServerList(tag)) ctx.body = servers } async getAllServerList(ctx) { let tag = ctx.query.tag || 'default' const servers = (await Server.getAllServerList(tag)) ctx.body = servers } async enterServer(ctx) { let ret = { code: 0, msg: '请求失败' } let { uid, server_id } = ctx.request.body if (!uid || !server_id) { ctx.body = ret return } await ctx.redis.client.set(`enter_sever_${uid}`, server_id); ctx.body = { code: 1, msg: '请求成功' } } async getLastServerList(ctx) { let { uid, } = ctx.request.body const tag = ctx.query.tag || 'default' const enter_server = await ctx.redis.client.get(`enter_sever_${uid}`); let isNewAccount = 1 let serverInfo = null if (enter_server) { serverInfo = (await Server.getServerListById(tag, enter_server))[0] isNewAccount = 0 } else { const servers = (await Server.getServerList(tag)) serverInfo = servers[servers.length - 1] } let data = { "channel": "Thailand", //渠道固定 "minSid": 1, //最小服务器 "maxSid": 10, //最大服务器 这里会控制 服务器列表显示的数量 "isNewAccount": isNewAccount, //1为新号 会弹出用户协议 //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区) "sid": serverInfo.id || 1, "id": serverInfo.id || 1, "name": serverInfo.name || "1区", "server": serverInfo.ip ? `ws://${serverInfo.ip}:${serverInfo.port}` : "", "status": serverInfo.status || 0, } ctx.body = data } async getNotice(ctx) { ctx.body = notice } async genCDK(ctx) { /* data = { cnt : number -- 生成数量 useCnt : number -- 当前批次最大使用数量 serverList : string -- 区服列表Json字符串 itemList : string -- CDK对应物品列表Json字符串 } */ let data = ctx.request.body await CDK.genCDK(ctx, data.cnt, data.useCnt, data.serverList, data.itemList) ctx.body = { code: 0, msg: 'success' } return } async getCDK(ctx) { let data = ctx.request.body let ret = await CDK.getCDK(ctx, data.batch) if (ret.length <= 0) { ctx.body = { code: 1, msg: "batch invalid" } return } ctx.body = { code: 0, msg: ret } } async useCDK(ctx) { let data = ctx.request.body let url = await getServerList(data.serverId, 'default') if (!url) { ctx.body = { code: 1, msg: `区服id错误: serverId ${data.serverId}` } return } let param:string = "" if (data.code.length == 10) { let batchInfo = await CDK.getCDKItemList(ctx,data.code) if (batchInfo.length <= 0) { ctx.body = { code: 1, msg: "invalid code" } } let ret = await CDK.checkCDK(ctx, data.code, data.serverId) if (ret != "success") { ctx.body = { code: 1, msg: ret } return } param = JSON.stringify({ type:"UseCDK", batchInfo:batchInfo }) }else{ // 固定码 param = JSON.stringify({ code:data.code, type:"UseFixCDK" }) } // 测试是否可以调用过去 // 通知给服务器,发放道具 // "ws://43.143.193.23:18192" Msg.connect(url, Account); new Promise((resolve) => { setTimeout(async () => { Msg.CG_TEST_PROTO(data.account,param) }, 500); }); ctx.body = { code: 0, msg: "success" } } async validCDK (ctx) { let data = ctx.request.body if (data.code.length == 10) { let ret = await CDK.useCDK(ctx, data.code) if (ret != "success") { ctx.body = { code: 1, msg: ret } return } } ctx.body = { code: 0, msg: "success" } } } module.exports = new ApiController()