0.2.1 • Published 3 years ago

@josephuspaye/pipe-emitter v0.2.1

Weekly downloads
1
License
MIT
Repository
github
Last release
3 years ago

pipe-emitter

A bidirectional inter-process event emitter that uses UNIX domain sockets (on Linux and macOS) and named pipes (on Windows).

This project is part of #CreateWeekly, my attempt to create something new publicly every week in 2020.

Installation

npm install @josephuspaye/pipe-emitter --save

Usage

The following example shows how to use pipe-emitter to communicate between two processes:

// server.js: creates a pipe for client connections

import { Server } from '@josephuspaye/pipe-emitter';

const server = new Server('pipe-emitter-example', {
  onError(error) {
    // An error has occured. `error.type` has the type of error.
    console.log('server error', error.type);
  },
  onConnect() {
    console.log('client connected, sending greeting');

    // A client has connected, send them a greeting
    server.emit('greeting', 'oh hai from server');
  },
  onDisconnect() {
    console.log('client disconnected, closing server');

    // A client (the only one) has disconnected, close server pipe
    server.close();
  },
});

// Listen for a message from clients
server.on('greeting', (message) => {
  console.log('received greeting from client:', message);
});

console.log('pipe server started');
// client.js: connects to an open pipe

import { Client } from '@josephuspaye/pipe-emitter';

const client = new Client('pipe-emitter-example', {
  onError(error) {
    // An error has occured. `error.type` has the type of error.
    console.log('server error', error.type);
  },
  onConnect() {
    // Connected to the server
    console.log('connected to server');
  },
  onDisconnect() {
    // Disconnected from the server
    console.log('disconnected from server');
  },
});

// Listen for a message from the server
client.on('greeting', (message) => {
  console.log('received greeting from server:', message);

  // Send a greeting in response
  client.emit('greeting', 'oh hai from client');

  // Close and clean up the client pipe after two seconds
  setTimeout(() => {
    console.log('responded, now disconnecting');
    client.close();
  }, 2000);
});

Running the above server.js in Node followed by client.js yields the following output from server.js:

pipe server started
client connected, sending greeting
received greeting from client: oh hai from client
client disconnected, closing server

And the following from client.js:

connected to server
received greeting from server: oh hai from server
responded, now disconnecting
disconnected from server

API

Server class

A server for creating IPC pipes (UNIX domain pipes or named pipes on Windows). Supports bi-directional communication with clients that connect. See Types below for additional types.

class Server<TSend = any, TReceive = any> {
  /**
   * Create a new pipe server that clients can connect to. See [the Node.js docs](https://nodejs.org/docs/latest-v14.x/api/net.html#net_identifying_paths_for_ipc_connections) for pipe name format and valid characters.
   *
   * @param pipeName The name of the pipe, globally unique at the OS level
   * @param options
   */
  constructor(
    pipeName: string,
    options: {
      onError: ErrorListener;
      onConnect?: ConnectListener;
      onDisconnect?: CloseListener;
    }
  );

  /**
   * Get the number of clients connected to this pipe.
   */
  clientCount(): number;

  /**
   * Emit the given event and data unto the pipe. Will throw an error of type "SEND_ERROR"
   * if a client socket is not writable (e.g. not ready or already closed).
   *
   * @param event The event type
   * @param data  Any value (object is recommended), passed to each handler
   */
  emit(event: EventType, data?: TSend): void;

  /**
   * Register an event handler for the given type on this pipe.
   *
   * @param type    Type of event to listen for, or `"*"` for all events
   * @param handler Function to call in response to given event
   */
  on(type: EventType, handler: Handler<TReceive>): void;

  /**
   * Remove an event handler for the given type on this pipe.
   *
   * @param type    Type of event to unregister `handler` from, or `"*"`
   * @param handler Handler function to remove
   */
  off(type: EventType, handler: Handler<TReceive>): void;

  /**
   * Remove all event listeners.
   */
  allOff(): void;

  /**
   * Close the pipe and clear event listeners.
   */
  close(): Promise<void>;
}

Client class

A client for connecting to IPC pipes (UNIX domain pipes or named pipes on Windows). Supports bi-directional communication with the server it's connected to. See Types below for additional types.

class Client<TSend = any, TReceive = any> {
  /**
   * Create a new pipe client and connect it to the given pipe.
   *
   * @param pipeName The name of the pipe to connect to
   * @param options
   */
  constructor(
    pipeName: string,
    options: {
      onError: ErrorListener;
      onConnect?: ConnectListener;
      onDisconnect?: CloseListener;
    }
  );

  /**
   * Emit the given event and data unto the pipe. Will throw an error of type "SEND_ERROR"
   * if the server socket is not writable (e.g. not ready or already closed).
   *
   * @param event The event type
   * @param data  Any value (object is recommended), passed to each handler
   */
  emit(event: EventType, data?: TSend): void;

  /**
   * Register an event handler for the given type on this pipe.
   *
   * @param type    Type of event to listen for, or `"*"` for all events
   * @param handler Function to call in response to given event
   */
  on(type: EventType, handler: Handler<TReceive>): void;

  /**
   * Remove an event handler for the given type on this pipe.
   *
   * @param type    Type of event to unregister `handler` from, or `"*"`
   * @param handler Handler function to remove
   */
  off(type: EventType, handler: Handler<TReceive>): void;

  /**
   * Remove all event listeners.
   */
  allOff(): void;

  /**
   * Close the pipe and clear event listeners.
   */
  close(): void;
}

Types

Additional types used by the Server and Client classes.

type PipeError = Error & {
  type: 'SEND_ERROR' | 'RECEIVE_ERROR' | 'SERVER_ERROR' | 'SOCKET_ERROR';
};
type EventType = string | symbol;
type Handler<T = any> = (event?: T) => void;
type WildcardHandler = (type: EventType, event?: any) => void;
type ErrorListener = (err: PipeError) => void;
type ConnectListener = () => void;
type CloseListener = (hadError: boolean) => void;

Licence

MIT