Search code examples
node.jslinuxbashmacosnamed-pipes

Read from a 'named pipe' / fifo with Node.js


I have this:

  const p = path.resolve(projectRoot + '/NAMEDPIPEIN');
  const fd = fs.openSync(p, 'r+');

  fs.createReadStream(null, {fd}).on('data', function (d) {
    if (String(d).trim() === '[stdin end]') {
      return process.nextTick(cb);
    }
    process.argv.push(String(d).trim());
  });

I start the Node.js process, and then later, I write to the named pipe. For some reason no data seems to be arriving in the on data callback.

I am writing to named pipe like so:

 mkfifo NAMEDPIPEIN
 echo "foo bar baz" > NAMEDPIPEIN

Solution

  • The other solution, from @richardpringle should work, but is limited in functionality.

    If you try to open multiple FIFOs that way (more than the number of threads in the thread-pool), the first ones you opened won't be streaming data anymore. This is because the fs module isn't designed to work with file-descriptors in non-blocking mode. Instead, use the net module!

    From https://stackoverflow.com/a/52622722/1843507 the current way to achieve streaming from a FIFO is using a socket:

    const fs = require('fs');
    const net = require('net');
    
    fs.open('path/to/fifo/', fs.constants.O_RDONLY | fs.constants.O_NONBLOCK, (err, fd) => {
      // Handle err
      const pipe = new net.Socket({ fd });
      // Now `pipe` is a stream that can be used for reading from the FIFO.
      pipe.on('data', (data) => {
        // process data ...
      });
    });
    

    In summary, you can use @richardpringle's solution if you are running a script and don't mind tying up one of the threads in the thread-pool. Otherwise, you should definitely use this solution.