Hubiquitus core system. Actor oriented framework massively distributed.
Create a new folder and run command :
$ npm install hubiquitus-core
Then create an index.js file and put inside :
var hubiquitus = require('hubiquitus-core');
var logger = hubiquitus.logger('pingpong');
hubiquitus.logger.enable('pingpong');
hubiquitus
.addActor('hello', function (req) {
logger.info('Hello World !');
})
.start()
.send('tmp', 'hello');
This code does the following :
- Imports hubiquitus library
- Creates a logger with the namespace "pingpong"
- Enables that logger; note that : - loggers are disabled by default - logger enabling function can take the minimum log level as a second argument - log levels are, in order : trace, debug, info, warn, error|err
- Creates a "hello" actor that just logs "Hello World !"
- Starts the hubiquitus system
- Sends a message to the hello actor using a "fake" tmp actor id : the hello actor will receive the message from tmp.
Run the sample with command :
$ node index.js
The container will run until you stop the node process. You can kill it with CTRL+C.
An actor is just a piece of code with an id. When a message is sent to this id, the code is executed. Inside an actor code, you have access to :
this.id
is the actor idthis.send
is a send function taking four arguments : the target actor id, a content, a timeout (optional) and a response callback (optional)
And actor id (or aid) has a specific format : [identifier]/[resource]
The identifier is also called bare id.
Example : hello/de3ef8f1-28f1-4548-95d2-304b70bd01d9
is a full aid
hello
is the bare id.de3ef8f1-28f1-4548-95d2-304b70bd01d9
is the resource
The resource is an UUID (unique identifier) generated automatically and added to the bare id of an actor when it is added to a container.
When sending a message, the target can be a full aid, or a bare id. If the target is a bare id, the system will select an existing actor with a matching full id to process the message to.
A container is a group of actors. Hubiquitus is a singleton obtained when requiring the hubiquitus-core module. Thus, there can be only one container in a node process.
The discovery is the process used so that containers can talk to eachother.
Let's make a "ping-pong" discussion between two Hubiquitus actors.
var hubiquitus = require('hubiquitus-core');
var logger = hubiquitus.logger('pingpong');
hubiquitus.logger.enable('pingpong');
hubiquitus
.addActor('ping', ping)
.addActor('pong', pong)
.start()
.send('pong', 'ping', 'PONG');
function ping(req) {
logger.info(this.id + '> from ' + req.from + ' : ' + req.content);
var _this = this;
setTimeout(function () {
_this.send(req.from, 'PING');
}, 1000);
}
function pong(req) {
logger.info(this.id + '> from ' + req.from + ' : ' + req.content);
var _this = this;
setTimeout(function () {
_this.send(req.from, 'PONG');
}, 1000);
}
This code does the following :
- Creates two actors named
ping
andpong
- Starts the container
- Initiates the dialog between
ping
andpong
by sending a message toping
, frompong
Now let's have the ping
actor count messages. To do this, we are going to specify a scope when creating the actor. See the code, it's pretty self-explanatory.
var hubiquitus = require('hubiquitus-core');
var logger = hubiquitus.logger('pingpong');
hubiquitus.logger.enable('pingpong');
hubiquitus
.addActor('ping', ping, {count: 0})
.addActor('pong', pong)
.start()
.send('pong', 'ping', 'PONG');
function ping(req) {
this.count++;
logger.info(this.id + '> from ' + req.from + ' : ' + req.content = ' [' + this.count + ']');
var _this = this;
setTimeout(function () {
_this.send(req.from, 'PING');
}, 1000);
}
function pong(req) {
logger.info(this.id + '> from ' + req.from + ' : ' + req.content);
var _this = this;
setTimeout(function () {
_this.send(req.from, 'PONG');
}, 1000);
}
Note that when specifying a scope, id
, send
, onMessage
and scope
are reserved by the system.
Here are the available methods on the Hubiquitus container.
The start method can be called at any time. Messages sent while hubiquitus isnt started are queued.
Parameters :
Parameter | Type | Description | Mandatory |
---|---|---|---|
options | Object | Options | No |
Available options :
- discoveryAddr {String}
- discoveryPort {Number}
- ip {String}
Example :
var hubiquitus = require('hubiquitus-core');
hubiquitus.start({
discoveryAddr: 'udp://224.0.0.1:5555'
});
Stops the Hubiquitus container.
Adds an actor to the container.
Parameters :
Parameter | Type | Description | Mandatory |
---|---|---|---|
aid | String | Receiver aid | Yes |
from | String | Actor aid | Yes |
onMessage | Function | on message behaviour | Yes |
scope | Object | Actor scope | No |
The onMessage
function is the behaviour executed when receiving a message.
It takes a req
Object as an unique parameter :
from
{String} is the sender aidto
{String} is the receiver aidcontent
{*} is the content of the messagetimeout
{Number} is the maximum delay for delivering the messagedate
{Date} is the send date of the messagereply
{Function} is a function to call to reply to the message
The reply
function takes two arguments :
err
{*} is the optional errorcontent
{*} is the response content
Example :
var hubiquitus = require('hubiquitus-core');
hubiquitus
.addActor('ping', function (req) {
this.count++;
req.reply(null, 'pong');
}, {count: 0});
.start();
Removes an actor from the container.
Parameters :
Parameter | Type | Description | Mandatory |
---|---|---|---|
aid | String | Actor aid | Yes |
Sends a message from an actor to another.
Parameters :
Parameter | Type | Description | Mandatory |
---|---|---|---|
from | String | Sender aid | Yes |
to | String | Receiver aid | Yes |
content | Object | Message content | No |
cb | Function | Response callback | No |
The cb
function is the behaviour executed when receiving the message response :
It takes a two arguments :
err
{*} is the optional errorres
{Object} is the response message.
A res
message is similar to a req
message. It contains :
from
{String} is the sender aidto
{String} is the receiver aidcontent
{*} is the content of the messagetimeout
{Number} is the maximum delay for delivering the messagedate
{Date} is the send date of the message
This function also exists within an actor with the following syntax :
send(to, [content, timeout, cb])
Example :
var hubiquitus = require('hubiquitus-core');
hubiquitus
.addActor('Asriel', asriel)
.addActor('Marisa', marisa)
.send('Metatron', 'Marisa', 'Greets Asriel for me!')
.start();
function asriel(req) {
console.log('Asriel> from ' + hubiquitus.utils.aid.bare(req.from) + ' : ' + req.content);
req.reply(null, '...');
}
function marisa(req) {
console.log('Marisa> from ' + hubiquitus.utils.aid.bare(req.from) + ' : ' + req.content);
this.send('Asriel', 'Hello from Metatron !', function (err, res) {
console.log('Marisa> response from ' + hubiquitus.utils.aid.bare(res.from) + ' : ' + res.content);
});
}
- A "fake"
Metatron
actor sends a message toMarisa
Marisa
sends a message toAsriel
Asriel
replies toMarisa
Adds a middleware to use. The defined function will be executed each time an incoming request comes in or an outcoming request comes out.
Parameters :
Parameter | Type | Description | Mandatory |
---|---|---|---|
function | Function | Middleware function | Yes |
The middleware function takes three parameters :
-
type
: message type. Is a String, four possibilities : -
req_out
: the message is an outcoming request -
req_in
: the message is an incoming request -
res_out
: the message is an outcoming response -
res_in
: the message is an incoming response -
msg
: transiting message (is a request or a response, depending on the type) -
next
: callback to call at the end of the process (to call the next middleware)
Example :
var hubiquitus = require('hubiquitus-core');
hubiquitus
.addActor('B', function (req) {
logger.info('Hello World !');
})
.start()
.use(function (type, msg, next) {
var fromAid = hubiquitus.utils.aid.bare(msg.from);
var toAid = hubiquitus.utils.aid.bare(msg.to);
switch (type) {
case 'req_out':
console.log('[outcoming request from ' + fromAid + ' to ' + toAid + ' !]');
break;
case 'req_in':
console.log('[incoming request from ' + fromAid + ' to ' + toAid + ' !]');
break;
case 'res_out':
console.log('[outcoming response from ' + fromAid + ' to ' + toAid + ' !]');
break;
case 'res_in':
console.log('[incoming response from ' + fromAid + ' to ' + toAid + ' !]');
break;
}
next();
})
.send('A', 'B');
In the above example, an A
actor sends a message to a B
actor inside the same container. The middleware function is executed twice and displays :
[outcoming request from A to B !]
[incoming request from A to B !]
Note that you can start using a middleware after the hubiquitus container has started.
Sets a hubiquitus property.
Parameters :
Parameter | Type | Description | Mandatory |
---|---|---|---|
key | String | Property key | Yes |
value | * | Property value | Yes |
Samples list :
- pingpong : simple actor based ping-pong
- ping : ping between two "instances" of the same actor
- ping-cs : coffeescript version of ping
- ping-remote : ping between two foreign actors (two different containers)
- request-reply : simple request-reply sample
- middlewares : middlewares demo
Under heavy developments.
The whole documentation of the Hubiquitus project is available in the docs
subdirectory of this repo.
Hubiquitus is a free and open source software licensed under the terms of the MIT license.
This document itself, as the whole documentation provided with the project, is licensed under the terms of the Creative Commons Attribution Unported 3.0 (CC BY 3.0).