UNPKG

11.5 kBMarkdownView Raw
1[![Build Status](https://www.codeship.io/projects/9274e5a0-341a-0131-92d2-228038a705a1/status)](https://www.codeship.io/projects/9749)
2
3# Hubiquitus
4
5Hubiquitus core system. Actor oriented framework massively distributed.
6
7## Quick start
8
9Create a new folder and run command :
10
11 $ npm install hubiquitus-core
12
13Then create an index.js file and put inside :
14
15```js
16var hubiquitus = require('hubiquitus-core');
17var logger = hubiquitus.logger('pingpong');
18hubiquitus.logger.enable('pingpong');
19
20hubiquitus
21 .addActor('hello', function (req) {
22 logger.info('Hello World !');
23 })
24 .start()
25 .send('tmp', 'hello');
26```
27This code does the following :
28
29 1. Imports hubiquitus library
30 2. Creates a logger with the namespace "pingpong"
31 3. Enables that logger; note that :
32 - loggers are disabled by default
33 - logger enabling function can take the minimum log level as a second argument
34 - log levels are, in order : trace, debug, info, warn, error|err
35 4. Creates a "hello" actor that just logs "Hello World !"
36 5. Starts the hubiquitus system
37 6. Sends a message to the hello actor using a "fake" tmp actor id : the hello actor will receive the message from tmp.
38
39Run the sample with command :
40
41 $ node index.js
42
43The container will run until you stop the node process. You can kill it with CTRL+C.
44
45## Concepts
46
47### Actor
48
49An **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 :
50
51 - `this.id` is the actor id
52 - `this.send` is a send function taking four arguments : the target actor id, a content, a timeout (optional) and a response callback (optional)
53
54And actor id (or **aid**) has a specific format : **[identifier]/[resource]**
55
56The identifier is also called **bare id**.
57
58Example : `hello/de3ef8f1-28f1-4548-95d2-304b70bd01d9` is a full aid
59 - `hello` is the bare id.
60 - `de3ef8f1-28f1-4548-95d2-304b70bd01d9` is the resource
61
62The resource is an **UUID** (unique identifier) generated automatically and added to the bare id of an actor when it is added to a container.
63
64When 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.
65
66### Container
67
68A **container** is a group of actors. Hubiquitus is a singleton obtained when requiring the hubiquitus-core module.
69Thus, there can be only one container in a node process.
70
71### Discovery
72
73The **discovery** is the process used so that containers can talk to eachother.
74
75## Ping-pong sample
76
77Let's make a "ping-pong" discussion between two Hubiquitus actors.
78
79```js
80var hubiquitus = require('hubiquitus-core');
81var logger = hubiquitus.logger('pingpong');
82hubiquitus.logger.enable('pingpong');
83
84hubiquitus
85 .addActor('ping', ping)
86 .addActor('pong', pong)
87 .start()
88 .send('pong', 'ping', 'PONG');
89
90function ping(req) {
91 logger.info(this.id + '> from ' + req.from + ' : ' + req.content);
92
93 var _this = this;
94 setTimeout(function () {
95 _this.send(req.from, 'PING');
96 }, 1000);
97}
98
99function pong(req) {
100 logger.info(this.id + '> from ' + req.from + ' : ' + req.content);
101
102 var _this = this;
103 setTimeout(function () {
104 _this.send(req.from, 'PONG');
105 }, 1000);
106}
107```
108
109This code does the following :
110 1. Creates two actors named `ping` and `pong`
111 2. Starts the container
112 3. Initiates the dialog between `ping` and `pong` by sending a message to `ping`, from `pong`
113
114Now 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.
115
116```js
117var hubiquitus = require('hubiquitus-core');
118var logger = hubiquitus.logger('pingpong');
119hubiquitus.logger.enable('pingpong');
120
121hubiquitus
122 .addActor('ping', ping, {count: 0})
123 .addActor('pong', pong)
124 .start()
125 .send('pong', 'ping', 'PONG');
126
127function ping(req) {
128 this.count++;
129 logger.info(this.id + '> from ' + req.from + ' : ' + req.content = ' [' + this.count + ']');
130
131 var _this = this;
132 setTimeout(function () {
133 _this.send(req.from, 'PING');
134 }, 1000);
135}
136
137function pong(req) {
138 logger.info(this.id + '> from ' + req.from + ' : ' + req.content);
139
140 var _this = this;
141 setTimeout(function () {
142 _this.send(req.from, 'PONG');
143 }, 1000);
144}
145```
146
147Note that when specifying a scope, `id`, `send`, `onMessage` and `scope` are reserved by the system.
148
149## Hubiquitus API
150
151Here are the available methods on the Hubiquitus container.
152
153### start(options)
154
155The start method can be called at any time. Messages sent while hubiquitus isnt started are queued.
156
157Parameters :
158
159|**Parameter**| **Type** |**Description**|**Mandatory**|
160|:-----------:|:--------:|:-------------:|:-----------:|
161| options | Object | Options | No |
162
163Available options :
164
165 - discoveryAddr {String}
166 - discoveryPort {Number}
167 - ip {String}
168
169Example :
170
171```js
172var hubiquitus = require('hubiquitus-core');
173hubiquitus.start({
174 discoveryAddr: 'udp://224.0.0.1:5555'
175});
176```
177
178### stop()
179
180Stops the Hubiquitus container.
181
182### addActor(aid, onMessage[, scope])
183
184Adds an actor to the container.
185
186Parameters :
187
188|**Parameter**| **Type** | **Description** |**Mandatory**|
189|:-----------:|:--------:|:---------------------:|:-----------:|
190| aid | String | Receiver aid | Yes |
191| from | String | Actor aid | Yes |
192| onMessage | Function | on message behaviour | Yes |
193| scope | Object | Actor scope | No |
194
195The `onMessage` function is the behaviour executed when receiving a message.
196It takes a `req` Object as an unique parameter :
197 - `from` {String} is the sender aid
198 - `to` {String} is the receiver aid
199 - `content` {*} is the content of the message
200 - `timeout` {Number} is the maximum delay for delivering the message
201 - `date` {Date} is the send date of the message
202 - `reply` {Function} is a function to call to reply to the message
203
204 The `reply` function takes two arguments :
205 - `err` {*} is the optional error
206 - `content` {*} is the response content
207
208Example :
209
210```js
211var hubiquitus = require('hubiquitus-core');
212
213hubiquitus
214 .addActor('ping', function (req) {
215 this.count++;
216 req.reply(null, 'pong');
217 }, {count: 0});
218 .start();
219```
220
221### removeActor(aid)
222
223Removes an actor from the container.
224
225Parameters :
226
227|**Parameter**| **Type** | **Description** |**Mandatory**|
228|:-----------:|:--------:|:-----------------:|:-----------:|
229| aid | String | Actor aid | Yes |
230
231### send(to, from, [content, timeout, cb])
232
233Sends a message from an actor to another.
234
235Parameters :
236
237|**Parameter**| **Type** | **Description** |**Mandatory**|
238|:-----------:|:--------:|:-----------------:|:-----------:|
239| to | String | Receiver aid | Yes |
240| from | String | Sender aid | Yes |
241| content | Object | Message content | No |
242| cb | Function | Response callback | No |
243
244The `cb` function is the behaviour executed when receiving the message response :
245It takes a two arguments :
246 - `err` {*} is the optional error
247 - `res` {Object} is the response message.
248
249 A `res` message is similar to a `req` message. It contains :
250 - `from` {String} is the sender aid
251 - `to` {String} is the receiver aid
252 - `content` {*} is the content of the message
253 - `timeout` {Number} is the maximum delay for delivering the message
254 - `date` {Date} is the send date of the message
255
256Example :
257
258```js
259var hubiquitus = require('hubiquitus-core');
260
261hubiquitus
262 .addActor('Asriel', asriel)
263 .addActor('Marisa', marisa)
264 .send('Metatron', 'Marisa', 'Greets Asriel for me!')
265 .start();
266
267function asriel(req) {
268 console.log('Asriel> from ' + hubiquitus.utils.aid.bare(req.from) + ' : ' + req.content);
269 req.reply(null, '...');
270}
271
272function marisa(req) {
273 console.log('Marisa> from ' + hubiquitus.utils.aid.bare(req.from) + ' : ' + req.content);
274 this.send('Asriel', 'Hello from Metatron !', function (err, res) {
275 console.log('Marisa> response from ' + hubiquitus.utils.aid.bare(res.from) + ' : ' + res.content);
276 });
277}
278```
279
280 - A "fake" `Metatron` actor sends a message to `Marisa`
281 - `Marisa` sends a message to `Asriel`
282 - `Asriel` replies to `Marisa`
283
284### use(function)
285
286Adds a middleware to use.
287The defined function will be executed each time an incoming request comes in or an outcoming request comes out.
288
289Parameters :
290
291|**Parameter**| **Type** | **Description** |**Mandatory**|
292|:-----------:|:--------:|:-----------------:|:-----------:|
293| function | Function |Middleware function| Yes |
294
295
296The middleware function takes three parameters :
297
298 - `type` : message type. Is a String, four possibilities :
299 - `req_out` : the message is an outcoming request
300 - `req_in` : the message is an incoming request
301 - `res_out` : the message is an outcoming response
302 - `res_in` : the message is an incoming response
303
304 - `msg` : transiting message (is a request or a response, depending on the type)
305 - `next` : callback to call at the end of the process (to call the next middleware)
306
307Example :
308
309```js
310var hubiquitus = require('hubiquitus-core');
311hubiquitus
312 .addActor('B', function (req) {
313 logger.info('Hello World !');
314 })
315 .start()
316 .use(function (type, msg, next) {
317 var fromAid = hubiquitus.utils.aid.bare(msg.from);
318 var toAid = hubiquitus.utils.aid.bare(msg.to);
319 switch (type) {
320 case 'req_out':
321 console.log('[outcoming request from ' + fromAid + ' to ' + toAid + ' !]');
322 break;
323 case 'req_in':
324 console.log('[incoming request from ' + fromAid + ' to ' + toAid + ' !]');
325 break;
326 case 'res_out':
327 console.log('[outcoming response from ' + fromAid + ' to ' + toAid + ' !]');
328 break;
329 case 'res_in':
330 console.log('[incoming response from ' + fromAid + ' to ' + toAid + ' !]');
331 break;
332 }
333 next();
334 })
335 .send('A', 'B');
336```
337
338In 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 :
339```
340[outcoming request from A to B !]
341[incoming request from A to B !]
342```
343Note that you can start using a middleware after the hubiquitus container has started.
344
345### set(key, value)
346
347Sets a hubiquitus property.
348
349Parameters :
350
351|**Parameter**| **Type** |**Description** |**Mandatory**|
352|:-----------:|:--------:|:--------------:|:-----------:|
353| key | String | Property key | Yes |
354| value | * | Property value | Yes |
355
356
357## Samples
358
359Samples list :
360
361 - **pingpong** : simple actor based ping-pong
362 - **ping** : ping between two "instances" of the same actor
363 - **ping-cs** : coffeescript version of ping
364 - **ping-remote** : ping between two foreign actors (two different containers)
365 - **request-reply** : simple request-reply sample
366 - **middlewares** : middlewares demo
367
368## Docs
369
370Under heavy developments.
371The whole documentation of the Hubiquitus project is available in the `docs` subdirectory of this repo.
372
373## License
374
375Hubiquitus is a free and open source software licensed under the terms of the [MIT license](http://opensource.org/licenses/MIT).
376
377This 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](http://creativecommons.org/licenses/by/3.0/)).