195 lines
7.0 KiB
TypeScript
195 lines
7.0 KiB
TypeScript
const modulename = 'WebServer:FXServerCommands';
|
|
import { AuthedCtx } from '@modules/WebServer/ctxTypes';
|
|
import consoleFactory from '@lib/console';
|
|
import { ApiToastResp } from '@shared/genericApiTypes';
|
|
import { txEnv } from '@core/globalData';
|
|
const console = consoleFactory(modulename);
|
|
|
|
//Helper functions
|
|
const delay = async (ms: number) => {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
};
|
|
|
|
|
|
/**
|
|
* Handle all the server commands
|
|
* @param {object} ctx
|
|
*/
|
|
export default async function FXServerCommands(ctx: AuthedCtx) {
|
|
if (
|
|
typeof ctx.request.body.action === 'undefined'
|
|
|| typeof ctx.request.body.parameter === 'undefined'
|
|
) {
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'error',
|
|
msg: 'Invalid request.',
|
|
});
|
|
}
|
|
const action = ctx.request.body.action;
|
|
const parameter = ctx.request.body.parameter;
|
|
|
|
//Ignore commands when the server is offline
|
|
if (!txCore.fxRunner.child?.isAlive) {
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'error',
|
|
msg: 'The server is not running.',
|
|
});
|
|
}
|
|
|
|
//Block starting/restarting the 'runcode' resource
|
|
const unsafeActions = ['restart_res', 'start_res', 'ensure_res'];
|
|
if (unsafeActions.includes(action) && parameter.includes('runcode')) {
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'error',
|
|
msg: 'The resource "runcode" might be unsafe. <br> If you know what you are doing, run it via the Live Console.',
|
|
});
|
|
}
|
|
|
|
|
|
//==============================================
|
|
//DEBUG: Only available in the /advanced page
|
|
//FIXME: move to the advanced route, give button for profiling, saving mem snapshot, verbose, etc.
|
|
if (action == 'profile_monitor') {
|
|
if (!ensurePermission(ctx, 'all_permissions')) return false;
|
|
ctx.admin.logAction('Profiling txAdmin instance.');
|
|
|
|
const profileDuration = 5;
|
|
const savePath = `${txEnv.profilePath}/data/txProfile.bin`;
|
|
ExecuteCommand('profiler record start');
|
|
await delay(profileDuration * 1000);
|
|
ExecuteCommand('profiler record stop');
|
|
await delay(150);
|
|
ExecuteCommand(`profiler save "${savePath}"`);
|
|
await delay(150);
|
|
console.ok(`Profile saved to: ${savePath}`);
|
|
txCore.fxRunner.sendCommand('profiler', ['view', savePath], ctx.admin.name);
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'success',
|
|
msg: 'Check your live console in a few seconds.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'admin_broadcast') {
|
|
if (!ensurePermission(ctx, 'announcement')) return false;
|
|
const message = (parameter ?? '').trim();
|
|
|
|
// Dispatch `txAdmin:events:announcement`
|
|
txCore.fxRunner.sendEvent('announcement', {
|
|
message,
|
|
author: ctx.admin.name,
|
|
});
|
|
ctx.admin.logAction(`Sending announcement: ${parameter}`);
|
|
|
|
// Sending discord announcement
|
|
const publicAuthor = txCore.adminStore.getAdminPublicName(ctx.admin.name, 'message');
|
|
txCore.discordBot.sendAnnouncement({
|
|
type: 'info',
|
|
title: {
|
|
key: 'nui_menu.misc.announcement_title',
|
|
data: { author: publicAuthor }
|
|
},
|
|
description: message
|
|
});
|
|
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'success',
|
|
msg: 'Announcement command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'kick_all') {
|
|
if (!ensurePermission(ctx, 'control.server')) return false;
|
|
const kickReason = (parameter ?? '').trim() || txCore.translator.t('kick_messages.unknown_reason');
|
|
const dropMessage = txCore.translator.t(
|
|
'kick_messages.everyone',
|
|
{ reason: kickReason }
|
|
);
|
|
ctx.admin.logAction(`Kicking all players: ${kickReason}`);
|
|
// Dispatch `txAdmin:events:playerKicked`
|
|
txCore.fxRunner.sendEvent('playerKicked', {
|
|
target: -1,
|
|
author: ctx.admin.name,
|
|
reason: kickReason,
|
|
dropMessage,
|
|
});
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'success',
|
|
msg: 'Kick All command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'restart_res') {
|
|
if (!ensurePermission(ctx, 'commands.resources')) return false;
|
|
ctx.admin.logAction(`Restarted resource "${parameter}"`);
|
|
txCore.fxRunner.sendCommand('restart', [parameter], ctx.admin.name);
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'warning',
|
|
msg: 'Resource restart command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'start_res') {
|
|
if (!ensurePermission(ctx, 'commands.resources')) return false;
|
|
ctx.admin.logAction(`Started resource "${parameter}"`);
|
|
txCore.fxRunner.sendCommand('start', [parameter], ctx.admin.name);
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'warning',
|
|
msg: 'Resource start command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'ensure_res') {
|
|
if (!ensurePermission(ctx, 'commands.resources')) return false;
|
|
ctx.admin.logAction(`Ensured resource "${parameter}"`);
|
|
txCore.fxRunner.sendCommand('ensure', [parameter], ctx.admin.name);
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'warning',
|
|
msg: 'Resource ensure command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'stop_res') {
|
|
if (!ensurePermission(ctx, 'commands.resources')) return false;
|
|
ctx.admin.logAction(`Stopped resource "${parameter}"`);
|
|
txCore.fxRunner.sendCommand('stop', [parameter], ctx.admin.name);
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'warning',
|
|
msg: 'Resource stop command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else if (action == 'refresh_res') {
|
|
if (!ensurePermission(ctx, 'commands.resources')) return false;
|
|
ctx.admin.logAction(`Refreshed resources`);
|
|
txCore.fxRunner.sendCommand('refresh', [], ctx.admin.name);
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'warning',
|
|
msg: 'Refresh command sent.',
|
|
});
|
|
|
|
//==============================================
|
|
} else {
|
|
return ctx.send<ApiToastResp>({
|
|
type: 'error',
|
|
msg: 'Unknown Action.',
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
//================================================================
|
|
/**
|
|
* Wrapper function to check permission and give output if denied
|
|
*/
|
|
function ensurePermission(ctx: AuthedCtx, perm: string) {
|
|
if (ctx.admin.testPermission(perm, modulename)) {
|
|
return true;
|
|
} else {
|
|
ctx.send<ApiToastResp>({
|
|
type: 'error',
|
|
msg: 'You don\'t have permission to execute this action.',
|
|
});
|
|
return false;
|
|
}
|
|
}
|