| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610 |
- import Msg from "../utils/msg";
- import {
- RefreshToken,
- PackageName,
- ProductId,
- IosUrl,
- Account,
- ClientSecret,
- ClientId,
- ORDER_SIGN_KEY,
- } from "../config/thirdParams";
- import {
- generateOrderNumber,
- formatDate,
- getServerList,
- getClientIp, getServerAddr,
- } from "../utils/common";
- import {PaymentHelper} from "../utils/PaymentHelper";
- import {SignatureVerifier} from "../utils/SignatureVerifier";
- import {ChannelConfigManager} from "../utils/ChannelConfigManager";
- import {getRoleInfoByUidAndServerId} from "../mongo/mongodb";
- // platform内存缓存,key: ip:device_no,TTL 5分钟
- const platformCache = new Map<string, {value: string; expireAt: number}>();
- const PLATFORM_CACHE_TTL = 60 * 1000; // 缓存1分钟
- function setPlatformCache(ip: string, platform: string) {
- platformCache.set(ip, {value: platform, expireAt: Date.now() + PLATFORM_CACHE_TTL});
- }
- function getPlatformCache(ip: string): string {
- const entry = platformCache.get(ip);
- if (!entry) return '';
- if (Date.now() > entry.expireAt) {
- platformCache.delete(ip);
- return '';
- }
- return entry.value;
- }
- // 导入依赖
- const CryptoJS = require("crypto-js");
- const Order = require("../model/OrderModel");
- const Server = require("../model/ServerModel");
- const System = require("../model/SystemModel");
- const User = require("../model/UserModel");
- const logger = require("../utils/log");
- const axios = require("axios");
- const {channelFactory} = require("../channels/factory/ChannelFactory");
- const {MianyouChannelHandler} = require("../channels/handlers/MianyouChannelHandler");
- /**
- * Google支付回调处理
- */
- const googleCallPay = async (ctx, config) => {
- let data = ctx.request.body;
- let orderId = data.orderId;
- let googleToken = data.purchaseToken;
- let out_trade_no = "";
- logger.info("Google支付回调参数:", {url: ctx.href, params: data});
- // 更新订单Token
- await Order.updateOrderToken(orderId, googleToken, "google");
- // 获取Google访问令牌
- const redisClient = ctx.redis.client;
- let access_token = await redisClient.get("access_token");
- if (!access_token) {
- logger.info("请求Google API获取token");
- const apiData = {
- grant_type: "refresh_token",
- client_id: ClientId,
- client_secret: ClientSecret,
- refresh_token: RefreshToken,
- };
- try {
- const response = await axios.post(
- "https://accounts.google.com/o/oauth2/token",
- apiData,
- {
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- },
- }
- );
- logger.info("Google token响应:", {data: response.data});
- if (!response.data.access_token) {
- return PaymentHelper.DEFAULT_RESULT;
- }
- access_token = response.data.access_token;
- await redisClient.set("access_token", response.data.access_token);
- await redisClient.expire("access_token", 1800);
- } catch (error) {
- logger.error("获取Google token失败:", error);
- return PaymentHelper.DEFAULT_RESULT;
- }
- }
- if (!access_token) {
- return PaymentHelper.DEFAULT_RESULT;
- }
- // 验证订单
- const validation = await PaymentHelper.validateOrder(orderId);
- if (!validation.valid) {
- return {
- code: validation.message?.includes("重复发货") ? 1 : 0,
- msg: validation.message,
- };
- }
- const orderInfo = validation.orderInfo;
- // 验证Google订单
- 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 = 3;
- let currentRetry = 0;
- let isCheck = false;
- // 使用循环进行重试
- while (currentRetry < maxRetries) {
- try {
- const googleRes = await axios.get(apiUrl, {
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- },
- });
- logger.info("Google验证响应:", googleRes.data);
- if (googleRes.data.purchaseState == 0) {
- out_trade_no = googleRes.data.orderId;
- isCheck = true;
- break;
- }
- } catch (error) {
- logger.error("Google验证请求失败:", error);
- }
- currentRetry++;
- }
- if (!isCheck) {
- return PaymentHelper.DEFAULT_RESULT;
- }
- // 发货处理
- const result = await PaymentHelper.deliverOrder(
- orderInfo,
- ctx.request.ip,
- validation.url,
- out_trade_no
- );
- // 确认和消费Google订单
- try {
- // 确认订单
- let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}`;
- 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}`;
- await axios.post(
- consumeUrl,
- {developerPayload: ""},
- {headers: {"Content-Type": "application/json"}}
- );
- logger.info("Google订单处理完成:", {orderId: orderId});
- } catch (error) {
- logger.error("Google订单确认/消费失败:", error);
- // 即使确认/消费失败,我们仍然返回发货结果,因为发货可能已经成功
- }
- return result;
- };
- /**
- * Apple支付回调处理
- */
- const appleCallPay = async (ctx, config) => {
- let data = ctx.request.body;
- logger.info("Apple支付回调参数:", {url: ctx.href, params: data});
- if (!data.purchaseToken || !data.orderId) {
- return PaymentHelper.DEFAULT_RESULT;
- }
- let receipt_data = data.purchaseToken.replace(/ /g, "+");
- let orderId = data.orderId;
- let out_trade_no = orderId;
- // 更新订单Token
- await Order.updateOrderToken(orderId, receipt_data, "apple");
- // 验证Apple收据
- let maxRetries = 5;
- let currentRetry = 0;
- let isCheck = false;
- while (currentRetry < maxRetries) {
- try {
- const apiData = {
- "receipt-data": receipt_data,
- };
- const response = await axios.post(IosUrl, apiData, {
- headers: {
- "Content-Type": "application/json",
- },
- });
- logger.info(`Apple验证响应状态:${response.data.status}`);
- if (response.data.status == 0) {
- isCheck = true;
- break;
- }
- } catch (error) {
- logger.error("Apple验证请求失败:", error);
- }
- currentRetry++;
- }
- if (!isCheck) {
- logger.info(`Apple票据验证失败!`);
- return {code: 0, msg: "票据验证失败!"};
- }
- // 验证订单
- const validation = await PaymentHelper.validateOrder(orderId);
- if (!validation.valid) {
- return {
- code: validation.message?.includes("重复发货") ? 1 : 0,
- msg: validation.message,
- };
- }
- const orderInfo = validation.orderInfo;
- // 发货处理
- logger.info(`订单${orderId}通知游戏发货开始`);
- const result = await PaymentHelper.deliverOrder(
- orderInfo,
- ctx.request.ip,
- validation.url,
- out_trade_no
- );
- logger.info(`订单${orderId}通知游戏发货结束,结果:`, result);
- return result;
- };
- function splitString(input: string, separator: string): string[] {
- return input.split(separator);
- }
- //验证账号
- const checkUserToken = async (ctx) => {
- let ip = getClientIp(ctx);
- let {
- uid,
- channel_id,
- device_no,
- reg_device,
- device_type,
- device_model,
- device_version,
- system_version,
- platform = ''
- } = ctx.request.body;
- // 前端未传platform时,从内存缓存(thirdLogin写入)中查询补全
- if (channel_id == 17 && !platform && ip) {
- platform = getPlatformCache(ip);
- logger.info("从缓存获取platform:", {platform, ip});
- }
- const create_time = formatDate(new Date());
- const accountInfo = (await User.checkAccountIsExist(uid, channel_id))[0];
- let accountRes = null;
- let res = null;
- if (!accountInfo) {
- accountRes = await User.createAccount(
- uid,
- channel_id,
- ip,
- device_no,
- reg_device,
- create_time,
- platform
- );
- if (accountRes.affectedRows <= 0) {
- return ApiController.fail("添加账户失败");
- }
- }
- res = await User.logAccountLogin(
- uid,
- ip,
- device_type,
- device_no,
- device_model,
- device_version,
- system_version,
- create_time,
- channel_id,
- platform,
- );
- if (res.affectedRows <= 0) {
- return ApiController.fail("添加日志失败");
- }
- return ApiController.success("请求成功", 1, false, {ip: ip});
- };
- class ApiController {
- /**
- * 生成成功响应
- * @param msg 成功消息
- * @param code 成功码,默认为1(部分API使用0表示成功)
- * @param useMessage 是否使用message字段而不是msg字段,默认为false
- * @param data 响应数据
- * @returns 标准化的成功响应对象
- */
- static success(
- msg: string = "请求成功",
- code: number = 1,
- useMessage: boolean = false,
- data: any = null
- ) {
- return {
- code: code,
- [useMessage ? "message" : "msg"]: msg,
- data: data,
- };
- }
- /**
- * 生成失败响应
- * @param msg 错误消息
- * @param code 错误码,默认为0
- * @param data 额外的错误数据
- * @param useMessage 是否使用message字段而不是msg字段,默认为false
- * @returns 标准化的失败响应对象
- */
- static fail(
- msg: string = "请求失败",
- code: number = 0,
- data: any = null,
- useMessage: boolean = false
- ) {
- return {
- code: code,
- [useMessage ? "message" : "msg"]: msg,
- data: data,
- };
- }
- async createOrder(ctx) {
- let {
- uid,
- level,
- amount,
- role_id,
- role_name,
- product_id,
- server_id,
- channel_id,
- platform = '',
- } = ctx.request.body;
- logger.info("create params:", {params: ctx.request.body});
- if (
- !product_id ||
- !server_id ||
- !role_name ||
- !role_id ||
- !amount ||
- !uid ||
- !channel_id
- ) {
- ctx.body = ApiController.fail("参数错误,创建订单失败!!", -1);
- return;
- }
- const data = ctx.request.body;
- if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
- logger.error("创建订单签名验证失败");
- ctx.body = ApiController.fail("签名错误,创建订单失败!!", -1);
- return;
- }
- if (amount <= 0) {
- ctx.body = ApiController.fail("金额错误,创建订单失败!!", -1);
- 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,
- channel_id,
- create_time,
- platform
- );
- if (res.affectedRows > 0) {
- ctx.body = ApiController.success("创建订单成功", 0, false, orderId);
- } else {
- ctx.body = ApiController.fail("创建订单失败", -1, null);
- }
- logger.info("创建订单返回结果:", {params: ctx.body});
- }
- async checkUserToken(ctx) {
- let {channel_id} = ctx.request.body;
- const channelConfig = ChannelConfigManager.getConfig(channel_id);
- if (!channelConfig) {
- logger.info("未找到渠道配置:", {channel_id});
- ctx.body = {
- code: 0,
- msg: "未知渠道id",
- };
- return;
- }
- var result = await checkUserToken(ctx);
- ctx.body = result;
- }
- async thirdLogin(ctx) {
- const data = ctx.request.body;
- let channelId = parseInt(data.channel_id) || 1;
- const platform = data.platform; // 平台参数:ios、Android、miniapp、h5
- logger.info("thirdLogin请求参数:", {data, channelId, platform});
- // 渠道11和渠道12数据打通,统一使用渠道11
- if (channelId === 12) {
- channelId = 11;
- logger.info("渠道12映射到渠道11,平台参数:", platform);
- }
- // 获取渠道配置
- let channelConfig = ChannelConfigManager.getConfig(channelId);
- if (data.is_new == 1) {
- if (channelId == 6) {
- channelConfig = ChannelConfigManager.getConfig(999);
- }
- if (channelId == 1) {
- channelConfig = ChannelConfigManager.getConfig(9);
- }
- }
- if (!channelConfig) {
- logger.info("未找到渠道配置:", {channelId});
- ctx.body = ApiController.fail("未知渠道id");
- return;
- }
- // 从工厂获取对应的渠道处理器
- const handler = channelFactory.getHandler(channelId);
- if (!handler) {
- logger.info("未找到渠道处理器:", {channelId});
- ctx.body = ApiController.fail("未知渠道id");
- return;
- }
- logger.info("使用渠道处理器处理登录:", {
- channelId: channelId,
- channelName: channelConfig.name,
- platform: platform
- });
- // 调用渠道处理器的登录方法
- const result = await handler.handleLogin(ctx, channelConfig);
- // 在返回结果中添加平台信息
- if (result && result.data) {
- result.data.platform = platform || 'unknown';
- }
- // 登录成功且有platform时,缓存到内存供checkUserToken查询
- if (result && result.code === 1 && platform) {
- const ip = getClientIp(ctx);
- const device_no = data.device_no || '';
- if (ip) {
- setPlatformCache(ip, platform);
- logger.info("thirdLogin缓存platform:", {ip, platform});
- }
- }
- // 根据不同渠道的返回格式要求处理结果
- ctx.body = result;
- }
- async callPay(ctx) {
- const data = ctx.request.body;
- let channelId = 1; // 默认渠道ID
- //打印回调参数
- logger.info("callPay支付回调参数:", {url: ctx.href, params: data, query: ctx.query});
- // 从请求中获取渠道ID
- if (ctx.query.channel_id) {
- channelId = parseInt(ctx.query.channel_id);
- }
- if (data.channel_id) {
- channelId = parseInt(data.channel_id);
- }
- logger.info("当前支付渠道id:", {channelId});
- // 获取渠道配置
- let channelConfig = ChannelConfigManager.getConfig(channelId);
- if (!channelConfig) {
- logger.info("未找到渠道配置:", {channelId});
- ctx.body = ApiController.fail("未知渠道id");
- return;
- }
- if (ctx.query.is_new && ctx.query.is_new == 1) {
- if (channelId == 6) {
- channelConfig = ChannelConfigManager.getConfig(999);
- }
- if (channelId == 1) {
- channelConfig = ChannelConfigManager.getConfig(9);
- }
- }
- const handler = channelFactory.getHandler(channelId);
- if (!handler) {
- logger.info("未找到渠道处理器:", {channelId});
- ctx.body = ApiController.fail("未知渠道id");
- return;
- }
- logger.info("使用渠道处理器处理支付:", {
- channelId: channelId,
- channelName: channelConfig.name,
- });
- // 调用渠道处理器的支付方法
- const result = await handler.handlePayment(ctx, channelConfig);
- // 根据不同渠道的返回格式要求处理结果
- switch (channelConfig.channelId) {
- case 6:
- ctx.body = result.code === 1 ? 1 : result.code;
- break;
- case 2:
- case 3:
- case 5:
- case 8:
- ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
- break;
- case 7:
- ctx.body = result.code === 1 ? "success" : "fail";
- break;
- case 11:
- ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
- break;
- case 12:
- ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
- break;
- case 13:
- //{"status":0,"msg":"status 非 0 时,传入失败信息"}
- ctx.body = {status: result.code === 1 ? 0 : -1, msg: result.msg};
- break;
- case 17:
- // 华为渠道:成功返回 {"errCode": 0},失败返回 {"errCode": 1, "errMsg": "..."}
- if (result.code === 0 || result.code === 1) {
- // 发货成功
- if (ctx.query.platform == "mtminiapp") {
- ctx.body = {"code": 0, "msg": "ok"}
- }else {
- ctx.body = {errCode: 0};
- }
- } else {
- // 发货失败
- ctx.body = {errCode: 1, errMsg: result.msg || "发放失败"};
- }
- break;
- case 14:
- case 21:
- ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
- break;
- default:
- ctx.body = result;
- }
- }
- async getServerList(ctx) {
- let tag = ctx.query.channel_id || 1;
- let data = ctx.request.body;
- let ip = getClientIp(ctx);
- // 尝试从渠道ID获取配置
- const channelConfig = ChannelConfigManager.getConfig(1);
- const signStr = data.timestamp + channelConfig.loginConfig?.signKey;
- let newSign = CryptoJS.MD5(signStr).toString();
- if (data.sign != newSign) {
- console.log("signStr:", signStr);
- logger.info(
- `签名错误: 签名串 ${signStr} newSign ${newSign} sign ${data.sign}`
- );
- ctx.body = ApiController.fail("签名错误");
- return;
- }
- let sort = data.sort == 0 ? "asc" : "desc";
- logger.info("区服接口", {ip: ip});
- const servers = await Server.getServerList(tag, 0, sort);
- let serverList = [];
- if (servers.length > 0) {
- servers.forEach(function (element) {
- let status = element.status;
- if ((status == 0 || status == 3) && element.white_list) {
- const list = element.white_list.split(",");
- if (list.length > 0) {
- if (list.includes(ip)) {
- status = 1;
- }
- }
- }
- serverList.push({
- serverId: element.id,
- serverName: element.name,
- });
- });
- }
- ctx.body = ApiController.success("成功", 1, false, serverList);
- }
- async getAllServerList(ctx) {
- let tag = ctx.query.channel_id || 1;
- let uid = ctx.query.uid || ctx.request.body?.uid; // uid是可选参数,支持GET和POST请求
- let ip = getClientIp(ctx);
- logger.info("getAllServerList 区服接口", {tag: tag, uid: uid, ip: ip});
- const servers = await Server.getAllServerList(tag, ip);
- // 如果提供了玩家ID,则查询每个服务器的角色信息;否则只返回基本服务器信息
- if (uid) {
- const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
- // 为每个服务器添加角色信息
- const serversWithRoleInfo = await Promise.all(
- servers.map(async (server) => {
- try {
- const newUniqueTag = `${server.tag}|${server.sid}|${uid}`;
- const roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, server.db_name);
- return {
- ...server,
- roleName: roleInfo?.roleName || null,
- roleLevel: roleInfo?.roleLevel || null,
- head: roleInfo?.head || null,
- hasRole: !!roleInfo
- };
- } catch (error) {
- logger.error(`查询服务器${server.id}角色信息失败:`, error);
- return {
- ...server,
- roleName: null,
- roleLevel: null,
- head: null,
- hasRole: false
- };
- }
- })
- );
- // tag=11 时,找到第一个有角色的服,隐藏它之前的服;都没角色则只显示最新的1个服
- if (tag == 11 || tag === '11') {
- const firstRoleIndex = serversWithRoleInfo.findIndex(s => s.hasRole);
- if (firstRoleIndex > 0) {
- ctx.body = serversWithRoleInfo.slice(firstRoleIndex);
- } else if (firstRoleIndex === -1) {
- ctx.body = serversWithRoleInfo.slice(-1);
- } else {
- ctx.body = serversWithRoleInfo;
- }
- } else {
- ctx.body = serversWithRoleInfo;
- }
- } else {
- ctx.body = servers;
- }
- }
- async enterServer(ctx) {
- let {uid, server_id, channel_id} = ctx.request.body;
- let url = await getServerList(server_id, channel_id || 1);
- if (!url) {
- ctx.body = ApiController.fail(`区服id错误: serverId ${server_id}`, -1);
- return;
- }
- logger.info("create params:", {params: ctx.request.body});
- if (!server_id || !uid) {
- ctx.body = ApiController.fail("参数错误!!", -1);
- return;
- }
- const create_time = formatDate(new Date());
- const serverInfo = (
- await Server.checkEnterServerByUid(uid, server_id, channel_id)
- )[0];
- let res = null;
- if (serverInfo) {
- res = await Server.updateEnterServer(serverInfo.id, create_time);
- } else {
- res = await Server.enterServer(uid, server_id, create_time, channel_id);
- }
- if (res.affectedRows > 0) {
- ctx.body = ApiController.success("请求成功", 0, true, "");
- } else {
- ctx.body = ApiController.fail("请求失败", -1, null, true);
- }
- }
- async getLastServerList(ctx) {
- let {uid, channel_id} = ctx.request.body;
- // uid是可选参数,如果不提供则只返回基本服务器信息
- let tag = channel_id || 1;
- let data = [];
- let isNewAccount = 1;
- let enterServerList = [];
- let ip = getClientIp(ctx);
- logger.info("getLastServerList 区服接口", {uid: uid, ip: ip});
- // 获取渠道配置
- const channelConfig = ChannelConfigManager.getConfig(tag);
- if (!channelConfig) {
- logger.info("未找到渠道配置:", {tag});
- ctx.body = ApiController.fail("未知渠道id");
- return;
- }
- // 如果提供了uid,查询用户进入过的服务器列表
- if (uid) {
- enterServerList = await Server.getEnterServerListByUid(uid, channel_id);
- }
- if (enterServerList.length > 0) {
- isNewAccount = 0;
- const servers = await Server.getAllServerList(tag, ip);
- const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
- // 为每个进入过的服务器添加角色信息
- for (const element of enterServerList) {
- let roleInfo = null;
- // 只有在提供了uid时才查询角色信息
- if (uid) {
- try {
- const newUniqueTag = `${tag}|${element.server_id}|${uid}`;
- roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, element.db_name);
- } catch (error) {
- logger.error(`查询服务器${element.server_id}角色信息失败:`, error);
- }
- }
- const sid = Number(element.server_id) || 1;
- const minSid = Math.floor((sid - 1) / 10) * 10 + 1;
- data.push({
- channel: channelConfig.name, //渠道固定
- minSid: minSid, //最小服务器
- maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
- isNewAccount: isNewAccount, //1为新号 会弹出用户协议
- //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
- sid: element.server_id || 1,
- id: element.server_id || 1,
- name: element.name || "1区",
- tips: element.tips || "",
- server: element.wss
- ? element.wss
- : `ws://${element.ip}:${element.port}`,
- status: element.status || 0,
- // 角色信息(只有在提供了uid时才包含)
- roleName: roleInfo?.roleName || null,
- roleLevel: roleInfo?.roleLevel || null,
- head: roleInfo?.head || null,
- hasRole: !!roleInfo
- });
- }
- logger.info("getLastServerList 区服接口 enterServerList", {
- enterServerList: enterServerList,
- });
- } else {
- const servers = await Server.getAllServerList(tag, ip);
- let roleInfo = null;
- if (servers.length > 0) {
- const serverInfo = servers[servers.length - 1];
- logger.info("getLastServerList 区服接口 serverInfo", {
- serverInfo: serverInfo,
- });
- // 只有在提供了uid时才查询最后一个服务器的角色信息
- if (uid) {
- const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
- try {
- const newUniqueTag = `${serverInfo.tag}|${serverInfo.sid}|${uid}`;
- roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, serverInfo.db_name);
- } catch (error) {
- logger.error(`查询服务器${serverInfo.id}角色信息失败:`, error);
- }
- }
- data.push({
- channel: channelConfig.name, //渠道固定
- minSid: Math.floor(((servers[0].sid || 1) - 1) / 10) * 10 + 1, //最小服务器
- maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
- isNewAccount: isNewAccount, //1为新号 会弹出用户协议
- //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
- sid: serverInfo.sid || 1,
- id: serverInfo.id || 1,
- name: serverInfo.name || "1区",
- tips: serverInfo.tips || "",
- server: serverInfo.server
- ? serverInfo.server
- : `ws://${serverInfo.ip}:${serverInfo.port}/`,
- status: serverInfo.status || 0,
- // 角色信息
- roleName: roleInfo?.roleName || null,
- roleLevel: roleInfo?.roleLevel || null,
- head: roleInfo?.head || null,
- hasRole: !!roleInfo
- });
- } else {
- data.push({
- channel: "未知", //渠道固定
- minSid: 1, //最小服务器
- maxSid: 10, //最大服务器 这里会控制 服务器列表显示的数量
- isNewAccount: isNewAccount, //1为新号 会弹出用户协议
- //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
- sid: 1,
- id: 1,
- name: "1区",
- tips: "",
- server: "",
- status: 0,
- // 角色信息(新用户,无角色)
- roleName: null,
- roleLevel: null,
- head: null,
- hasRole: false
- });
- }
- }
- // 根据sid去重
- const seenSids = new Set();
- data = data.filter(item => {
- if (seenSids.has(item.sid)) return false;
- seenSids.add(item.sid);
- return true;
- });
- // 所有组的minSid统一取最小值
- if (data.length > 0) {
- const globalMinSid = Math.min(...data.map(item => item.minSid));
- data.forEach(item => { item.minSid = globalMinSid; });
- }
- // tag=11 时,找到第一个有角色的服,隐藏它之前的服;都没角色则只显示最新的1个服
- if ((tag == 11 || tag === '11') && enterServerList.length > 0) {
- const firstRoleIndex = data.findIndex(s => s.hasRole);
- if (firstRoleIndex > 0) {
- data = data.slice(firstRoleIndex);
- } else if (firstRoleIndex === -1) {
- data = data.slice(-1);
- }
- }
- ctx.body = data;
- // ctx.body = ApiController.success("获取最近服务器列表成功", 1, false, data);
- }
- async getNotice(ctx) {
- let tag = ctx.query.channel_id || 1;
- let content = "";
- let content_wh = "";
- const system = await System.getSystemConfig(tag);
- if (system) {
- system.forEach((element) => {
- if (element.key == "content") {
- content = element.value;
- }
- if (element.key == "content_wh") {
- content_wh = element.value;
- }
- });
- }
- let notice_data = [
- {
- status: 1,
- content: content,
- content_wh: content_wh,
- },
- ];
- ctx.body = notice_data;
- // ctx.body = ApiController.success("获取公告成功", 1, false, notice_data);
- }
- // 维护服务器,踢掉所有玩家
- async maintenance(ctx) {
- let data = {
- channel_id: parseInt(ctx.query.channel_id),
- serverId: parseInt(ctx.query.serverId) || "",
- };
- logger.info("maintenance :", {channelId: data.channel_id});
- let url = await getServerList(data.serverId, data.channel_id || 1);
- if (!url) {
- ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
- return;
- }
- let param = JSON.stringify({
- type: "kickAllUser",
- });
- let sendMsg = new Msg();
- sendMsg.connect(url, Account);
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO("test", param);
- }, 1000);
- });
- ctx.body = ApiController.success("success", 0, false, null);
- }
- async maintenanceAll(ctx) {
- let channelId = parseInt(ctx.query.channel_id);
- let isMaintenance = ctx.query.isMaintenance;
- let key = ctx.query.key;
- logger.info("maintenanceAll :", {
- channelId: channelId,
- isMaintenance: isMaintenance,
- });
- if (key != "dsdadsadajkkjkxab") {
- ctx.body = ApiController.fail("无权使用", -1);
- return;
- }
- const servers = await Server.getAllServerList(channelId, "");
- logger.info("maintenanceAll servers:", {servers: servers});
- if (servers.length === 0) {
- ctx.body = ApiController.fail("不存在可操作区服", -1);
- return;
- }
- const serversId = servers.map((obj) => obj.id);
- if (isMaintenance == "true") {
- const res = await Server.updateServerStatus(serversId, 3);
- }
- servers.forEach(function (element) {
- let url = "ws://" + element.ip + ":" + element.port;
- if (!url) {
- ctx.body = ApiController.fail(`区服id错误: serverId ${element.id}`, 1);
- return;
- }
- let param = JSON.stringify({
- type: "kickAllUser",
- });
- // Msg.connect(url, Account);
- let sendMsg = new Msg();
- sendMsg.connect(url, Account);
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO("test", param);
- }, 1000);
- });
- });
- logger.info("maintenanceAll 更新的区服id:", {serversId: serversId});
- ctx.body = ApiController.success("success", 0, false, null);
- }
- async sendMail(ctx) {
- let data = ctx.request.body;
- let url = await getServerList(data.serverId, data.channel_id || 1);
- if (!url) {
- ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
- return;
- }
- let param = JSON.stringify({
- type: "sendMail",
- mail: JSON.stringify({
- uuid: data.uuid,
- title: data.title,
- content: data.content,
- items: JSON.parse(data.items),
- expire: data.expire,
- }),
- });
- // Msg.connect(url, Account);
- let sendMsg = new Msg();
- sendMsg.connect(url, Account);
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO("test", param);
- }, 1000);
- });
- ctx.body = ApiController.success("success", 0, false, null);
- }
- async sendAllMail(ctx) {
- let data = ctx.request.body;
- if (!data.server_list || data.server_list.length === 0) {
- ctx.body = ApiController.fail("区服不能为空", -1);
- return;
- }
- logger.info("sendAllMail 接口请求 data:", {data: data});
- const server_list = data.server_list;
- const servers = await Server.getServerList(data.channel_id || 1);
- const filteredServer = servers.filter((item) =>
- server_list.includes(item.id)
- );
- filteredServer.forEach(function (element) {
- let url = "ws://" + element.ip + ":" + element.port;
- if (!url) {
- ctx.body = ApiController.fail(
- `区服id错误: serverId ${element.server_id}`,
- 1
- );
- return;
- }
- let param = JSON.stringify({
- type: "sendAllMail",
- mail: JSON.stringify({
- title: data.title,
- content: data.content,
- items: JSON.parse(data.items),
- expire: data.expire,
- }),
- });
- let sendMsg = new Msg();
- sendMsg.connect(url, Account);
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO("test", param);
- }, 1000);
- });
- });
- ctx.body = ApiController.success("success", 0);
- }
- async useCDKV2(ctx) {
- let body = ctx.request.body;
- logger.info("useCDKV2接口请求参数:", {data: body});
- let data = {
- code: body.code,
- userId: body.account,
- channelId: body.channel_id || 0,
- };
- if (body.uuid) {
- data.userId = body.uuid;
- }
- let serverUrl = await getServerAddr(body.serverId, body.channel_id);
- let err = "";
- if (!serverUrl) {
- ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
- return;
- }
- let port = 8004;
- let host = "127.0.0.1";
- let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
- logger.info("接口请求后台 data:", {data: data, url: url});
- try {
- const specialCodes = [
- "gfyx555",
- "gfyx666",
- "gfyx777",
- "gfyx1000",
- "gfyx2000",
- "gfyx3000",
- "gfyxrqlb",
- "GFYX555",
- "GFYX666",
- "GFYX777",
- "GFYX1000",
- "GFYX2000",
- "GFYX3000",
- "GFYXrqlb",
- "GFYX000",
- "GFYX222",
- "GFYX333",
- "GFYX888",
- "GFYX1818",
- "GQ888",
- "ZQ888",
- "gfyx8888",
- "gfyx6666",
- "gfyx7777",
- "gfyxxjbc",
- "LIDONGLB",
- "XIAOXULB",
- "GANENLB",
- "WANSHLB",
- "HERO666",
- "HERO777",
- "HERO888",
- "gfyx9999",
- "aiqi6666",
- "aiqi7777",
- "aiqi8888",
- "aiqi9999",
- "gf555",
- "gf666",
- "gf777",
- "gf100",
- "gf200",
- "gf300",
- "YDKL888",
- "SDKL888",
- "CHUXILB",
- "CHUNJIELB",
- "YUANXIAOLB",
- "VIP555",
- "VIP666",
- "VIP777",
- "VIP888",
- ];
- let param: string = "";
- const h5Codes = ["gfyx000", "gfyx222", "gfyx333", "gfyx888", "gfyx1818"];
- if (h5Codes.includes(data.code) && body.channel_id != 5) {
- ctx.body = ApiController.fail("该激活码无法在h5渠道使用", 1);
- }
- if (specialCodes.includes(data.code) || h5Codes.includes(data.code)) {
- param = JSON.stringify({
- code: data.code,
- type: "UseFixCDK",
- channel_id: body.channel_id,
- });
- } else {
- const response = await axios.post(url, data, {
- headers: {
- "Content-Type": "application/json",
- },
- timeout: 10000,
- });
- logger.info("接口请求后台 接口返回 response:", {data: response.data});
- if (response.data.code != 200) {
- ctx.body = ApiController.fail(response.data.msg, 1);
- return;
- }
- const result = splitString(response.data.data, ";");
- // 重构itemList
- let itemList = Array();
- for (let i = 0; i < result.length; i++) {
- let elem = splitString(result[i], ":");
- let output0 = parseInt(elem[0], 10);
- let output1 = parseInt(elem[1], 10);
- itemList.push([output0, output1]);
- }
- param = JSON.stringify({
- type: "UseCDKV2",
- itemList: itemList,
- channel_id: body.channel_id,
- });
- }
- let sendMsg = new Msg();
- sendMsg.connect(serverUrl, Account);
- logger.info("api cdk 发送服务器 param:", {param: param});
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO(body.account, param, body.serverId);
- }, 1000);
- });
- } catch (error) {
- console.log(error);
- }
- ctx.body = ApiController.success("success", 0);
- }
- async banUser(ctx) {
- let data = ctx.request.body;
- logger.info("banUser 接口请求 data:", {data: data});
- if (!data.server_tag) {
- ctx.body = ApiController.fail("区服id不能为空", -1, "");
- return;
- }
- let banInfo = {};
- switch (parseInt(data.ban_type)) {
- case 1:
- banInfo = {
- roleBanInfo: {
- channelTag: data.channel_id,
- serverTag: data.server_tag,
- roleTag: data.role_tag,
- banTime: data.ban_time,
- },
- type: "setBan",
- };
- break;
- case 2:
- banInfo = {
- accountBanInfo: {
- channelTag: data.channel_id,
- accountTag: data.account_tag,
- banTime: data.ban_time,
- },
- type: "setBan",
- };
- break;
- case 3:
- banInfo = {
- appBanInfo: {
- appId: data.device_id,
- banTime: data.ban_time,
- },
- type: "setBan",
- };
- break;
- default:
- }
- logger.info("banUser 发送服务器 banInfo:", banInfo);
- let url = await getServerList(data.server_tag, data.channel_id);
- if (!url) {
- ctx.body = ApiController.fail(
- `区服id错误: serverId ${data.server_tag}`,
- 1
- );
- return;
- }
- let param = JSON.stringify(banInfo);
- logger.info("banUser 发送服务器 json字符串: " + param);
- let sendMsg = new Msg();
- sendMsg.connect(url, Account);
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO("test", param, data.server_tag);
- // sendMsg.CG_SET_BAN(param);
- }, 1000);
- });
- ctx.body = ApiController.success("success", 0);
- }
- async uicFilter4399(ctx) {
- let body = ctx.request.body;
- let channelConfig = ChannelConfigManager.getConfig(6);
- if (body.is_new == 1) {
- channelConfig = ChannelConfigManager.getConfig(999);
- }
- logger.info("uicFilter4399 body:", {data: body});
- let toCheck = body.toCheck;
- let signStr = channelConfig.loginConfig?.signKey + toCheck;
- logger.info("uicFilter4399 signStr:", {signStr: signStr});
- let apiParams = {
- toCheck: toCheck,
- app: channelConfig.loginConfig.appId,
- byPinyin: true,
- isBatch: false,
- sig: CryptoJS.MD5(signStr).toString(),
- };
- logger.info("uicFilter4399 apiParams:", {data: apiParams});
- const queryStr = Object.entries(apiParams)
- .map(
- ([key, value]) =>
- `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
- )
- .join("&");
- let url = "https://wo.webgame138.com/test/matchService.do" + "?" + queryStr;
- // let url = "https://wo.webgame138.com/test/matchService.do";
- logger.info("uicFilter4399 url:", {url: url});
- try {
- // let response = await axios.get(url, {
- // timeout: 10000, // 设置10秒超时
- // });
- const response = await axios.post(url, apiParams, {
- headers: {
- "Content-Type": "application/json",
- },
- });
- logger.info("uicFilter4399 接口返回 response:", {data: response.data});
- ctx.body = ApiController.success("success", 0, false, response.data);
- } catch (error) {
- console.log(error);
- ctx.body = ApiController.fail(error.message || "请求失败", 1);
- }
- }
- async roleList4399(ctx) {
- let body = ctx.request.body;
- logger.info("RoleList4399 请求参数:", {body: body});
- let data = {
- userId: body.userId,
- server: body.server,
- is_new: ctx.query.is_new || 0
- };
- let port = 8004;
- let host = "127.0.0.1";
- let url = "http://" + host + ":" + port + "/api/roleList/checkBy4399";
- logger.info("RoleList4399 url:", {url: url});
- try {
- const response = await axios.post(url, data, {
- headers: {
- "Content-Type": "application/json",
- },
- });
- logger.info("RoleList4399 返回 response:", {data: response.data});
- ctx.body = response.data;
- } catch (error) {
- console.log(error);
- }
- }
- async cdkBy4399(ctx) {
- let body = ctx.request.body;
- logger.info("cdkBy4399:", {data: body});
- let server = body.server || 1;
- let channel = 5;
- let data = {
- code: body.giftId,
- userId: body.userId,
- channelId: channel,
- };
- if (body.uuid) {
- data.userId = body.uuid;
- }
- let serverUrl = await getServerList(server, channel);
- let err = "";
- if (!serverUrl) {
- ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
- return;
- }
- let port = 8004;
- let host = "127.0.0.1";
- let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
- logger.info("cdkBy4399接口请求后台 data:", {data: data, url: url});
- try {
- const response = await axios.post(url, data, {
- headers: {
- "Content-Type": "application/json",
- },
- timeout: 10000,
- });
- logger.info("cdkBy4399接口请求后台 接口返回 response:", {
- data: response.data,
- });
- if (response.data.code != 200) {
- ctx.body = ApiController.fail(response.data.msg, 10004);
- return;
- }
- const result = splitString(response.data.data, ";");
- // 重构itemList
- let itemList = Array();
- for (let i = 0; i < result.length; i++) {
- let elem = splitString(result[i], ":");
- let output0 = parseInt(elem[0], 10);
- let output1 = parseInt(elem[1], 10);
- itemList.push([output0, output1]);
- }
- let param = JSON.stringify({
- type: "UseCDKV2",
- itemList: itemList,
- channel_id: channel,
- });
- let sendMsg = new Msg();
- sendMsg.connect(serverUrl, Account);
- logger.info("cdkBy4399 cdk 发送服务器 param:", {param: param});
- new Promise((resolve) => {
- setTimeout(async () => {
- sendMsg.CG_TEST_PROTO("test", param, server);
- }, 1000);
- });
- } catch (error) {
- console.log(error);
- }
- ctx.body = ApiController.success("success", 10000);
- }
- async roleListYfy(ctx) {
- let gameCode = ctx.query.gameCode;
- let timestamp = ctx.query.timestamp;
- let uid = ctx.query.uid;
- let sign = ctx.query.sign;
- let AppSecret = "H1EqhbpA80jt0Jw6Q3T2";
- logger.info("roleListYfy 请求参数:", {
- uid: uid,
- gameCode: gameCode,
- timestamp: timestamp,
- });
- const signStr = `gameCode-${gameCode}×tamp=${timestamp}&uid=${uid}${AppSecret}`;
- const newSign = CryptoJS.MD5(signStr).toString();
- if (newSign != sign) {
- logger.info("roleListYfy 签名错误:", {
- signStr: signStr,
- sign: sign,
- newSign: newSign,
- });
- ctx.body = ApiController.fail("签名错误!!", -1);
- }
- let port = 8004;
- let host = "127.0.0.1";
- let url = "http://" + host + ":" + port + "/api/roleList/checkByYfy";
- logger.info("roleListYfy url:", {url: url});
- try {
- const response = await axios.post(
- url,
- {
- userId: uid,
- },
- {
- headers: {
- "Content-Type": "application/json",
- },
- }
- );
- logger.info("roleListYfy 返回 response:", {data: response.data});
- ctx.body = response.data;
- } catch (error) {
- console.log(error);
- }
- }
- async getQuickSign(ctx) {
- let data = ctx.request.body;
- logger.info("getQuickSign 请求参数:", {body: data});
- if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
- logger.error("签名验证失败");
- ctx.body = ApiController.fail("签名错误!!", -1);
- return;
- }
- let key = "H1EqhbpA80jt0Jw6Q3T2";
- let signStr =
- "uid=" +
- data.uid +
- "&username=" +
- data.username +
- "&serverId=" +
- data.serverId +
- "&serverName=" +
- data.serverName +
- "&userRoleId=" +
- data.userRoleId +
- "&userRoleName=" +
- data.userRoleName +
- "&userRoleLevel=" +
- data.userRoleLevel +
- "&vipLevel=" +
- data.vipLevel +
- "&gameRolePower=" +
- data.gameRolePower +
- "&key=" +
- key;
- logger.info("getQuickSign signStr:", {signStr: signStr});
- data.sign = CryptoJS.MD5(signStr).toString();
- ctx.body = ApiController.success("success", 0, false, data);
- }
- /**
- * mianyou开服同步处理
- * @param ctx Koa上下文
- */
- async mianyouSyncServer(ctx) {
- try {
- const data = ctx.request.body;
- logger.info("mianyou开服同步请求参数:", {data});
- // 验证必要参数
- const {serverId, gameServerId, serverName, startTime, channelId} = data;
-
- if (!serverId || !gameServerId || !serverName || !startTime) {
- logger.warn("mianyou开服同步失败: 缺少必要参数", {data});
- ctx.body = ApiController.fail("缺少必要参数: serverId, gameServerId, serverName, startTime");
- return;
- }
- // 获取渠道配置
- const channelConfig = ChannelConfigManager.getConfig(channelId || 1);
- if (!channelConfig) {
- logger.error("mianyou开服同步失败: 未找到渠道配置", {channelId});
- ctx.body = ApiController.fail("未找到渠道配置");
- return;
- }
- // 创建MianyouChannelHandler实例
- const mianyouHandler = new MianyouChannelHandler();
- // 调用开服同步方法
- const result = await mianyouHandler.openServer(
- parseInt(serverId),
- gameServerId,
- serverName,
- startTime,
- channelConfig
- );
- logger.info("mianyou开服同步结果:", {result});
- // 根据返回结果设置响应
- if (result.status === 0) {
- ctx.body = ApiController.success("开服同步成功", 0, false, result);
- } else {
- ctx.body = ApiController.fail(result.msg || "开服同步失败", result.status);
- }
- } catch (error) {
- logger.error("mianyou开服同步异常:", error);
- ctx.body = ApiController.fail("服务器内部错误", -1);
- }
- }
- }
- module.exports = new ApiController();
|