Category: Uncategorized

Enter the Wormhole; IPC goodness

Enter the Wormhole; IPC goodness

This post and the example in it have been updated to match version 1.x.x.

Node’s child_process module allows you to spawn and fork new processes, optionally with a built-in Inter-Process Communication (IPC) channel. This is an easy way to communicate with the child process, and valuable on its own in many situations. But it’s not very developer-friendly.

Wait, scratch that, its very developer-friendly. It’s just not… easily and repeatably usable. You will need to define your own JSON-based protocol, which can become tedious if you need to do this often. Addition: it’s not really necessary to define your own protocol: primitive values can be sent too, albeit without metadata.

So, to stay in keeping with DRY and KISS I decided to make a little module that does most of the heavy lifting for me. Note that there are probably dozens of modules out there that do what I did and probably better, but that doesn’t take the fun out of building it. It’s simple and it works, so I’m sure there are applications.

I wanted a couple of things:

  • A way to notify the other end of the link of events that have happened
  • A way to call commands on the remote end and receive a result back (RPC-like behavior)

To satisfy these requirements I built wormhole. It’s designed to work with Node.JS’s child_process and process, and provides what I was looking for.

Installing it is super simple:

npm i @art-of-coding/wormhole --save

How do you use it, you ask? It’s fairly simple – just fork a child process that uses wormhole, and you can send events and call commands!

In the example below we fork a child process, and both processes use wormhole. This allows them to send events and call remote commands. All features are supported in either direction (it’s bidirectional).

The master process:

const childProcess = require('child_process')
const Wormhole = require('@art-of-coding/wormhole')

const child = childProcess.fork('./my-child.js')
const wormhole = new Wormhole(child)

// Register a `startup` event handler
wormhole.events.on('startup', () => {
  console.log('received startup event!')
})

// Register an `add` command
wormhole.define('add', function (a, b) {
  return a + b
})

// Send the `quit` event to the child
setTimeout(() => wormhole.event('quit'), 5000)

The child process:

const Wormhole = require('@art-of-coding/wormhole')

// Without the `channel` argument, `process` is selected by default
const wormhole = new Wormhole()

// Register a `quit` event handler
wormhole.events.once('quit', () => {
  process.exit(-1)
})

// Send an event
wormhole.event('startup')

// Call a remote command
wormhole.command('add', 5, 6).then(result => {
  console.log(`5 + 6 = ${result}`)
})

As you can see for yourself, using it could not be easier!

You can find wormhole on GitHub or npm.

A simple procedure caller

A simple procedure caller

Sometimes you just need something simple. Something that’s light-weight though capable, and does what you want – nothing more. That’s what I did with procedure-caller, a simple Node.JS module for calling, you guessed it, procedures. To be clear: in this context, a ‘procedure’ is nothing more than a function that can be called repeatedly.

Installing it using npm is child’s play:

npm i @art-of-coding/procedure-caller --save

Now that it’s installed we’ll dive right into an example:

const ProcedureCaller = require('@art-of-coding/procedure-caller')

// Create a new instance
const pc = new ProcedureCaller()

// Define a procedure named 'add', which adds two numbers
pc.define('add', function (a, b) {
  if (isNaN(a) || isNaN(b)) {
    throw new TypeError('arguments must be numbers')
  }

  return a + b
}

// Now call the procedure
const result = pc.call('add', 5, 6)

// Display the result
console.log(`5 + 6 = ${result}`)

As you can see, it’s easy to call a procedure and get the result. But what if we’re using asynchronous methods, like Promises or async/await? That’s covered too!

const ProcedureCaller = require('@art-of-coding/procedure-caller')
// We're using gh-got to talk to the GitHub API
const ghGot = require('gh-got')

const pc = new ProcedureCaller()

// Define an async procedure
pc.define('repo', async function (user, name) {
  const response = await ghGot(`repos/${user}/${name}`)
  return response.body
}

// Call the async procedure
pc.call('repo', 'Art-of-Coding', 'procedure-caller').then(result => {
  console.log(`Repo description: ${repo.description}`)
})

Like I said in the opening of this post, my goal was to make something that was exceedingly simple to use. I believe I have done so.

You can view the module on npm and GitHub.