ApiController.ts 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
  1. import Msg from "../utils/msg";
  2. import {
  3. RefreshToken,
  4. PackageName,
  5. ProductId,
  6. IosUrl,
  7. Account,
  8. ClientSecret,
  9. ClientId,
  10. ORDER_SIGN_KEY,
  11. } from "../config/thirdParams";
  12. import {
  13. generateOrderNumber,
  14. formatDate,
  15. getServerList,
  16. getClientIp, getServerAddr,
  17. } from "../utils/common";
  18. import {PaymentHelper} from "../utils/PaymentHelper";
  19. import {SignatureVerifier} from "../utils/SignatureVerifier";
  20. import {ChannelConfigManager} from "../utils/ChannelConfigManager";
  21. import {getRoleInfoByUidAndServerId} from "../mongo/mongodb";
  22. // platform内存缓存,key: ip:device_no,TTL 5分钟
  23. const platformCache = new Map<string, {value: string; expireAt: number}>();
  24. const PLATFORM_CACHE_TTL = 60 * 1000; // 缓存1分钟
  25. function setPlatformCache(ip: string, platform: string) {
  26. platformCache.set(ip, {value: platform, expireAt: Date.now() + PLATFORM_CACHE_TTL});
  27. }
  28. function getPlatformCache(ip: string): string {
  29. const entry = platformCache.get(ip);
  30. if (!entry) return '';
  31. if (Date.now() > entry.expireAt) {
  32. platformCache.delete(ip);
  33. return '';
  34. }
  35. return entry.value;
  36. }
  37. // 导入依赖
  38. const CryptoJS = require("crypto-js");
  39. const Order = require("../model/OrderModel");
  40. const Server = require("../model/ServerModel");
  41. const System = require("../model/SystemModel");
  42. const User = require("../model/UserModel");
  43. const logger = require("../utils/log");
  44. const axios = require("axios");
  45. const {channelFactory} = require("../channels/factory/ChannelFactory");
  46. const {MianyouChannelHandler} = require("../channels/handlers/MianyouChannelHandler");
  47. /**
  48. * Google支付回调处理
  49. */
  50. const googleCallPay = async (ctx, config) => {
  51. let data = ctx.request.body;
  52. let orderId = data.orderId;
  53. let googleToken = data.purchaseToken;
  54. let out_trade_no = "";
  55. logger.info("Google支付回调参数:", {url: ctx.href, params: data});
  56. // 更新订单Token
  57. await Order.updateOrderToken(orderId, googleToken, "google");
  58. // 获取Google访问令牌
  59. const redisClient = ctx.redis.client;
  60. let access_token = await redisClient.get("access_token");
  61. if (!access_token) {
  62. logger.info("请求Google API获取token");
  63. const apiData = {
  64. grant_type: "refresh_token",
  65. client_id: ClientId,
  66. client_secret: ClientSecret,
  67. refresh_token: RefreshToken,
  68. };
  69. try {
  70. const response = await axios.post(
  71. "https://accounts.google.com/o/oauth2/token",
  72. apiData,
  73. {
  74. headers: {
  75. "Content-Type": "application/x-www-form-urlencoded",
  76. },
  77. }
  78. );
  79. logger.info("Google token响应:", {data: response.data});
  80. if (!response.data.access_token) {
  81. return PaymentHelper.DEFAULT_RESULT;
  82. }
  83. access_token = response.data.access_token;
  84. await redisClient.set("access_token", response.data.access_token);
  85. await redisClient.expire("access_token", 1800);
  86. } catch (error) {
  87. logger.error("获取Google token失败:", error);
  88. return PaymentHelper.DEFAULT_RESULT;
  89. }
  90. }
  91. if (!access_token) {
  92. return PaymentHelper.DEFAULT_RESULT;
  93. }
  94. // 验证订单
  95. const validation = await PaymentHelper.validateOrder(orderId);
  96. if (!validation.valid) {
  97. return {
  98. code: validation.message?.includes("重复发货") ? 1 : 0,
  99. msg: validation.message,
  100. };
  101. }
  102. const orderInfo = validation.orderInfo;
  103. // 验证Google订单
  104. const productId = ProductId + orderInfo.product_id;
  105. let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}`;
  106. let maxRetries = 3;
  107. let currentRetry = 0;
  108. let isCheck = false;
  109. // 使用循环进行重试
  110. while (currentRetry < maxRetries) {
  111. try {
  112. const googleRes = await axios.get(apiUrl, {
  113. headers: {
  114. "Content-Type": "application/x-www-form-urlencoded",
  115. },
  116. });
  117. logger.info("Google验证响应:", googleRes.data);
  118. if (googleRes.data.purchaseState == 0) {
  119. out_trade_no = googleRes.data.orderId;
  120. isCheck = true;
  121. break;
  122. }
  123. } catch (error) {
  124. logger.error("Google验证请求失败:", error);
  125. }
  126. currentRetry++;
  127. }
  128. if (!isCheck) {
  129. return PaymentHelper.DEFAULT_RESULT;
  130. }
  131. // 发货处理
  132. const result = await PaymentHelper.deliverOrder(
  133. orderInfo,
  134. ctx.request.ip,
  135. validation.url,
  136. out_trade_no
  137. );
  138. // 确认和消费Google订单
  139. try {
  140. // 确认订单
  141. let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}`;
  142. await axios.post(
  143. acknowledgeUrl,
  144. {developerPayload: ""},
  145. {headers: {"Content-Type": "application/json"}}
  146. );
  147. // 消费订单
  148. let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}`;
  149. await axios.post(
  150. consumeUrl,
  151. {developerPayload: ""},
  152. {headers: {"Content-Type": "application/json"}}
  153. );
  154. logger.info("Google订单处理完成:", {orderId: orderId});
  155. } catch (error) {
  156. logger.error("Google订单确认/消费失败:", error);
  157. // 即使确认/消费失败,我们仍然返回发货结果,因为发货可能已经成功
  158. }
  159. return result;
  160. };
  161. /**
  162. * Apple支付回调处理
  163. */
  164. const appleCallPay = async (ctx, config) => {
  165. let data = ctx.request.body;
  166. logger.info("Apple支付回调参数:", {url: ctx.href, params: data});
  167. if (!data.purchaseToken || !data.orderId) {
  168. return PaymentHelper.DEFAULT_RESULT;
  169. }
  170. let receipt_data = data.purchaseToken.replace(/ /g, "+");
  171. let orderId = data.orderId;
  172. let out_trade_no = orderId;
  173. // 更新订单Token
  174. await Order.updateOrderToken(orderId, receipt_data, "apple");
  175. // 验证Apple收据
  176. let maxRetries = 5;
  177. let currentRetry = 0;
  178. let isCheck = false;
  179. while (currentRetry < maxRetries) {
  180. try {
  181. const apiData = {
  182. "receipt-data": receipt_data,
  183. };
  184. const response = await axios.post(IosUrl, apiData, {
  185. headers: {
  186. "Content-Type": "application/json",
  187. },
  188. });
  189. logger.info(`Apple验证响应状态:${response.data.status}`);
  190. if (response.data.status == 0) {
  191. isCheck = true;
  192. break;
  193. }
  194. } catch (error) {
  195. logger.error("Apple验证请求失败:", error);
  196. }
  197. currentRetry++;
  198. }
  199. if (!isCheck) {
  200. logger.info(`Apple票据验证失败!`);
  201. return {code: 0, msg: "票据验证失败!"};
  202. }
  203. // 验证订单
  204. const validation = await PaymentHelper.validateOrder(orderId);
  205. if (!validation.valid) {
  206. return {
  207. code: validation.message?.includes("重复发货") ? 1 : 0,
  208. msg: validation.message,
  209. };
  210. }
  211. const orderInfo = validation.orderInfo;
  212. // 发货处理
  213. logger.info(`订单${orderId}通知游戏发货开始`);
  214. const result = await PaymentHelper.deliverOrder(
  215. orderInfo,
  216. ctx.request.ip,
  217. validation.url,
  218. out_trade_no
  219. );
  220. logger.info(`订单${orderId}通知游戏发货结束,结果:`, result);
  221. return result;
  222. };
  223. function splitString(input: string, separator: string): string[] {
  224. return input.split(separator);
  225. }
  226. //验证账号
  227. const checkUserToken = async (ctx) => {
  228. let ip = getClientIp(ctx);
  229. let {
  230. uid,
  231. channel_id,
  232. device_no,
  233. reg_device,
  234. device_type,
  235. device_model,
  236. device_version,
  237. system_version,
  238. platform = ''
  239. } = ctx.request.body;
  240. // 前端未传platform时,从内存缓存(thirdLogin写入)中查询补全
  241. if (channel_id == 17 && !platform && ip) {
  242. platform = getPlatformCache(ip);
  243. logger.info("从缓存获取platform:", {platform, ip});
  244. }
  245. const create_time = formatDate(new Date());
  246. const accountInfo = (await User.checkAccountIsExist(uid, channel_id))[0];
  247. let accountRes = null;
  248. let res = null;
  249. if (!accountInfo) {
  250. accountRes = await User.createAccount(
  251. uid,
  252. channel_id,
  253. ip,
  254. device_no,
  255. reg_device,
  256. create_time,
  257. platform
  258. );
  259. if (accountRes.affectedRows <= 0) {
  260. return ApiController.fail("添加账户失败");
  261. }
  262. }
  263. res = await User.logAccountLogin(
  264. uid,
  265. ip,
  266. device_type,
  267. device_no,
  268. device_model,
  269. device_version,
  270. system_version,
  271. create_time,
  272. channel_id,
  273. platform,
  274. );
  275. if (res.affectedRows <= 0) {
  276. return ApiController.fail("添加日志失败");
  277. }
  278. return ApiController.success("请求成功", 1, false, {ip: ip});
  279. };
  280. class ApiController {
  281. /**
  282. * 生成成功响应
  283. * @param msg 成功消息
  284. * @param code 成功码,默认为1(部分API使用0表示成功)
  285. * @param useMessage 是否使用message字段而不是msg字段,默认为false
  286. * @param data 响应数据
  287. * @returns 标准化的成功响应对象
  288. */
  289. static success(
  290. msg: string = "请求成功",
  291. code: number = 1,
  292. useMessage: boolean = false,
  293. data: any = null
  294. ) {
  295. return {
  296. code: code,
  297. [useMessage ? "message" : "msg"]: msg,
  298. data: data,
  299. };
  300. }
  301. /**
  302. * 生成失败响应
  303. * @param msg 错误消息
  304. * @param code 错误码,默认为0
  305. * @param data 额外的错误数据
  306. * @param useMessage 是否使用message字段而不是msg字段,默认为false
  307. * @returns 标准化的失败响应对象
  308. */
  309. static fail(
  310. msg: string = "请求失败",
  311. code: number = 0,
  312. data: any = null,
  313. useMessage: boolean = false
  314. ) {
  315. return {
  316. code: code,
  317. [useMessage ? "message" : "msg"]: msg,
  318. data: data,
  319. };
  320. }
  321. async createOrder(ctx) {
  322. let {
  323. uid,
  324. level,
  325. amount,
  326. role_id,
  327. role_name,
  328. product_id,
  329. server_id,
  330. channel_id,
  331. platform = '',
  332. } = ctx.request.body;
  333. logger.info("create params:", {params: ctx.request.body});
  334. if (
  335. !product_id ||
  336. !server_id ||
  337. !role_name ||
  338. !role_id ||
  339. !amount ||
  340. !uid ||
  341. !channel_id
  342. ) {
  343. ctx.body = ApiController.fail("参数错误,创建订单失败!!", -1);
  344. return;
  345. }
  346. const data = ctx.request.body;
  347. if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
  348. logger.error("创建订单签名验证失败");
  349. ctx.body = ApiController.fail("签名错误,创建订单失败!!", -1);
  350. return;
  351. }
  352. if (amount <= 0) {
  353. ctx.body = ApiController.fail("金额错误,创建订单失败!!", -1);
  354. return;
  355. }
  356. const orderId = generateOrderNumber(); // 生成一个长度为8的订单号
  357. const create_time = formatDate(new Date());
  358. const res = await Order.createOrder(
  359. orderId,
  360. uid,
  361. level,
  362. amount,
  363. role_id,
  364. role_name,
  365. product_id,
  366. server_id,
  367. channel_id,
  368. create_time,
  369. platform
  370. );
  371. if (res.affectedRows > 0) {
  372. ctx.body = ApiController.success("创建订单成功", 0, false, orderId);
  373. } else {
  374. ctx.body = ApiController.fail("创建订单失败", -1, null);
  375. }
  376. logger.info("创建订单返回结果:", {params: ctx.body});
  377. }
  378. async checkUserToken(ctx) {
  379. let {channel_id} = ctx.request.body;
  380. const channelConfig = ChannelConfigManager.getConfig(channel_id);
  381. if (!channelConfig) {
  382. logger.info("未找到渠道配置:", {channel_id});
  383. ctx.body = {
  384. code: 0,
  385. msg: "未知渠道id",
  386. };
  387. return;
  388. }
  389. var result = await checkUserToken(ctx);
  390. ctx.body = result;
  391. }
  392. async thirdLogin(ctx) {
  393. const data = ctx.request.body;
  394. let channelId = parseInt(data.channel_id) || 1;
  395. const platform = data.platform; // 平台参数:ios、Android、miniapp、h5
  396. logger.info("thirdLogin请求参数:", {data, channelId, platform});
  397. // 渠道11和渠道12数据打通,统一使用渠道11
  398. if (channelId === 12) {
  399. channelId = 11;
  400. logger.info("渠道12映射到渠道11,平台参数:", platform);
  401. }
  402. // 获取渠道配置
  403. let channelConfig = ChannelConfigManager.getConfig(channelId);
  404. if (data.is_new == 1) {
  405. if (channelId == 6) {
  406. channelConfig = ChannelConfigManager.getConfig(999);
  407. }
  408. if (channelId == 1) {
  409. channelConfig = ChannelConfigManager.getConfig(9);
  410. }
  411. }
  412. if (!channelConfig) {
  413. logger.info("未找到渠道配置:", {channelId});
  414. ctx.body = ApiController.fail("未知渠道id");
  415. return;
  416. }
  417. // 从工厂获取对应的渠道处理器
  418. const handler = channelFactory.getHandler(channelId);
  419. if (!handler) {
  420. logger.info("未找到渠道处理器:", {channelId});
  421. ctx.body = ApiController.fail("未知渠道id");
  422. return;
  423. }
  424. logger.info("使用渠道处理器处理登录:", {
  425. channelId: channelId,
  426. channelName: channelConfig.name,
  427. platform: platform
  428. });
  429. // 调用渠道处理器的登录方法
  430. const result = await handler.handleLogin(ctx, channelConfig);
  431. // 在返回结果中添加平台信息
  432. if (result && result.data) {
  433. result.data.platform = platform || 'unknown';
  434. }
  435. // 登录成功且有platform时,缓存到内存供checkUserToken查询
  436. if (result && result.code === 1 && platform) {
  437. const ip = getClientIp(ctx);
  438. const device_no = data.device_no || '';
  439. if (ip) {
  440. setPlatformCache(ip, platform);
  441. logger.info("thirdLogin缓存platform:", {ip, platform});
  442. }
  443. }
  444. // 根据不同渠道的返回格式要求处理结果
  445. ctx.body = result;
  446. }
  447. async callPay(ctx) {
  448. const data = ctx.request.body;
  449. let channelId = 1; // 默认渠道ID
  450. //打印回调参数
  451. logger.info("callPay支付回调参数:", {url: ctx.href, params: data, query: ctx.query});
  452. // 从请求中获取渠道ID
  453. if (ctx.query.channel_id) {
  454. channelId = parseInt(ctx.query.channel_id);
  455. }
  456. if (data.channel_id) {
  457. channelId = parseInt(data.channel_id);
  458. }
  459. logger.info("当前支付渠道id:", {channelId});
  460. // 获取渠道配置
  461. let channelConfig = ChannelConfigManager.getConfig(channelId);
  462. if (!channelConfig) {
  463. logger.info("未找到渠道配置:", {channelId});
  464. ctx.body = ApiController.fail("未知渠道id");
  465. return;
  466. }
  467. if (ctx.query.is_new && ctx.query.is_new == 1) {
  468. if (channelId == 6) {
  469. channelConfig = ChannelConfigManager.getConfig(999);
  470. }
  471. if (channelId == 1) {
  472. channelConfig = ChannelConfigManager.getConfig(9);
  473. }
  474. }
  475. const handler = channelFactory.getHandler(channelId);
  476. if (!handler) {
  477. logger.info("未找到渠道处理器:", {channelId});
  478. ctx.body = ApiController.fail("未知渠道id");
  479. return;
  480. }
  481. logger.info("使用渠道处理器处理支付:", {
  482. channelId: channelId,
  483. channelName: channelConfig.name,
  484. });
  485. // 调用渠道处理器的支付方法
  486. const result = await handler.handlePayment(ctx, channelConfig);
  487. // 根据不同渠道的返回格式要求处理结果
  488. switch (channelConfig.channelId) {
  489. case 6:
  490. ctx.body = result.code === 1 ? 1 : result.code;
  491. break;
  492. case 2:
  493. case 3:
  494. case 5:
  495. case 8:
  496. ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
  497. break;
  498. case 7:
  499. ctx.body = result.code === 1 ? "success" : "fail";
  500. break;
  501. case 11:
  502. ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
  503. break;
  504. case 12:
  505. ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
  506. break;
  507. case 13:
  508. //{"status":0,"msg":"status 非 0 时,传入失败信息"}
  509. ctx.body = {status: result.code === 1 ? 0 : -1, msg: result.msg};
  510. break;
  511. case 17:
  512. // 华为渠道:成功返回 {"errCode": 0},失败返回 {"errCode": 1, "errMsg": "..."}
  513. if (result.code === 0 || result.code === 1) {
  514. // 发货成功
  515. if (ctx.query.platform == "mtminiapp") {
  516. ctx.body = {"code": 0, "msg": "ok"}
  517. }else {
  518. ctx.body = {errCode: 0};
  519. }
  520. } else {
  521. // 发货失败
  522. ctx.body = {errCode: 1, errMsg: result.msg || "发放失败"};
  523. }
  524. break;
  525. case 14:
  526. case 21:
  527. ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
  528. break;
  529. default:
  530. ctx.body = result;
  531. }
  532. }
  533. async getServerList(ctx) {
  534. let tag = ctx.query.channel_id || 1;
  535. let data = ctx.request.body;
  536. let ip = getClientIp(ctx);
  537. // 尝试从渠道ID获取配置
  538. const channelConfig = ChannelConfigManager.getConfig(1);
  539. const signStr = data.timestamp + channelConfig.loginConfig?.signKey;
  540. let newSign = CryptoJS.MD5(signStr).toString();
  541. if (data.sign != newSign) {
  542. console.log("signStr:", signStr);
  543. logger.info(
  544. `签名错误: 签名串 ${signStr} newSign ${newSign} sign ${data.sign}`
  545. );
  546. ctx.body = ApiController.fail("签名错误");
  547. return;
  548. }
  549. let sort = data.sort == 0 ? "asc" : "desc";
  550. logger.info("区服接口", {ip: ip});
  551. const servers = await Server.getServerList(tag, 0, sort);
  552. let serverList = [];
  553. if (servers.length > 0) {
  554. servers.forEach(function (element) {
  555. let status = element.status;
  556. if ((status == 0 || status == 3) && element.white_list) {
  557. const list = element.white_list.split(",");
  558. if (list.length > 0) {
  559. if (list.includes(ip)) {
  560. status = 1;
  561. }
  562. }
  563. }
  564. serverList.push({
  565. serverId: element.id,
  566. serverName: element.name,
  567. });
  568. });
  569. }
  570. ctx.body = ApiController.success("成功", 1, false, serverList);
  571. }
  572. async getAllServerList(ctx) {
  573. let tag = ctx.query.channel_id || 1;
  574. let uid = ctx.query.uid || ctx.request.body?.uid; // uid是可选参数,支持GET和POST请求
  575. let ip = getClientIp(ctx);
  576. logger.info("getAllServerList 区服接口", {tag: tag, uid: uid, ip: ip});
  577. const servers = await Server.getAllServerList(tag, ip);
  578. // 如果提供了玩家ID,则查询每个服务器的角色信息;否则只返回基本服务器信息
  579. if (uid) {
  580. const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
  581. // 为每个服务器添加角色信息
  582. const serversWithRoleInfo = await Promise.all(
  583. servers.map(async (server) => {
  584. try {
  585. const newUniqueTag = `${server.tag}|${server.sid}|${uid}`;
  586. const roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, server.db_name);
  587. return {
  588. ...server,
  589. roleName: roleInfo?.roleName || null,
  590. roleLevel: roleInfo?.roleLevel || null,
  591. head: roleInfo?.head || null,
  592. hasRole: !!roleInfo
  593. };
  594. } catch (error) {
  595. logger.error(`查询服务器${server.id}角色信息失败:`, error);
  596. return {
  597. ...server,
  598. roleName: null,
  599. roleLevel: null,
  600. head: null,
  601. hasRole: false
  602. };
  603. }
  604. })
  605. );
  606. // tag=11 时,找到第一个有角色的服,隐藏它之前的服;都没角色则只显示最新的1个服
  607. if (tag == 11 || tag === '11') {
  608. const firstRoleIndex = serversWithRoleInfo.findIndex(s => s.hasRole);
  609. if (firstRoleIndex > 0) {
  610. ctx.body = serversWithRoleInfo.slice(firstRoleIndex);
  611. } else if (firstRoleIndex === -1) {
  612. ctx.body = serversWithRoleInfo.slice(-1);
  613. } else {
  614. ctx.body = serversWithRoleInfo;
  615. }
  616. } else {
  617. ctx.body = serversWithRoleInfo;
  618. }
  619. } else {
  620. ctx.body = servers;
  621. }
  622. }
  623. async enterServer(ctx) {
  624. let {uid, server_id, channel_id} = ctx.request.body;
  625. let url = await getServerList(server_id, channel_id || 1);
  626. if (!url) {
  627. ctx.body = ApiController.fail(`区服id错误: serverId ${server_id}`, -1);
  628. return;
  629. }
  630. logger.info("create params:", {params: ctx.request.body});
  631. if (!server_id || !uid) {
  632. ctx.body = ApiController.fail("参数错误!!", -1);
  633. return;
  634. }
  635. const create_time = formatDate(new Date());
  636. const serverInfo = (
  637. await Server.checkEnterServerByUid(uid, server_id, channel_id)
  638. )[0];
  639. let res = null;
  640. if (serverInfo) {
  641. res = await Server.updateEnterServer(serverInfo.id, create_time);
  642. } else {
  643. res = await Server.enterServer(uid, server_id, create_time, channel_id);
  644. }
  645. if (res.affectedRows > 0) {
  646. ctx.body = ApiController.success("请求成功", 0, true, "");
  647. } else {
  648. ctx.body = ApiController.fail("请求失败", -1, null, true);
  649. }
  650. }
  651. async getLastServerList(ctx) {
  652. let {uid, channel_id} = ctx.request.body;
  653. // uid是可选参数,如果不提供则只返回基本服务器信息
  654. let tag = channel_id || 1;
  655. let data = [];
  656. let isNewAccount = 1;
  657. let enterServerList = [];
  658. let ip = getClientIp(ctx);
  659. logger.info("getLastServerList 区服接口", {uid: uid, ip: ip});
  660. // 获取渠道配置
  661. const channelConfig = ChannelConfigManager.getConfig(tag);
  662. if (!channelConfig) {
  663. logger.info("未找到渠道配置:", {tag});
  664. ctx.body = ApiController.fail("未知渠道id");
  665. return;
  666. }
  667. // 如果提供了uid,查询用户进入过的服务器列表
  668. if (uid) {
  669. enterServerList = await Server.getEnterServerListByUid(uid, channel_id);
  670. }
  671. if (enterServerList.length > 0) {
  672. isNewAccount = 0;
  673. const servers = await Server.getAllServerList(tag, ip);
  674. const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
  675. // 为每个进入过的服务器添加角色信息
  676. for (const element of enterServerList) {
  677. let roleInfo = null;
  678. // 只有在提供了uid时才查询角色信息
  679. if (uid) {
  680. try {
  681. const newUniqueTag = `${tag}|${element.server_id}|${uid}`;
  682. roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, element.db_name);
  683. } catch (error) {
  684. logger.error(`查询服务器${element.server_id}角色信息失败:`, error);
  685. }
  686. }
  687. const sid = Number(element.server_id) || 1;
  688. const minSid = Math.floor((sid - 1) / 10) * 10 + 1;
  689. data.push({
  690. channel: channelConfig.name, //渠道固定
  691. minSid: minSid, //最小服务器
  692. maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
  693. isNewAccount: isNewAccount, //1为新号 会弹出用户协议
  694. //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
  695. sid: element.server_id || 1,
  696. id: element.server_id || 1,
  697. name: element.name || "1区",
  698. tips: element.tips || "",
  699. server: element.wss
  700. ? element.wss
  701. : `ws://${element.ip}:${element.port}`,
  702. status: element.status || 0,
  703. // 角色信息(只有在提供了uid时才包含)
  704. roleName: roleInfo?.roleName || null,
  705. roleLevel: roleInfo?.roleLevel || null,
  706. head: roleInfo?.head || null,
  707. hasRole: !!roleInfo
  708. });
  709. }
  710. logger.info("getLastServerList 区服接口 enterServerList", {
  711. enterServerList: enterServerList,
  712. });
  713. } else {
  714. const servers = await Server.getAllServerList(tag, ip);
  715. let roleInfo = null;
  716. if (servers.length > 0) {
  717. const serverInfo = servers[servers.length - 1];
  718. logger.info("getLastServerList 区服接口 serverInfo", {
  719. serverInfo: serverInfo,
  720. });
  721. // 只有在提供了uid时才查询最后一个服务器的角色信息
  722. if (uid) {
  723. const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
  724. try {
  725. const newUniqueTag = `${serverInfo.tag}|${serverInfo.sid}|${uid}`;
  726. roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, serverInfo.db_name);
  727. } catch (error) {
  728. logger.error(`查询服务器${serverInfo.id}角色信息失败:`, error);
  729. }
  730. }
  731. data.push({
  732. channel: channelConfig.name, //渠道固定
  733. minSid: Math.floor(((servers[0].sid || 1) - 1) / 10) * 10 + 1, //最小服务器
  734. maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
  735. isNewAccount: isNewAccount, //1为新号 会弹出用户协议
  736. //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
  737. sid: serverInfo.sid || 1,
  738. id: serverInfo.id || 1,
  739. name: serverInfo.name || "1区",
  740. tips: serverInfo.tips || "",
  741. server: serverInfo.server
  742. ? serverInfo.server
  743. : `ws://${serverInfo.ip}:${serverInfo.port}/`,
  744. status: serverInfo.status || 0,
  745. // 角色信息
  746. roleName: roleInfo?.roleName || null,
  747. roleLevel: roleInfo?.roleLevel || null,
  748. head: roleInfo?.head || null,
  749. hasRole: !!roleInfo
  750. });
  751. } else {
  752. data.push({
  753. channel: "未知", //渠道固定
  754. minSid: 1, //最小服务器
  755. maxSid: 10, //最大服务器 这里会控制 服务器列表显示的数量
  756. isNewAccount: isNewAccount, //1为新号 会弹出用户协议
  757. //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
  758. sid: 1,
  759. id: 1,
  760. name: "1区",
  761. tips: "",
  762. server: "",
  763. status: 0,
  764. // 角色信息(新用户,无角色)
  765. roleName: null,
  766. roleLevel: null,
  767. head: null,
  768. hasRole: false
  769. });
  770. }
  771. }
  772. // 根据sid去重
  773. const seenSids = new Set();
  774. data = data.filter(item => {
  775. if (seenSids.has(item.sid)) return false;
  776. seenSids.add(item.sid);
  777. return true;
  778. });
  779. // 所有组的minSid统一取最小值
  780. if (data.length > 0) {
  781. const globalMinSid = Math.min(...data.map(item => item.minSid));
  782. data.forEach(item => { item.minSid = globalMinSid; });
  783. }
  784. // tag=11 时,找到第一个有角色的服,隐藏它之前的服;都没角色则只显示最新的1个服
  785. if ((tag == 11 || tag === '11') && enterServerList.length > 0) {
  786. const firstRoleIndex = data.findIndex(s => s.hasRole);
  787. if (firstRoleIndex > 0) {
  788. data = data.slice(firstRoleIndex);
  789. } else if (firstRoleIndex === -1) {
  790. data = data.slice(-1);
  791. }
  792. }
  793. ctx.body = data;
  794. // ctx.body = ApiController.success("获取最近服务器列表成功", 1, false, data);
  795. }
  796. async getNotice(ctx) {
  797. let tag = ctx.query.channel_id || 1;
  798. let content = "";
  799. let content_wh = "";
  800. const system = await System.getSystemConfig(tag);
  801. if (system) {
  802. system.forEach((element) => {
  803. if (element.key == "content") {
  804. content = element.value;
  805. }
  806. if (element.key == "content_wh") {
  807. content_wh = element.value;
  808. }
  809. });
  810. }
  811. let notice_data = [
  812. {
  813. status: 1,
  814. content: content,
  815. content_wh: content_wh,
  816. },
  817. ];
  818. ctx.body = notice_data;
  819. // ctx.body = ApiController.success("获取公告成功", 1, false, notice_data);
  820. }
  821. // 维护服务器,踢掉所有玩家
  822. async maintenance(ctx) {
  823. let data = {
  824. channel_id: parseInt(ctx.query.channel_id),
  825. serverId: parseInt(ctx.query.serverId) || "",
  826. };
  827. logger.info("maintenance :", {channelId: data.channel_id});
  828. let url = await getServerList(data.serverId, data.channel_id || 1);
  829. if (!url) {
  830. ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
  831. return;
  832. }
  833. let param = JSON.stringify({
  834. type: "kickAllUser",
  835. });
  836. let sendMsg = new Msg();
  837. sendMsg.connect(url, Account);
  838. new Promise((resolve) => {
  839. setTimeout(async () => {
  840. sendMsg.CG_TEST_PROTO("test", param);
  841. }, 1000);
  842. });
  843. ctx.body = ApiController.success("success", 0, false, null);
  844. }
  845. async maintenanceAll(ctx) {
  846. let channelId = parseInt(ctx.query.channel_id);
  847. let isMaintenance = ctx.query.isMaintenance;
  848. let key = ctx.query.key;
  849. logger.info("maintenanceAll :", {
  850. channelId: channelId,
  851. isMaintenance: isMaintenance,
  852. });
  853. if (key != "dsdadsadajkkjkxab") {
  854. ctx.body = ApiController.fail("无权使用", -1);
  855. return;
  856. }
  857. const servers = await Server.getAllServerList(channelId, "");
  858. logger.info("maintenanceAll servers:", {servers: servers});
  859. if (servers.length === 0) {
  860. ctx.body = ApiController.fail("不存在可操作区服", -1);
  861. return;
  862. }
  863. const serversId = servers.map((obj) => obj.id);
  864. if (isMaintenance == "true") {
  865. const res = await Server.updateServerStatus(serversId, 3);
  866. }
  867. servers.forEach(function (element) {
  868. let url = "ws://" + element.ip + ":" + element.port;
  869. if (!url) {
  870. ctx.body = ApiController.fail(`区服id错误: serverId ${element.id}`, 1);
  871. return;
  872. }
  873. let param = JSON.stringify({
  874. type: "kickAllUser",
  875. });
  876. // Msg.connect(url, Account);
  877. let sendMsg = new Msg();
  878. sendMsg.connect(url, Account);
  879. new Promise((resolve) => {
  880. setTimeout(async () => {
  881. sendMsg.CG_TEST_PROTO("test", param);
  882. }, 1000);
  883. });
  884. });
  885. logger.info("maintenanceAll 更新的区服id:", {serversId: serversId});
  886. ctx.body = ApiController.success("success", 0, false, null);
  887. }
  888. async sendMail(ctx) {
  889. let data = ctx.request.body;
  890. let url = await getServerList(data.serverId, data.channel_id || 1);
  891. if (!url) {
  892. ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
  893. return;
  894. }
  895. let param = JSON.stringify({
  896. type: "sendMail",
  897. mail: JSON.stringify({
  898. uuid: data.uuid,
  899. title: data.title,
  900. content: data.content,
  901. items: JSON.parse(data.items),
  902. expire: data.expire,
  903. }),
  904. });
  905. // Msg.connect(url, Account);
  906. let sendMsg = new Msg();
  907. sendMsg.connect(url, Account);
  908. new Promise((resolve) => {
  909. setTimeout(async () => {
  910. sendMsg.CG_TEST_PROTO("test", param);
  911. }, 1000);
  912. });
  913. ctx.body = ApiController.success("success", 0, false, null);
  914. }
  915. async sendAllMail(ctx) {
  916. let data = ctx.request.body;
  917. if (!data.server_list || data.server_list.length === 0) {
  918. ctx.body = ApiController.fail("区服不能为空", -1);
  919. return;
  920. }
  921. logger.info("sendAllMail 接口请求 data:", {data: data});
  922. const server_list = data.server_list;
  923. const servers = await Server.getServerList(data.channel_id || 1);
  924. const filteredServer = servers.filter((item) =>
  925. server_list.includes(item.id)
  926. );
  927. filteredServer.forEach(function (element) {
  928. let url = "ws://" + element.ip + ":" + element.port;
  929. if (!url) {
  930. ctx.body = ApiController.fail(
  931. `区服id错误: serverId ${element.server_id}`,
  932. 1
  933. );
  934. return;
  935. }
  936. let param = JSON.stringify({
  937. type: "sendAllMail",
  938. mail: JSON.stringify({
  939. title: data.title,
  940. content: data.content,
  941. items: JSON.parse(data.items),
  942. expire: data.expire,
  943. }),
  944. });
  945. let sendMsg = new Msg();
  946. sendMsg.connect(url, Account);
  947. new Promise((resolve) => {
  948. setTimeout(async () => {
  949. sendMsg.CG_TEST_PROTO("test", param);
  950. }, 1000);
  951. });
  952. });
  953. ctx.body = ApiController.success("success", 0);
  954. }
  955. async useCDKV2(ctx) {
  956. let body = ctx.request.body;
  957. logger.info("useCDKV2接口请求参数:", {data: body});
  958. let data = {
  959. code: body.code,
  960. userId: body.account,
  961. channelId: body.channel_id || 0,
  962. };
  963. if (body.uuid) {
  964. data.userId = body.uuid;
  965. }
  966. let serverUrl = await getServerAddr(body.serverId, body.channel_id);
  967. let err = "";
  968. if (!serverUrl) {
  969. ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
  970. return;
  971. }
  972. let port = 8004;
  973. let host = "127.0.0.1";
  974. let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
  975. logger.info("接口请求后台 data:", {data: data, url: url});
  976. try {
  977. const specialCodes = [
  978. "gfyx555",
  979. "gfyx666",
  980. "gfyx777",
  981. "gfyx1000",
  982. "gfyx2000",
  983. "gfyx3000",
  984. "gfyxrqlb",
  985. "GFYX555",
  986. "GFYX666",
  987. "GFYX777",
  988. "GFYX1000",
  989. "GFYX2000",
  990. "GFYX3000",
  991. "GFYXrqlb",
  992. "GFYX000",
  993. "GFYX222",
  994. "GFYX333",
  995. "GFYX888",
  996. "GFYX1818",
  997. "GQ888",
  998. "ZQ888",
  999. "gfyx8888",
  1000. "gfyx6666",
  1001. "gfyx7777",
  1002. "gfyxxjbc",
  1003. "LIDONGLB",
  1004. "XIAOXULB",
  1005. "GANENLB",
  1006. "WANSHLB",
  1007. "HERO666",
  1008. "HERO777",
  1009. "HERO888",
  1010. "gfyx9999",
  1011. "aiqi6666",
  1012. "aiqi7777",
  1013. "aiqi8888",
  1014. "aiqi9999",
  1015. "gf555",
  1016. "gf666",
  1017. "gf777",
  1018. "gf100",
  1019. "gf200",
  1020. "gf300",
  1021. "YDKL888",
  1022. "SDKL888",
  1023. "CHUXILB",
  1024. "CHUNJIELB",
  1025. "YUANXIAOLB",
  1026. "VIP555",
  1027. "VIP666",
  1028. "VIP777",
  1029. "VIP888",
  1030. ];
  1031. let param: string = "";
  1032. const h5Codes = ["gfyx000", "gfyx222", "gfyx333", "gfyx888", "gfyx1818"];
  1033. if (h5Codes.includes(data.code) && body.channel_id != 5) {
  1034. ctx.body = ApiController.fail("该激活码无法在h5渠道使用", 1);
  1035. }
  1036. if (specialCodes.includes(data.code) || h5Codes.includes(data.code)) {
  1037. param = JSON.stringify({
  1038. code: data.code,
  1039. type: "UseFixCDK",
  1040. channel_id: body.channel_id,
  1041. });
  1042. } else {
  1043. const response = await axios.post(url, data, {
  1044. headers: {
  1045. "Content-Type": "application/json",
  1046. },
  1047. timeout: 10000,
  1048. });
  1049. logger.info("接口请求后台 接口返回 response:", {data: response.data});
  1050. if (response.data.code != 200) {
  1051. ctx.body = ApiController.fail(response.data.msg, 1);
  1052. return;
  1053. }
  1054. const result = splitString(response.data.data, ";");
  1055. // 重构itemList
  1056. let itemList = Array();
  1057. for (let i = 0; i < result.length; i++) {
  1058. let elem = splitString(result[i], ":");
  1059. let output0 = parseInt(elem[0], 10);
  1060. let output1 = parseInt(elem[1], 10);
  1061. itemList.push([output0, output1]);
  1062. }
  1063. param = JSON.stringify({
  1064. type: "UseCDKV2",
  1065. itemList: itemList,
  1066. channel_id: body.channel_id,
  1067. });
  1068. }
  1069. let sendMsg = new Msg();
  1070. sendMsg.connect(serverUrl, Account);
  1071. logger.info("api cdk 发送服务器 param:", {param: param});
  1072. new Promise((resolve) => {
  1073. setTimeout(async () => {
  1074. sendMsg.CG_TEST_PROTO(body.account, param, body.serverId);
  1075. }, 1000);
  1076. });
  1077. } catch (error) {
  1078. console.log(error);
  1079. }
  1080. ctx.body = ApiController.success("success", 0);
  1081. }
  1082. async banUser(ctx) {
  1083. let data = ctx.request.body;
  1084. logger.info("banUser 接口请求 data:", {data: data});
  1085. if (!data.server_tag) {
  1086. ctx.body = ApiController.fail("区服id不能为空", -1, "");
  1087. return;
  1088. }
  1089. let banInfo = {};
  1090. switch (parseInt(data.ban_type)) {
  1091. case 1:
  1092. banInfo = {
  1093. roleBanInfo: {
  1094. channelTag: data.channel_id,
  1095. serverTag: data.server_tag,
  1096. roleTag: data.role_tag,
  1097. banTime: data.ban_time,
  1098. },
  1099. type: "setBan",
  1100. };
  1101. break;
  1102. case 2:
  1103. banInfo = {
  1104. accountBanInfo: {
  1105. channelTag: data.channel_id,
  1106. accountTag: data.account_tag,
  1107. banTime: data.ban_time,
  1108. },
  1109. type: "setBan",
  1110. };
  1111. break;
  1112. case 3:
  1113. banInfo = {
  1114. appBanInfo: {
  1115. appId: data.device_id,
  1116. banTime: data.ban_time,
  1117. },
  1118. type: "setBan",
  1119. };
  1120. break;
  1121. default:
  1122. }
  1123. logger.info("banUser 发送服务器 banInfo:", banInfo);
  1124. let url = await getServerList(data.server_tag, data.channel_id);
  1125. if (!url) {
  1126. ctx.body = ApiController.fail(
  1127. `区服id错误: serverId ${data.server_tag}`,
  1128. 1
  1129. );
  1130. return;
  1131. }
  1132. let param = JSON.stringify(banInfo);
  1133. logger.info("banUser 发送服务器 json字符串: " + param);
  1134. let sendMsg = new Msg();
  1135. sendMsg.connect(url, Account);
  1136. new Promise((resolve) => {
  1137. setTimeout(async () => {
  1138. sendMsg.CG_TEST_PROTO("test", param, data.server_tag);
  1139. // sendMsg.CG_SET_BAN(param);
  1140. }, 1000);
  1141. });
  1142. ctx.body = ApiController.success("success", 0);
  1143. }
  1144. async uicFilter4399(ctx) {
  1145. let body = ctx.request.body;
  1146. let channelConfig = ChannelConfigManager.getConfig(6);
  1147. if (body.is_new == 1) {
  1148. channelConfig = ChannelConfigManager.getConfig(999);
  1149. }
  1150. logger.info("uicFilter4399 body:", {data: body});
  1151. let toCheck = body.toCheck;
  1152. let signStr = channelConfig.loginConfig?.signKey + toCheck;
  1153. logger.info("uicFilter4399 signStr:", {signStr: signStr});
  1154. let apiParams = {
  1155. toCheck: toCheck,
  1156. app: channelConfig.loginConfig.appId,
  1157. byPinyin: true,
  1158. isBatch: false,
  1159. sig: CryptoJS.MD5(signStr).toString(),
  1160. };
  1161. logger.info("uicFilter4399 apiParams:", {data: apiParams});
  1162. const queryStr = Object.entries(apiParams)
  1163. .map(
  1164. ([key, value]) =>
  1165. `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
  1166. )
  1167. .join("&");
  1168. let url = "https://wo.webgame138.com/test/matchService.do" + "?" + queryStr;
  1169. // let url = "https://wo.webgame138.com/test/matchService.do";
  1170. logger.info("uicFilter4399 url:", {url: url});
  1171. try {
  1172. // let response = await axios.get(url, {
  1173. // timeout: 10000, // 设置10秒超时
  1174. // });
  1175. const response = await axios.post(url, apiParams, {
  1176. headers: {
  1177. "Content-Type": "application/json",
  1178. },
  1179. });
  1180. logger.info("uicFilter4399 接口返回 response:", {data: response.data});
  1181. ctx.body = ApiController.success("success", 0, false, response.data);
  1182. } catch (error) {
  1183. console.log(error);
  1184. ctx.body = ApiController.fail(error.message || "请求失败", 1);
  1185. }
  1186. }
  1187. async roleList4399(ctx) {
  1188. let body = ctx.request.body;
  1189. logger.info("RoleList4399 请求参数:", {body: body});
  1190. let data = {
  1191. userId: body.userId,
  1192. server: body.server,
  1193. is_new: ctx.query.is_new || 0
  1194. };
  1195. let port = 8004;
  1196. let host = "127.0.0.1";
  1197. let url = "http://" + host + ":" + port + "/api/roleList/checkBy4399";
  1198. logger.info("RoleList4399 url:", {url: url});
  1199. try {
  1200. const response = await axios.post(url, data, {
  1201. headers: {
  1202. "Content-Type": "application/json",
  1203. },
  1204. });
  1205. logger.info("RoleList4399 返回 response:", {data: response.data});
  1206. ctx.body = response.data;
  1207. } catch (error) {
  1208. console.log(error);
  1209. }
  1210. }
  1211. async cdkBy4399(ctx) {
  1212. let body = ctx.request.body;
  1213. logger.info("cdkBy4399:", {data: body});
  1214. let server = body.server || 1;
  1215. let channel = 5;
  1216. let data = {
  1217. code: body.giftId,
  1218. userId: body.userId,
  1219. channelId: channel,
  1220. };
  1221. if (body.uuid) {
  1222. data.userId = body.uuid;
  1223. }
  1224. let serverUrl = await getServerList(server, channel);
  1225. let err = "";
  1226. if (!serverUrl) {
  1227. ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
  1228. return;
  1229. }
  1230. let port = 8004;
  1231. let host = "127.0.0.1";
  1232. let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
  1233. logger.info("cdkBy4399接口请求后台 data:", {data: data, url: url});
  1234. try {
  1235. const response = await axios.post(url, data, {
  1236. headers: {
  1237. "Content-Type": "application/json",
  1238. },
  1239. timeout: 10000,
  1240. });
  1241. logger.info("cdkBy4399接口请求后台 接口返回 response:", {
  1242. data: response.data,
  1243. });
  1244. if (response.data.code != 200) {
  1245. ctx.body = ApiController.fail(response.data.msg, 10004);
  1246. return;
  1247. }
  1248. const result = splitString(response.data.data, ";");
  1249. // 重构itemList
  1250. let itemList = Array();
  1251. for (let i = 0; i < result.length; i++) {
  1252. let elem = splitString(result[i], ":");
  1253. let output0 = parseInt(elem[0], 10);
  1254. let output1 = parseInt(elem[1], 10);
  1255. itemList.push([output0, output1]);
  1256. }
  1257. let param = JSON.stringify({
  1258. type: "UseCDKV2",
  1259. itemList: itemList,
  1260. channel_id: channel,
  1261. });
  1262. let sendMsg = new Msg();
  1263. sendMsg.connect(serverUrl, Account);
  1264. logger.info("cdkBy4399 cdk 发送服务器 param:", {param: param});
  1265. new Promise((resolve) => {
  1266. setTimeout(async () => {
  1267. sendMsg.CG_TEST_PROTO("test", param, server);
  1268. }, 1000);
  1269. });
  1270. } catch (error) {
  1271. console.log(error);
  1272. }
  1273. ctx.body = ApiController.success("success", 10000);
  1274. }
  1275. async roleListYfy(ctx) {
  1276. let gameCode = ctx.query.gameCode;
  1277. let timestamp = ctx.query.timestamp;
  1278. let uid = ctx.query.uid;
  1279. let sign = ctx.query.sign;
  1280. let AppSecret = "H1EqhbpA80jt0Jw6Q3T2";
  1281. logger.info("roleListYfy 请求参数:", {
  1282. uid: uid,
  1283. gameCode: gameCode,
  1284. timestamp: timestamp,
  1285. });
  1286. const signStr = `gameCode-${gameCode}&timestamp=${timestamp}&uid=${uid}${AppSecret}`;
  1287. const newSign = CryptoJS.MD5(signStr).toString();
  1288. if (newSign != sign) {
  1289. logger.info("roleListYfy 签名错误:", {
  1290. signStr: signStr,
  1291. sign: sign,
  1292. newSign: newSign,
  1293. });
  1294. ctx.body = ApiController.fail("签名错误!!", -1);
  1295. }
  1296. let port = 8004;
  1297. let host = "127.0.0.1";
  1298. let url = "http://" + host + ":" + port + "/api/roleList/checkByYfy";
  1299. logger.info("roleListYfy url:", {url: url});
  1300. try {
  1301. const response = await axios.post(
  1302. url,
  1303. {
  1304. userId: uid,
  1305. },
  1306. {
  1307. headers: {
  1308. "Content-Type": "application/json",
  1309. },
  1310. }
  1311. );
  1312. logger.info("roleListYfy 返回 response:", {data: response.data});
  1313. ctx.body = response.data;
  1314. } catch (error) {
  1315. console.log(error);
  1316. }
  1317. }
  1318. async getQuickSign(ctx) {
  1319. let data = ctx.request.body;
  1320. logger.info("getQuickSign 请求参数:", {body: data});
  1321. if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
  1322. logger.error("签名验证失败");
  1323. ctx.body = ApiController.fail("签名错误!!", -1);
  1324. return;
  1325. }
  1326. let key = "H1EqhbpA80jt0Jw6Q3T2";
  1327. let signStr =
  1328. "uid=" +
  1329. data.uid +
  1330. "&username=" +
  1331. data.username +
  1332. "&serverId=" +
  1333. data.serverId +
  1334. "&serverName=" +
  1335. data.serverName +
  1336. "&userRoleId=" +
  1337. data.userRoleId +
  1338. "&userRoleName=" +
  1339. data.userRoleName +
  1340. "&userRoleLevel=" +
  1341. data.userRoleLevel +
  1342. "&vipLevel=" +
  1343. data.vipLevel +
  1344. "&gameRolePower=" +
  1345. data.gameRolePower +
  1346. "&key=" +
  1347. key;
  1348. logger.info("getQuickSign signStr:", {signStr: signStr});
  1349. data.sign = CryptoJS.MD5(signStr).toString();
  1350. ctx.body = ApiController.success("success", 0, false, data);
  1351. }
  1352. /**
  1353. * mianyou开服同步处理
  1354. * @param ctx Koa上下文
  1355. */
  1356. async mianyouSyncServer(ctx) {
  1357. try {
  1358. const data = ctx.request.body;
  1359. logger.info("mianyou开服同步请求参数:", {data});
  1360. // 验证必要参数
  1361. const {serverId, gameServerId, serverName, startTime, channelId} = data;
  1362. if (!serverId || !gameServerId || !serverName || !startTime) {
  1363. logger.warn("mianyou开服同步失败: 缺少必要参数", {data});
  1364. ctx.body = ApiController.fail("缺少必要参数: serverId, gameServerId, serverName, startTime");
  1365. return;
  1366. }
  1367. // 获取渠道配置
  1368. const channelConfig = ChannelConfigManager.getConfig(channelId || 1);
  1369. if (!channelConfig) {
  1370. logger.error("mianyou开服同步失败: 未找到渠道配置", {channelId});
  1371. ctx.body = ApiController.fail("未找到渠道配置");
  1372. return;
  1373. }
  1374. // 创建MianyouChannelHandler实例
  1375. const mianyouHandler = new MianyouChannelHandler();
  1376. // 调用开服同步方法
  1377. const result = await mianyouHandler.openServer(
  1378. parseInt(serverId),
  1379. gameServerId,
  1380. serverName,
  1381. startTime,
  1382. channelConfig
  1383. );
  1384. logger.info("mianyou开服同步结果:", {result});
  1385. // 根据返回结果设置响应
  1386. if (result.status === 0) {
  1387. ctx.body = ApiController.success("开服同步成功", 0, false, result);
  1388. } else {
  1389. ctx.body = ApiController.fail(result.msg || "开服同步失败", result.status);
  1390. }
  1391. } catch (error) {
  1392. logger.error("mianyou开服同步异常:", error);
  1393. ctx.body = ApiController.fail("服务器内部错误", -1);
  1394. }
  1395. }
  1396. }
  1397. module.exports = new ApiController();