315 lines
13 KiB
TypeScript
315 lines
13 KiB
TypeScript
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;
|
||
}
|
||
}
|