Files
ZYZ/web-server/app/controller/game.ts
2023-04-18 11:35:34 +08:00

315 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { UserModel } from '@db/User';
import { LadderMatchRecModel } from '@db/LadderMatchRec';
import { PvpRecordModel } from '@db/PvpRecord';
import { BattleRecordModel } from '@db/BattleRecord';
import { STATUS, WAR_TYPE } from '@consts';
import { Controller } from 'egg';
import * as fs from 'fs';
import { RoleModel } from '@db/Role';
import { NoticeModel } from '@db/Notice';
import { ServerParamWithRole, GroupParam } from '../domain/gameField/serverlist';
import { reloadResources } from 'app/pubUtils/data';
import { ServerlistModel } from '@db/Serverlist';
import { dispatch } from 'app/pubUtils/dispatcher';
import { RedisClient } from 'redis';
import { REDIS_KEY } from '@consts';
import { RegionModel } from '@db/Region';
import { getRandEelmWithWeight } from 'app/pubUtils/util';
import { getLocalRplUrl, getRemoteRplUrl } from 'app/pubUtils/battleUtils'
import { ChannelInfoModel } from '@db/ChannelInfo';
import { GVGVestigeRecModel } from '@db/GVGVestigeRec';
import { GVGBattleRecModel } from '@db/GVGBattleRec';
import { PackageModel } from '@db/Package';
const sendToWormhole = require('stream-wormhole');
const pump = require('mz-modules/pump');
export default class GameController extends Controller {
public async checkVersion() {
const { ctx } = this;
const { version } = ctx.request.body;
let curRegion = await RegionModel.findRegionByEnv(this.app.config.realEnv);
if(!curRegion) {
return ctx.body = ctx.service.utils.resResult(STATUS.VERSION_ERR);
}
const versionFlag = ctx.service.utils.compareVersion(version, curRegion.minVersion);
if (versionFlag >= 0) {
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS);
return;
}
//版本号太低
ctx.body = ctx.service.utils.resResult(STATUS.VERSION_ERR, { version: curRegion.minVersion });
return;
}
public async checkReview() {
const { ctx } = this;
const { version, platformAppid, platformAppId, addressType } = ctx.request.body;
let curRegion = await RegionModel.findRegionByEnv(this.app.config.realEnv);
if(!curRegion) {
return ctx.body = ctx.service.utils.resResult(STATUS.VERSION_ERR);
}
if(curRegion.addressType != addressType) {
return ctx.body = ctx.service.utils.resResult(STATUS.ADDRESS_ERR);
}
let hasPolicy = false, userPolicyLink = '', privacyPolicyLink = ''; // 是否需要替换协议,有就是用下面两个字段替换
let platform = platformAppid ?? platformAppId;
let channelInfo = await ChannelInfoModel.findByPlatform(platform);
if(channelInfo && !channelInfo.isDefaultPolicy) {
hasPolicy = true;
userPolicyLink = channelInfo.userPolicyLink;
privacyPolicyLink = channelInfo.privacyPolicyLink;
}
let isReview = await ctx.service.update.checkReview(curRegion, version);
let hasNewWebServer = false, webServerUrl = '';
if(isReview && curRegion.reviewEnv) {
let reviewRegion = await RegionModel.findRegionByEnv(curRegion.reviewEnv);
if(reviewRegion) {
hasNewWebServer = true, webServerUrl = reviewRegion.webHost;
}
}
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isReview, hasNewWebServer, webServerUrl, hasPolicy, userPolicyLink, privacyPolicyLink });
return;
}
public async getServerList() {
try {
const { ctx } = this;
let { uid } = ctx;
const { version, addressType, pid, gid } = ctx.request.body;
let serverList = new Array<GroupParam>();
let loginServerList = new Array<ServerParamWithRole>();
let curRegion = await RegionModel.findRegionByEnv(this.app.config.realEnv);
if(!curRegion) {
return ctx.body = ctx.service.utils.resResult(STATUS.VERSION_ERR);
}
if(curRegion.addressType != addressType) {
return ctx.body = ctx.service.utils.resResult(STATUS.ADDRESS_ERR);
}
let isReview = await ctx.service.update.checkReview(curRegion, version);
let env = isReview? curRegion.reviewEnv: ctx.app.config.realEnv;
let allServers = await ServerlistModel.findByEnv(env||ctx.app.config.realEnv, isReview);
if(pid && gid) {
const pkg = await PackageModel.getPackageByGidPid(gid, pid);
if(pkg && pkg.hideServers && pkg.hideServers.length > 0) {
allServers = allServers.filter(server => !pkg.hideServers.includes(server.id));
}
}
let roles = await RoleModel.findAllByUid(uid, true, true);
for (let server of allServers) {
let curGroup = serverList.find(cur => cur.groupId == server.groupId);
if (!curGroup) {
curGroup = new GroupParam(server);
serverList.push(curGroup);
}
curGroup.pushServer(server);
let role = roles.find(role => role.serverId == server.id);
if (!!role) {
let curLoginInfo = new ServerParamWithRole(role, server);
loginServerList.push(curLoginInfo);
}
}
loginServerList.sort((a, b) => { return b.updatedAt.getTime() - a.updatedAt.getTime() });
if (serverList) {
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { serverList, loginServerList });
} else {
ctx.body = ctx.service.utils.resResult(STATUS.SERVER_NOT_FOUND);
}
return
}catch(e) {
console.error(e);
}
}
public async getnotice() {
const { ctx } = this;
let notice = await NoticeModel.getAllNotice();
let result = notice.map(cur => {
let { id, title, tag, type, content, time } = cur;
return {
id, title, tag, type, content, time
}
})
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { notice: result });
return
}
public async reloadResource() {
const { ctx } = this;
try {
reloadResources();
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true });
return;
} catch (e) {
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: (<Error>e).stack });
return;
}
}
public async queryEnter() {
const { ctx } = this;
const { app, userCode } = ctx;
let redisClient: RedisClient = app.context.redisClient;
let hash = await redisClient.hvalsAsync(REDIS_KEY.SYS_SERVER);
let connectors = hash.map(cur => JSON.parse(cur));
if (!connectors || connectors.length === 0) {
ctx.body = ctx.service.utils.resResult(STATUS.CONNECTOR_ERR);
return
}
// select connector
let sum = connectors.reduce((pre, cur) => pre + (cur['num']||0), 0);
let res;
if(sum > 0) {
let serversWithWeight = connectors.map(cur => ({...cur, weight: sum - (cur['num']||0)}));
let randResult = getRandEelmWithWeight(serversWithWeight);
res = randResult.dic;
}
if(!res) {
res = dispatch(userCode, connectors, 'connector');
}
let { id, serverType, clientHost, clientPort, num = 0 } = res;
await redisClient.hsetAsync(REDIS_KEY.SYS_SERVER, id, JSON.stringify({ serverType, clientHost, clientPort, id, num: num + 1 }));
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { host: res.clientHost, port: res.clientPort });
return
}
public async upload() {
const { ctx } = this;
const parts = ctx.multipart();
let part;
let [writePath, token, battleCode, fullPath, remoteUrl, warType] = ['', '', '', '', '', 0];
while ((part = await parts()) != null) {
if (part.length) {
console.log('kv: ', `${part[0]}: ${part[1]}`);
if (part[0] === 'token') {
token = part[1];
} else if (part[0] === 'battleCode') {
battleCode = part[1];
} else if (part[0] === 'warType') {
// 检测 part[1] 类型
if (typeof part[1] === 'number') {
warType = part[1];
} else if (typeof part[1] === 'string' && !isNaN(parseInt(part[1]))) {
warType = parseInt(part[1]);
}
}
} else {
if (!part.filename) {
continue;
}
console.log(part);
if (part.fieldname === 'rpl' && battleCode !== '') {
console.log('field: ', part.fieldname);
console.log('filename: ', part.filename);
if (token === '') {
ctx.body = ctx.service.utils.resResult(STATUS.WRONG_PARMS);
return;
}
const user = await UserModel.findUserByToken(token);
if (!user) {
console.error('token invalid');
ctx.body = ctx.service.utils.resResult(STATUS.TOKEN_ERR);
return;
}
let roleId = '';
if (!!warType && warType === WAR_TYPE.GVG_BATTLE) { // gvg激战期录像没有通用 BattleRecord单独处理
let gvgBattleRec = await GVGBattleRecModel.findByBattleCode(battleCode);
if (!gvgBattleRec) return ctx.body = ctx.service.utils.resResult(STATUS.BATTLE_NOT_FOUND);
roleId = gvgBattleRec.attackTeam?.roleId;
if (!roleId) return ctx.body = ctx.service.utils.resResult(STATUS.BATTLE_NOT_FOUND);
} else {
let battleRec = await BattleRecordModel.getBattleRecordByCode(battleCode, true);
if (!battleRec) return ctx.body = ctx.service.utils.resResult(STATUS.BATTLE_NOT_FOUND);
roleId = battleRec.roleId;
warType = battleRec.warType;
if (warType !== WAR_TYPE.PVP && warType !== WAR_TYPE.LADDER && warType !== WAR_TYPE.GVG_VESTIGE) return ctx.body = ctx.service.utils.resResult(STATUS.BATTLE_RPL_NOT_SUPPORT);
}
writePath = getLocalRplUrl(roleId, warType, battleCode);
try {
fs.accessSync(writePath);
} catch (err) {
if (err) {
fs.mkdirSync(writePath, { recursive: true });
}
}
fullPath = `${writePath}/${battleCode}.bin`
console.log(fullPath);
if (!fs.existsSync(fullPath)) {
fs.writeFileSync(fullPath, '');
}
const writeStream = fs.createWriteStream(fullPath);
await pump(part, writeStream);
remoteUrl = `${getRemoteRplUrl(ctx.app.config.realEnv, ctx.app.config.sshHost,roleId, warType, battleCode)}/${battleCode}.bin`;
let updateDBRes;
if (warType === WAR_TYPE.PVP) {
updateDBRes = await PvpRecordModel.updateRplStatus(battleCode, true, remoteUrl);
} else if (warType === WAR_TYPE.LADDER) {
updateDBRes = await LadderMatchRecModel.updateRplStatus(battleCode, true, remoteUrl);
} else if (warType == WAR_TYPE.GVG_VESTIGE) {
updateDBRes = await GVGVestigeRecModel.updateRplStatus(battleCode, true, remoteUrl);
} else if (warType == WAR_TYPE.GVG_BATTLE) {
updateDBRes = await GVGBattleRecModel.updateRplStatus(battleCode, true, remoteUrl);
}
if (!updateDBRes) return ctx.body = ctx.service.utils.resResult(STATUS.BATTLE_RPL_UPDATE_ERR);
} else {
await sendToWormhole(part);
}
}
}
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { rplUrl: remoteUrl });
return;
}
// 根据 pid 和 gid 获取大区地址
public async getRegionAddr() {
const { ctx } = this;
const { pid, gid } = ctx.request.body;
if (!pid || !gid) {
ctx.body = ctx.service.utils.resResult(STATUS.WRONG_PARMS);
return;
}
const pkg = await PackageModel.getPackageByGidPid(gid, pid);
if (!pkg) {
ctx.body = ctx.service.utils.resResult(STATUS.PACKAGE_NOT_FOUND);
return;
}
const { regionId, loginPage = '', loadingPage = '' } = pkg;
const region = await RegionModel.findRegionById(regionId);
if (!region) {
ctx.body = ctx.service.utils.resResult(STATUS.REGION_NOT_FOUND);
return;
}
const { webHost = 'https://sq7-web-sgzzyz.yev242.com', addressType = 9 } = region;
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { webHost, addressType, loginPage, loadingPage });
return;
}
}