I am currently working on a web admin panel system for managing game servers for a particular game and mod. I wish to implement in the panel a feature to allow you to start and stop the servers individually by clicking start and stop buttons.
To be able to label the server processes and their children such that I can find them again later to kill I am using Linux screens and labelling them. I am using nodejs's spawn command to start the screen. As shown here:
console.log(`screen -m -d -S serverscreen${server.id} wine ${(args.disableWSE === true) ? 'mb_warband_dedicated.exe' : 'WSELoaderServer.exe'} -r "Configs/${args.config}" -m "${args.module}"`);
const program = spawn(
'screen',
[
'-m', '-d',
'-S', `serverscreen${server.id}`,
'wine',
(args.disableWSE === true) ? 'mb_warband_dedicated.exe' : 'WSELoaderServer.exe',
'-r', `Configs/${args.config}`,
'-m', `${args.module}`
],
{
cwd: currentGameserverPath,
detached: true,
stdio: 'ignore'
}
);
However, I am facing an issue that I have exhausted all my knowledge on trying to solve. The command does not work when used in the spawn, i.e. I can run the command shown in the console.log
into the cwd
directory and the gameserver will happily start, however, when the spawn command is called the screen does not start. I have logged stderr and stdout and both are empty and the spawn exits with 0
.
Any suggestions?
For greater context, here is the remainder of the function that encapsulates this code snippet:
export default async (parent, args, context) => {
/* Check for Permissions */
if (context.user === null)
throw new Error('You must be logged in to complete this action.');
const requestingAdmin = await AdminPermission.findOne({
server: args.serverID,
admin: context.user
});
if (requestingAdmin === null)
throw new Error('You do not have permission to do that.');
const server = await Server.findOne({
id: args.serverID
});
if(server === null) throw new Error('Server not found.');
const currentGameserverPath = path.join(
require.resolve('gameservers'),
`../${server.id}`
);
if (!fs.existsSync(currentGameserverPath))
throw new Error('Server folder does not exist!');
const executablePath = path.join(
currentGameserverPath,
(args.disableWSE === true) ? '/mb_warband_dedicated.exe' : '/WSELoaderServer.exe'
);
if (!fs.existsSync(executablePath)) throw new Error('Executable does not exist!');
const moduleFolder = path.join(currentGameserverPath, `/Modules/${args.module}`);
if (!fs.existsSync(moduleFolder)) throw new Error('Module does not exist!');
let configFile = path.join(currentGameserverPath, `/Configs/${args.config}`);
if (!fs.existsSync(configFile)) throw new Error('Config does not exist!');
console.log(`screen -m -d -S serverscreen${server.id} wine ${(args.disableWSE === true) ? 'mb_warband_dedicated.exe' : 'WSELoaderServer.exe'} -r "Configs/${args.config}" -m "${args.module}"`);
const program = spawn(
'screen',
[
'-m', '-d',
'-S', `serverscreen${server.id}`,
'wine',
(args.disableWSE === true) ? 'mb_warband_dedicated.exe' : 'WSELoaderServer.exe',
'-r', `Configs/${args.config}`,
'-m', `${args.module}`
],
{
cwd: currentGameserverPath,
detached: true,
stdio: 'ignore'
}
);
program.unref();
server.gameserverLastModule = args.module;
server.gameserverLastConfig = args.config;
await server.save();
return server;
}
I found a new lead whilst browsing SO:
-L
will create a log file. wine: /home/tsm/.wine is not owned by you
.sudo chown -R root: ~/.wine
. This is because I am running the web server as root to get port 80 perms, so it starts wine as root, so root must own the .wine
folder.