Highly scalable, modular, flexible, lightweight and performant solution for evented interactions.
message-network allows you to build a network of nodes that can interact by sending messages to each other. message-network provides three models of interaction:
- notification,
- request-response,
- chat,
where notification is fire-and-forget interaction, no response is expected or waited for, request-response, as its name implies, allows one node to ask another one for response and chat is much like request-response with multiple roundtrips.
For an interaction to occur both sides of the interaction have to declare theirs participation. By default no nodes is listening on messages (though some nodes may emit messages by default). Hence no interaction occurs by default. A message can be sent to one (unicast message), many (multicast message) or all (broadcast message) nodes of a network.
Message networks can be combined by using gates. A gate is a special kind of a network node. This nodes, when receive messages, pass them to gate nodes of another networks which in turn send the messages into destination network. Networks by itself does not have names but by using (always) named gates they can refer to other networks (including itself) by that names. It is possible to transparently connect networks residing on different devices which makes message-network a good basement for distributed architectures also.
npm install message-network
- Net ()
- Node ([properties])
- Gate ([options])
- MemoryGate ([options])
- BaseError (message [, data])
- TimeoutError (message [, data])
- DisconnectedError (message [, data])
- Handler function
Connects a node to the network under specified name. A network cannot have more than one connected node under the same name. A node can be connected to multiple message networks. A node can be connected to the same network under different names.
An instance of one of the following classes can be passed in place of node:
- Node
- Net
- EventEmitter
- Object
Instances of Node is used as is. Passing an instance of Net is an implicit way to create a MemoryGate node under specified name in the current network that is linked to another MemoryGate node in the passed network under name defined by options.remoteGateName option, which is required in this case. If an EventEmitter is passed, an implicit Node is created which listens on events specified by options.events option and resends messages of the same topic name into the network. Passing an Object instance is a shortcut of connecting a Node instance initialized with that object.
Disconnects a node under specified name from the network.
Shorthand for calling .disconnect
and
.connect
sequentially.
Registers new handlers on messages sent from nodes specified by params.
params are:
- as - name of the node listening.
- to - names of nodes to listen to. Setting to '*' listens to all
nodes.
- to.node - names of nodes to listen to. Setting to '*' listens to all nodes.
- to.gate - names of gates to listen to, to.node is required if to.gate is set. Setting to '*' listens to all gates.
- topic - names of topics of messages to listen on. Setting to '*' listens on all topics.
- success - a handler to execute on a message.
- error - optional default error handler to execute on reply error.
Not used directly normally, but through nodes.
Send a message to nodes specified by params.
params are:
- as - name of the node sending.
- to - names of nodes to send to. Setting to '*' sends to all
nodes.
- to.node - names of nodes to send to. Setting to '*' sends to all nodes.
- to.gate - names of gate to send to, to.node is required if to.gate is set. Setting to '*' sends to all gates.
- topic - a name of a topic to send the message of.
- data - optional message payload.
- success - optional success handler. Called when receiving node handler calls its context's reply method.
- error - optional error handler. Called when receiving node handler calls its context's refuse method. Its first argument is always an instance of BaseError class.
- options
- options.timeout - optional timeout in which response is expected. If timeout is expired, error handler is called with a TimeoutError.
Not used directly normally, but through nodes.
Removes handlers on messages sent from nodes specified by params.
params are:
- as - name of the node listening.
- to - names of nodes to stop listen to. Setting to '*' stops
listening to all nodes.
- to.node - names of nodes to stop listen to. Setting to '*' stops listening to all nodes.
- to.gate - names of gates to stop listen to, note that to.node is
optional here, unlike in
.listen
. Setting to '*' stops listening to all gates.
- topic - names of topics of messages to stop listen on. Setting to '*' stops listening on all topics.
- success - handlers to stop execute on message.
Not used directly normally, but through nodes.
Returns a node under specified name.
Returns a node names under which it is registered in the network.
When properties object is passed its properties are set on newly created Node instance.
Passes params to a network's .listen
method
with params.as param set to name under which node is registered in the
network.
Passes params to a network's .send
method with
params.as param set to name under which node is registered in the
network.
Passes params to a network's .unlisten
method with params.as param set to name under which node is registered
in the network.
Extends Node class. Includes specific implementation for inter-network
event passing. Unlike Node constructor, accepts options object, not
properties one. Used as base class for actual Gate classes. Subclasses
must implement ._transfer
method.
options are:
- MAX_HELD_CB_COUNT - Number of callbacks to hold, wating for possible call triggered by other network. Defaults to 1000.
Overrides Node .listen
method. Ignores
passed params.success param.
Always throws. Method to override for subclasses. Its single responsibility is
to pass data to other gate which in turn must call its
.receive
method on receive.
Should not be used directly. This method is used as
.listen
method params.success param.
Should be used only within Gate's subclass implementation. Receives data transfered by other gate.
Extends Gate class. Accepts all the same options as Gate class does. Includes specific implementation for inter-network event passing for the networks in the same memory.
Sets link to other MemoryGate node connected to other network to pass inter- network messages to.
Unsets linked MemoryGate node.
Base error class.
Property set on an error instance passed on constructor
Thrown when a request is not respond within timeout.
Value of expired timeout.
Thrown when either sender or receiver is disconnected from the network.
Flag showing whether receiving or sending node is disconnected.
A function of the following signature: function (data, context)
.
Function accepts message payload as its first param and message context as its second param.
An object with the following properties:
- sender - name of the sender.
- sender.node - name of the sender node.
- sender.gate - name of the sender gate.
- topic - name of the message topic.
- reply - function accepting as its first argument data to send back to calling node success handler, and options as its second argument.
- refuse - function accepting as its first argument error to send back to calling node error handler, and options as its second argument.
options of both context functions are similar to those of the Node's send method and are the following:
- success - optional success handler. Called when receiving node handler calls its context's reply method.
- error - optional error handler. Called when receiving node handler calls its context's refuse method. Its first argument is always an instance of BaseError class.
- options
- options.timeout - optional timeout in which response is expected. If timeout is expired, error handler is called with a TimeoutError.
import {Net, Node} from 'message-network'
function Player (name, skill) {
return Node({
name: name,
skill: skill,
takeTurn: function (data, context) {
const fault = Math.random() > this.skill
if (fault) {
console.log(this.name, 'out!')
context.refuse()
} else {
console.log(this.name, 'in!')
context.reply()
}
},
callReferee: function (data, context) {
const loser = context.sender.node
this.send({
to: 'referee',
topic: 'out',
data: loser,
})
},
})
}
const match = Net()
const ping = Player('ping', 0.8)
const pong = Player('pong', 0.75)
const referee = Node()
match
.connect('ping', ping)
.connect('pong', pong)
.connect('referee', referee)
ping.listen({
to: 'pong',
topic: 'turn',
success: function (data, context) {
this.takeTurn(data, context)
},
error: function (data, context) {
this.callReferee(data, context)
},
})
pong.send({
to: 'ping',
topic: 'turn',
success: function (data, context) {
this.takeTurn(data, context)
},
error: function (data, context) {
this.callReferee(data, context)
},
})
referee.listen({
to: ['ping', 'pong'],
topic: 'out',
success: function (loser, context) {
const winner = context.sender.node
console.log('referee!', loser, 'has lost!')
console.log('referee!', winner, 'has won!')
}
})
// ping in!
// pong in!
// ping out!
// referee! ping has lost!
// referee! pong has won!