npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dual-protocol

v0.4.6

Published

Protocol layer for dual-api

Downloads

4

Readme

Dual-protocol Build Status

This is the protocol layer for dualapi.

Dual-protocol extends my hierarchical event emitter, HevEmitter, by constraining the schema of the event bodies to create an HTTP-like layered system.

Messages

Dual protocol messages (assuming an instance named ctxt here) are similar in concept to HTTP requests. Dual protocol messages consist in:

  • A destination address: ctxt.to.
  • An optional source address: ctxt.from.
  • An optional body: ctxt.body.
  • And an optional hash of meta data (like headers): ctxt.options.

The destination address names a resource controlled by a host function mounted on the dual-protocol domain. Under the hood, the destination address is a HevEmitter event, which is a list of strings representing the heirarchical event.

The entity associated with the message is expressed by the optional body. Messages without bodies can be interpreted like HTTP GET or HEAD requests; similarly messages with bodies may be interpreted like HTTP POST or PUT. The event body should be JSON serializable. In order for the message to cross interprocess boundaries, the body MUST be JSON serializable.

The optional source address provides information orthogonal to the body information, which the destination host can use to create a layered system in the RESTful sense. The source address should also be a HevEmitter event. Practically, hosts may use the source address to affect message processing in a manner distinct from the expected function of the body (e.g., source address filtering, responses, proxy).

Finally, the optional hash of meta data is similar to headers in HTTP. ctxt.options express information about the message orthogonal to both the source and body, providing information which aid in processing, but do not affect the function of the host (e.g., authorization tokens, body schema, classification).

Constructing dual-protocol domains

Any process holding a dual-protocol domain instance may send messages to any host mounted on the domain. Host functions receive a reference to the domain on which the message was sent on each request.

The dual-protocol module is the constructor for domain instances:

var dualproto = require('dual-protocol');
var domain = dualproto();

Mounting a host

A dual protocol host is a function which accepts dual protocol messages. Hosts are mounted on the domain using the mount method.

In addition to the attributes associated with dual protocol messages, the dual-protocol object will automatically parse parameters declared in the destination address (strings prefixed with :), and provide these in the ctxt.params object. Strings prefixed with :: will match the tail of the address.

For example the following host will record all messages it receives in a list.

var db = {};
domain.mount(['database', ':collection'], function (body, ctxt) {
    var collection = ctxt.params.collection;
    if (!db.hasOwnProperty(collection)) {
      db[collection] = [];
    }
    db[collection].push(ctxt.body);
});

Sending messages with domain.send

Messages are sent to hosts mounted on the domain via domain.send(to, from, body, options).

domain.send(['database', 'message'], [], 'Hello Alice!');

Here we are using an empty source address. Because 'database' is not attempting to make a reply, no source address is necessary.

In addition to the usual message properties, dual-protocol also attaches a reference to the domain on which the host is mounted at ctxt.domain. The host could use the domain to send additional messages and/or replies. For example, the following host outputs information about the message to the console, and forwards a copy of the message to the database host:

domain.mount(['message', ':name'], function (body, ctxt) {
    console.log(ctxt.from.join('/') + ' sent a message to ' + ctxt.params.name);
    console.log('The message was received by ' + ctxt.from.join('/'));
    console.log('The message is: ', ctxt.body);
    ctxt.domain.send(['database', 'message'], [], ctxt.body);
});

Then, a message such as:

domain.send(['message', 'alice'], ['user', 'bob'], 'Hello Alice!');

would result in:

user/bob sent a message to alice
The message was received by message/alice
The message is: Hello Alice!

Creating temporary hosts with domain.waitFor

A common pattern is to create a temporary host to wait for a single message, such as a ready event or a request response, which is removed immediately after the event. Dual-protocol provides the domain.waitFor(event, options) method for this purpose.

domain.waitFor returns a promise that will resolve when the event has been received. For instance, we create a listener for 'ready':

domain.waitFor(['ready'], { timeout: 60 })
.then(function (ctxt) {
  console.log('We are ready!');
});

Then we can trigger this host once, and only once, by using domain.send. If the timeout option is provided, the host will be cancelled after timeout seconds.

In order to wait for a response to a specific message, we need to create a unique host name known only by the request originator and receiver. For this purpose, dual-protocol includes a unique id generator at domain.uid.

domain.uid().then(function (mailbox) {
  domain.waitFor([mailbox])
  .then(function (ctxt) {
    console.log('My temporary mailbox just received: ', ctxt.body);
  });

  domain.send([mailbox], [], 'mail!');
});

Extending dual-protocol

Dual-protocol strives to be simple, without constraining the behavior of the hosts or senders. Additional constraints, convenience functions and automated behaviors can be added by customizing dual-protocol; creating an API:

var dualproto = require('dual-protocol');
var api = dualproto.use(function (Domain) {
  Domain.prototype.Message.prototype.reply = function (body) {
      this.domain.send(this.from, [], body);
  };
});
var domain = api();
domain.mount(['responder'], function (ctxt) {
  ctxt.reply('Hello');
});