ApiController.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. import Msg from '../utils/msg'; // 确保路径是正确的
  2. import {
  3. RefreshToken,
  4. PackageName,
  5. ProductId,
  6. IosUrl,
  7. SandboxIosUrl,
  8. Account,
  9. ClientSecret,
  10. ClientId
  11. } from '../config/thirdParams'
  12. import {
  13. compareVersions,
  14. generateOrderNumber,
  15. formatDate,
  16. getServerList
  17. } from '../utils/common'
  18. const CryptoJS = require("crypto-js");
  19. const Order = require('../model/OrderModel')
  20. const Server = require('../model/ServerModel')
  21. const Version = require('../model/VersionModel')
  22. const CDK = require("../model/CDK")
  23. const notice = require("../json/notice.json")
  24. const logger = require('../utils/log')
  25. const axios = require('axios');
  26. const googleCallPay = async (ctx) => {
  27. let ret = {
  28. code: 0,
  29. msg: '发货失败'
  30. }
  31. let data = ctx.request.body
  32. logger.info("pay callback params:", { "url": ctx.href, "params": data })
  33. const redisClient = ctx.redis.client;
  34. let access_token = await redisClient.get('access_token');
  35. if (!access_token) {
  36. console.log('请求api获取token')
  37. const apiData = {
  38. "grant_type": "refresh_token",
  39. "client_id": ClientId,
  40. "client_secret": ClientSecret,
  41. "refresh_token": RefreshToken
  42. }
  43. const response = await axios.post('https://accounts.google.com/o/oauth2/token', apiData, {
  44. headers: {
  45. 'Content-Type': 'application/x-www-form-urlencoded'
  46. }
  47. });
  48. logger.info("token params:", { "data": response.data, "params": apiData })
  49. if (!response.data.access_token) {
  50. return ret
  51. }
  52. access_token = response.data.access_token
  53. await redisClient.set('access_token', response.data.access_token);
  54. await redisClient.expire('access_token', 1800);
  55. }
  56. if (!access_token) {
  57. return ret;
  58. }
  59. let orderId = data.orderId
  60. let googleToken = data.purchaseToken
  61. let out_trade_no = ''
  62. const orderInfo = (await Order.getOrder(orderId))[0]
  63. if (!orderInfo) {
  64. logger.info(`订单${orderId}不存在`)
  65. ret.msg = `订单${orderId}不存在`
  66. return ret
  67. }
  68. if (orderInfo.status == 2) {
  69. logger.info(`订单${orderId}已经重复发货`)
  70. ret.code = 1
  71. ret.msg = `订单${orderId}已经重复发货`
  72. return ret
  73. }
  74. let url = await getServerList(orderInfo.server_id, 'default')
  75. if (!url) {
  76. logger.info(`区服id错误: serverId ${orderInfo.server_id}`)
  77. ret.msg = `区服id错误: serverId ${orderInfo.server_id}`
  78. return ret
  79. }
  80. const productId = ProductId + orderInfo.product_id
  81. let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}`
  82. let maxRetries = 5;
  83. let currentRetry = 0;
  84. let isCheck = false;
  85. // 使用 while 循环进行重试
  86. while (currentRetry < maxRetries) {
  87. try {
  88. // // 尝试执行的操作
  89. const googleRes = await axios.get(apiUrl, {
  90. headers: {
  91. 'Content-Type': 'application/x-www-form-urlencoded'
  92. }
  93. })
  94. console.log(googleRes.data)
  95. // 如果操作成功,退出循环
  96. if (googleRes.data.purchaseState == 0) {
  97. out_trade_no = googleRes.data.orderId
  98. isCheck = true
  99. break;
  100. }
  101. } catch (error) {
  102. // 如果操作失败,记录错误并继续尝试
  103. console.log(error)
  104. }
  105. currentRetry++;
  106. }
  107. if (!isCheck) {
  108. return ret;
  109. }
  110. Msg.connect(url, Account);
  111. let orgMemId = orderInfo.uid
  112. let orgOderId = orderId
  113. let orgProductId = orderInfo.product_id
  114. let orgProductPrice = orderInfo.amount
  115. // 在适当的时机,调用 CG_ASK_LOGIN 方法
  116. let params = `{"account":"${orgMemId}","order":"${orgOderId}","id":${orgProductId},"cnt":100,"money":${orgProductPrice}}`
  117. return new Promise((resolve) => {
  118. setTimeout(async () => {
  119. const send_res = Msg.CG_ASK_LOGIN(Account, 0, "", 'cn', 'CN', ctx.request.ip, params);
  120. if (!send_res) {
  121. resolve(ret);
  122. return;
  123. }
  124. let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}`
  125. console.log(acknowledgeUrl)
  126. const acknowledgeRes = await axios.post(acknowledgeUrl,
  127. {
  128. developerPayload: ""
  129. }
  130. ,
  131. {
  132. headers: {
  133. 'Content-Type': 'application/json'
  134. }
  135. })
  136. let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}`
  137. const consumeRes = await axios.post(consumeUrl,
  138. {
  139. developerPayload: ""
  140. }
  141. ,
  142. {
  143. headers: {
  144. 'Content-Type': 'application/json'
  145. }
  146. })
  147. logger.info("check :", { "orderId": orderId, "consumeRes": consumeRes, "acknowledgeRes": acknowledgeRes })
  148. const update_time = formatDate(new Date())
  149. const res = await Order.updateOrderStats(
  150. orderId,
  151. 2,
  152. out_trade_no,
  153. update_time
  154. );
  155. if (res.affectedRows <= 0) {
  156. logger.info(`订单${orderId} 发货失败`)
  157. ret.msg = '发货失败'
  158. resolve(ret);
  159. return;
  160. }
  161. ret.code = 1
  162. ret.msg = '发货成功'
  163. resolve(ret);
  164. }, 1000);
  165. });
  166. }
  167. const appleCallPay = async (ctx) => {
  168. let ret = {
  169. code: 0,
  170. msg: '发货失败'
  171. }
  172. let data = ctx.request.body
  173. logger.info("pay callback params:", { "url": ctx.href, "params": data })
  174. if (!data.purchaseToken || !data.orderId) {
  175. return ret;
  176. }
  177. let receipt_data = data.purchaseToken.replace(/ /g, '+')
  178. let orderId = data.orderId
  179. let maxRetries = 5;
  180. let currentRetry = 0;
  181. let isCheck = false;
  182. let out_trade_no = orderId
  183. // 使用 while 循环进行重试
  184. while (currentRetry < maxRetries) {
  185. try {
  186. const apiData = {
  187. "receipt-data": receipt_data,
  188. }
  189. const response = await axios.post(SandboxIosUrl, apiData, {
  190. headers: {
  191. 'Content-Type': 'application/json'
  192. }
  193. });
  194. logger.info(`苹果返回的状态:${response.data.status}`)
  195. // 如果操作成功,退出循环
  196. if (response.data.status == 0) {
  197. isCheck = true
  198. break;
  199. }
  200. } catch (error) {
  201. // 如果操作失败,记录错误并继续尝试
  202. console.log(error)
  203. }
  204. currentRetry++;
  205. }
  206. if (!isCheck) {
  207. logger.info(`票据验证失败!`)
  208. ret.msg = `票据验证失败!`
  209. return ret;
  210. }
  211. const orderInfo = (await Order.getOrder(orderId))[0]
  212. if (!orderInfo) {
  213. logger.info(`订单${orderId}不存在`)
  214. ret.msg = `订单${orderId}不存在`
  215. return ret
  216. }
  217. if (orderInfo.status == 2) {
  218. logger.info(`订单${orderId}已经重复发货`)
  219. ret.code = 1
  220. ret.msg = `订单${orderId}已经重复发货`
  221. return ret
  222. }
  223. let url = await getServerList(orderInfo.server_id, 'default')
  224. if (!url) {
  225. logger.info(`区服id错误: serverId ${orderInfo.server_id}`)
  226. ret.msg = `区服id错误: serverId ${orderInfo.server_id}`
  227. return ret
  228. }
  229. Msg.connect(url, Account);
  230. let orgMemId = orderInfo.uid
  231. let orgOderId = orderId
  232. let orgProductId = orderInfo.product_id
  233. let orgProductPrice = orderInfo.amount
  234. // 在适当的时机,调用 CG_ASK_LOGIN 方法
  235. let params = `{"account":"${orgMemId}","order":"${orgOderId}","id":${orgProductId},"cnt":100,"money":${orgProductPrice}}`
  236. return new Promise((resolve) => {
  237. setTimeout(async () => {
  238. logger.info(`订单${orderId}通知游戏发货开始`)
  239. const send_res = Msg.CG_ASK_LOGIN(Account, 0, "", 'cn', 'CN', ctx.request.ip, params);
  240. if (!send_res) {
  241. resolve(ret);
  242. return;
  243. }
  244. logger.info(`订单${orderId}通知游戏发货结束`)
  245. const update_time = formatDate(new Date())
  246. const res = await Order.updateOrderStats(
  247. orderId,
  248. 2,
  249. out_trade_no,
  250. update_time
  251. );
  252. if (res.affectedRows <= 0) {
  253. logger.info(`订单${orderId} 发货失败`)
  254. ret.msg = '发货失败'
  255. resolve(ret);
  256. return;
  257. }
  258. ret.code = 1
  259. ret.msg = '发货成功'
  260. resolve(ret);
  261. }, 1000);
  262. });
  263. }
  264. const testGoogleCallPay = async (ctx) => {
  265. let ret = {
  266. code: 0,
  267. msg: '消费失败'
  268. }
  269. let data = ctx.request.body
  270. logger.info("pay callback params:", { "url": ctx.href, "params": data })
  271. const redisClient = ctx.redis.client;
  272. let access_token = await redisClient.get('access_token');
  273. if (!access_token) {
  274. console.log('请求api获取token')
  275. const apiData = {
  276. "grant_type": "refresh_token",
  277. "client_id": ClientId,
  278. "client_secret": ClientSecret,
  279. "refresh_token": RefreshToken
  280. }
  281. const response = await axios.post('https://accounts.google.com/o/oauth2/token', apiData, {
  282. headers: {
  283. 'Content-Type': 'application/x-www-form-urlencoded'
  284. }
  285. });
  286. logger.info("token params:", { "data": response.data, "params": apiData })
  287. if (!response.data.access_token) {
  288. return ret
  289. }
  290. access_token = response.data.access_token
  291. await redisClient.set('access_token', response.data.access_token);
  292. await redisClient.expire('access_token', 1800);
  293. }
  294. if (!access_token) {
  295. return ret;
  296. }
  297. let googleToken = data.purchaseToken
  298. let product_id = data.orderId
  299. const productId = ProductId + product_id
  300. let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}`
  301. let maxRetries = 5;
  302. let currentRetry = 0;
  303. let isCheck = false;
  304. // 使用 while 循环进行重试
  305. while (currentRetry < maxRetries) {
  306. try {
  307. // // 尝试执行的操作
  308. const googleRes = await axios.get(apiUrl, {
  309. headers: {
  310. 'Content-Type': 'application/x-www-form-urlencoded'
  311. }
  312. })
  313. console.log(googleRes.data)
  314. // 如果操作成功,退出循环
  315. if (googleRes.data.purchaseState == 0) {
  316. isCheck = true
  317. break;
  318. }
  319. } catch (error) {
  320. // 如果操作失败,记录错误并继续尝试
  321. console.log(error)
  322. }
  323. currentRetry++;
  324. }
  325. if (!isCheck) {
  326. return ret;
  327. }
  328. return new Promise(async (resolve) => {
  329. let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}`
  330. console.log(acknowledgeUrl)
  331. const acknowledgeRes = await axios.post(acknowledgeUrl,
  332. {
  333. developerPayload: ""
  334. }
  335. ,
  336. {
  337. headers: {
  338. 'Content-Type': 'application/json'
  339. }
  340. })
  341. let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}`
  342. const consumeRes = await axios.post(consumeUrl,
  343. {
  344. developerPayload: ""
  345. }
  346. ,
  347. {
  348. headers: {
  349. 'Content-Type': 'application/json'
  350. }
  351. })
  352. ret.code = 1
  353. ret.msg = '发货成功'
  354. resolve(ret);
  355. });
  356. }
  357. const checkVersion = async (ctx) => {
  358. let ret = {
  359. code: 0,
  360. msg: '无需更新',
  361. url: '',
  362. }
  363. let data = ctx.request.body
  364. let version = data.version
  365. let tag = data.tag || 'default'
  366. logger.info("checkVersion params:", { "url": ctx.href, "params": data })
  367. const versionInfo = (await Version.getGameVersion(tag))[0]
  368. if (!versionInfo) {
  369. return ret
  370. }
  371. if (compareVersions(versionInfo.version, version) === 1) {
  372. if (versionInfo.download_url) {
  373. ret.code = 1
  374. ret.msg = '需要更新'
  375. ret.url = versionInfo.download_url
  376. }
  377. }
  378. return ret
  379. }
  380. //验证账号
  381. const checkUserToken = async (ctx) => {
  382. }
  383. class ApiController {
  384. async createOrder(ctx) {
  385. let {
  386. uid,
  387. level,
  388. amount,
  389. role_id,
  390. role_name,
  391. product_id,
  392. server_id
  393. } = ctx.request.body
  394. logger.info("create params:", { "params": ctx.request.body })
  395. if (!product_id || !server_id || !role_name || !role_id || !amount || !uid) {
  396. ctx.body = { code: -1, message: '参数错误,创建订单失败!!', data: '' }
  397. return
  398. }
  399. const orderId = generateOrderNumber(); // 生成一个长度为8的订单号
  400. const create_time = formatDate(new Date())
  401. const res = await Order.createOrder(
  402. orderId,
  403. uid,
  404. level,
  405. amount,
  406. role_id,
  407. role_name,
  408. product_id,
  409. server_id,
  410. create_time
  411. );
  412. if (res.affectedRows > 0) {
  413. ctx.body = { code: 0, message: '创建订单成功', data: orderId }
  414. } else {
  415. ctx.body = { code: -1, message: '创建订单失败', data: '' }
  416. }
  417. logger.info("创建订单返回结果:", { "params": ctx.body })
  418. }
  419. async checkUserToken(ctx) {
  420. // const result = await checkUserToken(ctx);
  421. // let data = { "status": false, "sign": "" }
  422. // if (result) {
  423. // data.status = true
  424. // data.sign = result
  425. // }
  426. // ctx.body = data
  427. }
  428. async callPay(ctx) {
  429. let data = ctx.request.body
  430. let platform = data.platform || 'google'
  431. switch (platform) {
  432. case 'google':
  433. var result = await googleCallPay(ctx)
  434. console.log('发货结果', result)
  435. ctx.body = result
  436. break;
  437. case 'apple':
  438. var result = await appleCallPay(ctx)
  439. console.log('发货结果', result)
  440. ctx.body = result
  441. break;
  442. // case 'testGoogle':
  443. // var result = await testGoogleCallPay(ctx)
  444. // console.log('发货结果', result)
  445. // ctx.body = result
  446. // break;
  447. default:
  448. ctx.body = {
  449. code: 0,
  450. msg: '渠道错误'
  451. }
  452. }
  453. }
  454. async checkVersion(ctx) {
  455. var result = await checkVersion(ctx)
  456. console.log('校验版本', result)
  457. ctx.body = result
  458. }
  459. async getServerList(ctx) {
  460. let tag = ctx.query.tag || 'default'
  461. const servers = (await Server.getServerList(tag))
  462. ctx.body = servers
  463. }
  464. async getAllServerList(ctx) {
  465. let tag = ctx.query.tag || 'default'
  466. const servers = (await Server.getAllServerList(tag))
  467. ctx.body = servers
  468. }
  469. async enterServer(ctx) {
  470. let ret = {
  471. code: 0,
  472. msg: '请求失败'
  473. }
  474. let {
  475. uid,
  476. server_id
  477. } = ctx.request.body
  478. if (!uid || !server_id) {
  479. ctx.body = ret
  480. return
  481. }
  482. await ctx.redis.client.set(`enter_sever_${uid}`, server_id);
  483. ctx.body = {
  484. code: 1,
  485. msg: '请求成功'
  486. }
  487. }
  488. async getLastServerList(ctx) {
  489. let {
  490. uid,
  491. } = ctx.request.body
  492. const tag = ctx.query.tag || 'default'
  493. const enter_server = await ctx.redis.client.get(`enter_sever_${uid}`);
  494. let isNewAccount = 1
  495. let serverInfo = null
  496. if (enter_server) {
  497. serverInfo = (await Server.getServerListById(tag, enter_server))[0]
  498. isNewAccount = 0
  499. } else {
  500. const servers = (await Server.getServerList(tag))
  501. serverInfo = servers[servers.length - 1]
  502. }
  503. let data = {
  504. "channel": "Thailand", //渠道固定
  505. "minSid": 1, //最小服务器
  506. "maxSid": 10, //最大服务器 这里会控制 服务器列表显示的数量
  507. "isNewAccount": isNewAccount, //1为新号 会弹出用户协议
  508. //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
  509. "sid": serverInfo.id || 1,
  510. "id": serverInfo.id || 1,
  511. "name": serverInfo.name || "1区",
  512. "server": serverInfo.ip ? `ws://${serverInfo.ip}:${serverInfo.port}` : "",
  513. "status": serverInfo.status || 0,
  514. }
  515. ctx.body = data
  516. }
  517. async getNotice(ctx) {
  518. ctx.body = notice
  519. }
  520. async genCDK(ctx) {
  521. /*
  522. data = {
  523. cnt : number -- 生成数量
  524. useCnt : number -- 当前批次最大使用数量
  525. serverList : string -- 区服列表Json字符串
  526. itemList : string -- CDK对应物品列表Json字符串
  527. }
  528. */
  529. let data = ctx.request.body
  530. await CDK.genCDK(ctx, data.cnt, data.useCnt, data.serverList, data.itemList)
  531. ctx.body = {
  532. code: 0,
  533. msg: 'success'
  534. }
  535. return
  536. }
  537. async getCDK(ctx) {
  538. let data = ctx.request.body
  539. let ret = await CDK.getCDK(ctx, data.batch)
  540. if (ret.length <= 0) {
  541. ctx.body = {
  542. code: 1,
  543. msg: "batch invalid"
  544. }
  545. return
  546. }
  547. ctx.body = {
  548. code: 0,
  549. msg: ret
  550. }
  551. }
  552. async useCDK(ctx) {
  553. let data = ctx.request.body
  554. let url = await getServerList(data.serverId, 'default')
  555. if (!url) {
  556. ctx.body = {
  557. code: 1,
  558. msg: `区服id错误: serverId ${data.serverId}`
  559. }
  560. return
  561. }
  562. let param:string = ""
  563. if (data.code.length == 10) {
  564. let batchInfo = await CDK.getCDKItemList(ctx,data.code)
  565. if (batchInfo.length <= 0) {
  566. ctx.body = {
  567. code: 1,
  568. msg: "invalid code"
  569. }
  570. }
  571. let ret = await CDK.checkCDK(ctx, data.code, data.serverId)
  572. if (ret != "success") {
  573. ctx.body = {
  574. code: 1,
  575. msg: ret
  576. }
  577. return
  578. }
  579. param = JSON.stringify({
  580. type:"UseCDK",
  581. batchInfo:batchInfo
  582. })
  583. }else{
  584. // 固定码
  585. param = JSON.stringify({
  586. code:data.code,
  587. type:"UseFixCDK"
  588. })
  589. }
  590. // 测试是否可以调用过去
  591. // 通知给服务器,发放道具
  592. // "ws://43.143.193.23:18192"
  593. Msg.connect(url, Account);
  594. new Promise((resolve) => {
  595. setTimeout(async () => {
  596. Msg.CG_TEST_PROTO(data.account,param)
  597. }, 500);
  598. });
  599. ctx.body = {
  600. code: 0,
  601. msg: "success"
  602. }
  603. }
  604. async validCDK (ctx) {
  605. let data = ctx.request.body
  606. if (data.code.length == 10) {
  607. let ret = await CDK.useCDK(ctx, data.code)
  608. if (ret != "success") {
  609. ctx.body = {
  610. code: 1,
  611. msg: ret
  612. }
  613. return
  614. }
  615. }
  616. ctx.body = {
  617. code: 0,
  618. msg: "success"
  619. }
  620. }
  621. }
  622. module.exports = new ApiController()