How to write on process.stdin with nodejs

Viewed 160

I have a problem with nodejs when trying to write to stdin of a process I have spawned with this spawn function of child_process

const spawn = require("child_process").spawn;
class Barotrauma {
  static instance = null;
  server = null;

  constructor() {
    this.server = spawn(
      "F:\\dev\\barotrauma\\steamcmd\\steamapps\\common\\Barotrauma Dedicated Server\\DedicatedServer.exe",
      {
        stdio: [process.stdin, process.stdout, process.stderr],
      }
    );
  }
  static getInstance() {
    if (Barotrauma.instance === null) {
      Barotrauma.instance = new Barotrauma();
    } else {
      return Barotrauma.instance;
    }
  }

  sendCommand(command) {
    //this.server.stdout.write(`${command}\n`)
    // this is a test to get an output on command execution to see if it works
    process.stdin.write("help\n");
  }
}

module.exports = Barotrauma;

So, this snippet of code is for starting a game server then send command to it on socket events (the socket call sendCommand function)

if I try to write commands in the console it works fine, but if I try to execute the sendCommand function it crash with error :

node:events:498
      throw er; // Unhandled 'error' event
      ^

Error: write EPIPE
    at afterWriteDispatched (node:internal/stream_base_commons:160:15)
    at writeGeneric (node:internal/stream_base_commons:151:3)
    at ReadStream.Socket._writeGeneric (node:net:795:11)
    at ReadStream.Socket._write (node:net:807:8)
    at writeOrBuffer (node:internal/streams/writable:389:12)
    at _write (node:internal/streams/writable:330:10)
    at ReadStream.Writable.write (node:internal/streams/writable:334:10)
    at Barotrauma.sendCommand (F:\dev\barotrauma\serverManager.js:26:19)
    at handleReward (F:\dev\barotrauma\handler.js:4:28)
    at WebSocket.connection.onmessage (F:\dev\barotrauma\index.js:26:5)
Emitted 'error' event on ReadStream instance at:
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -4047,
  code: 'EPIPE',
  syscall: 'write'
}

The crash seems to originate from the process.stin.write function.

Any idea how to solve this?

1 Answers

You might want to refer to options.stdio.

Without further depth into the full context it's hard to say what's exactly going on, but the following might work as you'd expect:

If you really need the parent and children fds to be connected you could use pipe for the stdio option and have data be propagated between the two processes.

The following snippet (reduced to minimize noise) should do the trick:

class Barotrauma {
  server = null;

  constructor() {
    // Default `stdio` option is `pipe` for fds 0, 1 and 2 (stdio, stdout and stderr)
    this.server = spawn(
      "F:\\dev\\barotrauma\\steamcmd\\steamapps\\common\\Barotrauma Dedicated Server\\DedicatedServer.exe"
    );

    // Catches incoming messages from child, if necessary
    this.server.stdout.on('data', (d) => {
      console.log(`Message from child: '${d}'`)
    })
  }

  sendCommand(cmd) {
    // Sends messages to child
    this.server.stdin.write(`${cmd}\n`);
  }
}

Given you're in a Windows environment, mind you might want to use overlapped instead of pipe if you need async I/O to communicate with that application. For more info, refer to the official docs.

Related