Search code examples
node.jslinuxspawn

Starting Linux Screen Session with Nodejs Spawn


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;
}

Solution

  • I found a new lead whilst browsing SO: