{"_id":"smart-router","_rev":"32-243ba049acb3e4bf272add0b602fdf5e","name":"smart-router","description":"a message routing system that routes messages based on their content.","dist-tags":{"latest":"0.2.5"},"versions":{"0.1.0":{"name":"smart-router","version":"0.1.0","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"0.1.3","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5"},"engines":{"node":">=0.6"},"scripts":{"test":"mocha"},"license":"Apache2","readme":"smart-router\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be repesented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define wht to do \nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** enpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message);\n      smartrouter.publish(message.ids.logger, 'log', message);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message); \n    }\n  }\n}\n``` \n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connectiong to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connectiong to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","_id":"smart-router@0.1.0","dist":{"shasum":"6a66183dbf94299f1fbcadca3bb6c3d9b1cda47f","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.1.0.tgz","integrity":"sha512-KkMJiWGl1INTiDAK22/ghiKP95G6m3G0hn7tiF/8keBxgeu5B48DRNsPul5xgwh4AYjsELlEPNlV7LFw4Tr+KQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDpBkxYDIzRQ2YM7UO9f73jOgFTxRuVvzMKbAJLc1U6BQIgbQMFjE6s42oE9hXhHA9ynHSW7OICsD2yChfXDSuIRfA="}]},"_npmVersion":"1.1.63","_npmUser":{"name":"callixte","email":"callixte@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"}],"directories":{}},"0.1.1":{"name":"smart-router","version":"0.1.1","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"0.1.3","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5"},"engines":{"node":">=0.6"},"scripts":{"test":"mocha"},"license":"Apache2","readme":"smart-router\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be repesented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define wht to do \nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** enpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message);\n      smartrouter.publish(message.ids.logger, 'log', message);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message); \n    }\n  }\n}\n``` \n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connectiong to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connectiong to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","_id":"smart-router@0.1.1","dist":{"shasum":"8baaafcee73a7033d827c1755938c27d8861d5ed","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.1.1.tgz","integrity":"sha512-eCyz4BQIIelc5eSWyQW3IQuGx21IGLue5y1Q/bMrtGZ4SJReMpfT5ceWBVAIVxv5MzwM5hFE/9K1NZDOveA0Aw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDbQo/fu3AhpGlvKSRYUYX+gnRUYlYmqlzNpjoJkYcRAQIhAIEgnCQihuwAt2pai1ow8HlL5T1kgN4Wb5nH37vnZ3CX"}]},"_npmVersion":"1.1.63","_npmUser":{"name":"callixte","email":"callixte@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"}],"directories":{}},"0.1.2":{"name":"smart-router","version":"0.1.2","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"0.1.4","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5"},"engines":{"node":">=0.6"},"scripts":{"test":"mocha"},"license":"Apache2","readme":"smart-router\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be repesented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define wht to do \nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** enpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message);\n      smartrouter.publish(message.ids.logger, 'log', message);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message); \n    }\n  }\n}\n``` \n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connectiong to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connectiong to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","_id":"smart-router@0.1.2","dist":{"shasum":"dca7c2a4afa8a7192c266bfb376d90076b34f026","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.1.2.tgz","integrity":"sha512-N6IvbDOxL/fjpom0uQ7wJp1BYKPg97KdNbkU0acMW/qJ/7pbrD6wH5kxSRerYErtoiAdYxiEctW/mN+DXlBB/Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCl0aVrH1lTSRrLVXy3z1HUS329V97B/7BkhtdMSPRdlAIhAIgKl2sXFSMvbux0NWoUkE7I6Nr0bKWt8+phablzAO9K"}]},"_npmVersion":"1.1.63","_npmUser":{"name":"callixte","email":"callixte@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"}],"directories":{}},"0.1.3":{"name":"smart-router","version":"0.1.3","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"0.1.4","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.6"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be repesented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define wht to do \nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** enpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message);\n      smartrouter.publish(message.ids.logger, 'log', message);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message); \n    }\n  }\n}\n``` \n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connectiong to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connectiong to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","_id":"smart-router@0.1.3","dist":{"shasum":"d2e919f408c661705189b1a0551262725d861f67","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.1.3.tgz","integrity":"sha512-WbJwC+enzbbio1un77qaS/h1D89LtKlBJpE7Tr2Udsv2Z8WtrAZtVIepBoY2QLeJNZ5jPtpGWjoXXUhDSEiAxQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDcZqtWcpKWRU8tGKpZ2WSUmNXaDzYEV1apomTwbkkEdgIgcUbdrXm+6Nz3LnoZUi+9p7vFARV6xyFTUo/v6LoSJKI="}]},"_npmVersion":"1.1.63","_npmUser":{"name":"callixte","email":"callixte@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"}],"directories":{}},"0.2.0":{"name":"smart-router","version":"0.2.0","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"0.1.4","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.8.18"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be represented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define what to do\nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** endpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message, socket);\n      smartrouter.publish(message.ids.logger, 'log', message, socket);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message, socket);\n    }\n  }\n}\n```\n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connecting to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connecting to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message, socket)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n        The `socket` argument is the actual socket where your actor is connected. By passing it as an argument of the\n        `publish()` method of the smart-router, the smart-router will be able to send back to your actor the errors which\n        might occur while publishing the message on RabbitMQ (Typically: The queue where your actor is trying to publish\n        does not exist).\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","readmeFilename":"README.md","_id":"smart-router@0.2.0","dist":{"shasum":"b8a19aae123bf4d96f02c7c91fa1a432b2b68e32","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.2.0.tgz","integrity":"sha512-c5WVw7m26EE8TBLuH6NfNAylcmYqQGilJ9M6aiIcdS34qyn1lXakbQP9UPLlPsjxlZhiO0oInHvA3nQrjzpQfw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBrOVvD0rm9xnQ6Yl7CdNTBiN7KqAaN3LuoLKcoB2MU8AiEA0oU3deiL1CSYsJhdyyClfWw5U8TCWHUl/SUB7WMpf+s="}]},"_from":".","_npmVersion":"1.2.11","_npmUser":{"name":"callixte","email":"callixte@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"}],"directories":{}},"0.2.1":{"name":"smart-router","version":"0.2.1","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"0.1.4","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.8.18"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be represented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define what to do\nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** endpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message, socket);\n      smartrouter.publish(message.ids.logger, 'log', message, socket);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message, socket);\n    }\n  }\n}\n```\n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connecting to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connecting to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message, socket)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n        The `socket` argument is the actual socket where your actor is connected. By passing it as an argument of the\n        `publish()` method of the smart-router, the smart-router will be able to send back to your actor the errors which\n        might occur while publishing the message on RabbitMQ (Typically: The queue where your actor is trying to publish\n        does not exist).\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","readmeFilename":"README.md","_id":"smart-router@0.2.1","dist":{"shasum":"2c594557abdd190747ad743a453e1fbcf49834ed","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.2.1.tgz","integrity":"sha512-8mYm0kxvi7nWisnf3fe4rx1+TxPSHleSo/NAkuEd8JSDjsZZcO3DIMWuVnVoB6katJeo1did1J55cJ82a4vGpw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDzO2PdHYMsEVZ+ptDfOzm8kQ2+1yln35AfwmedXS+DxAIhAJf0JDOdbUBczhXCko/VKu4kwx79Rv86oj9DLQHD690b"}]},"_from":".","_npmVersion":"1.2.11","_npmUser":{"name":"callixte","email":"callixte@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"}],"directories":{}},"0.2.2":{"name":"smart-router","version":"0.2.2","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"git+ssh://git@github.com:VirtuOz/node-amqp.git#fixReconnectAndPassiveQueues","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.8.18"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be represented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define what to do\nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** endpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message, socket);\n      smartrouter.publish(message.ids.logger, 'log', message, socket);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message, socket);\n    }\n  }\n}\n```\n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connecting to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connecting to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n#### Queue cleaning\n\nThe smart-router will create queues with 'x-expires' argument.\nBy default, a queue will be deleted 15 minutes after the last actor has been disconnected from it.\nThis value configurable in the yaml properties file.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message, socket)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n        The `socket` argument is the actual socket where your actor is connected. By passing it as an argument of the\n        `publish()` method of the smart-router, the smart-router will be able to send back to your actor the errors which\n        might occur while publishing the message on RabbitMQ (Typically: The queue where your actor is trying to publish\n        does not exist).\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","readmeFilename":"README.md","_id":"smart-router@0.2.2","dist":{"shasum":"8802434ad7e7cc97d3270c92b393d63e046c86a0","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.2.2.tgz","integrity":"sha512-AVdf2I4cch4b/pxbQv6DNhA5x7/BbbOXc7xsQ0cbK8x3mR1gPXKvy+RX5kWRuaue9bTZMi01avko95zYK5V1rA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDlGuMzl96r5I/FETfbLxavSGPx56NDcl/PkHGTIbkOhAiEA/opIOMSsjAV9oyr1fZFLeSXxtZG2I2JT+lQ7bZSC29M="}]},"_from":".","_npmVersion":"1.2.10","_npmUser":{"name":"sylvain","email":"sylvain.bellone@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"},{"name":"sylvain","email":"sylvain.bellone@gmail.com"}]},"0.2.3":{"name":"smart-router","version":"0.2.3","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"git+https://github.com/VirtuOz/node-amqp.git#fixReconnectAndPassiveQueues","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.8.18"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be represented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define what to do\nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** endpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message, socket);\n      smartrouter.publish(message.ids.logger, 'log', message, socket);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message, socket);\n    }\n  }\n}\n```\n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connecting to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connecting to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n#### Queue cleaning\n\nThe smart-router will create queues with 'x-expires' argument.\nBy default, a queue will be deleted 15 minutes after the last actor has been disconnected from it.\nThis value configurable in the yaml properties file.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message, socket)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n        The `socket` argument is the actual socket where your actor is connected. By passing it as an argument of the\n        `publish()` method of the smart-router, the smart-router will be able to send back to your actor the errors which\n        might occur while publishing the message on RabbitMQ (Typically: The queue where your actor is trying to publish\n        does not exist).\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","readmeFilename":"README.md","_id":"smart-router@0.2.3","dist":{"shasum":"f0eb668e9824beaa6498b7b60ab26136256baea8","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.2.3.tgz","integrity":"sha512-Uy2FDW99k2eM0eC7G3K/7wTzENYQIoXY1jiNi1aNZkT/jSzL59NyElJCC4Udi1Zq+/ICtOCTPB3Ixe6jtWehwg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD0Lj4G/MDilCMPP1CdCFBprgBYXm2D/gKi84FUgygFrwIhAIr5kqHHt6KBgLYRJgBBte73XFJZMAwo5WsElhJ2KEln"}]},"_from":"smart-router","_npmVersion":"1.2.10","_npmUser":{"name":"sylvain","email":"sylvain.bellone@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"},{"name":"sylvain","email":"sylvain.bellone@gmail.com"}]},"0.2.4":{"name":"smart-router","version":"0.2.4","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"git+https://github.com/VirtuOz/node-amqp.git#fixReconnectAndPassiveQueues","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.8.18"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be represented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define what to do\nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** endpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message, socket);\n      smartrouter.publish(message.ids.logger, 'log', message, socket);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message, socket);\n    }\n  }\n}\n```\n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connecting to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connecting to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n#### Queue cleaning\n\nThe smart-router will create queues with 'x-expires' argument.\nBy default, a queue will be deleted 15 minutes after the last actor has been disconnected from it.\nThis value configurable in the yaml properties file.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message, socket)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n        The `socket` argument is the actual socket where your actor is connected. By passing it as an argument of the\n        `publish()` method of the smart-router, the smart-router will be able to send back to your actor the errors which\n        might occur while publishing the message on RabbitMQ (Typically: The queue where your actor is trying to publish\n        does not exist).\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","readmeFilename":"README.md","_id":"smart-router@0.2.4","dist":{"shasum":"84063160170ddcc645c0ab5202f3694a1208a170","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.2.4.tgz","integrity":"sha512-JpeoepkTKxi72nNaq7VTRaeYRKF3YubpdFh2jchF/h56ilJ9uqr0i1lJlpuFNXTG6ctEMmhulMvPMV9c280Jeg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBGiA6Pj5JuzxuC2k7NnxJcaAvrUeUqYI4a7OCIxLnjSAiEAhib3g3RDts1TZyNcSebsTFDlXr5ESkr2E9Zbzt4qbq4="}]},"_from":"smart-router","_npmVersion":"1.2.10","_npmUser":{"name":"sylvain","email":"sylvain.bellone@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"},{"name":"sylvain","email":"sylvain.bellone@gmail.com"}]},"0.2.5":{"name":"smart-router","version":"0.2.5","author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"description":"a message routing system that routes messages based on their content.","main":"./lib/index","repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"},"dependencies":{"jsclass":"3.0.9","amqp":"git+https://github.com/VirtuOz/node-amqp.git#fixReconnectAndPassiveQueues","socket.io":"0.9","socket.io-client":"0.9","winston":"0.6.2","config":"0.4.17","nagios":"1.0.0"},"devDependencies":{"mocha":"1.7.0","chai":"1.3.0","nock":"0.13.5","xunit-html-cov":"0.0.2"},"engines":{"node":">=0.8.18"},"scripts":{"test":"PORT=8889 mocha --ignore-leaks -R spec -t 30000 --ui bdd","test-coverage":"scripts/runTestsWithCoverage.sh","clean":"rm -rf target"},"license":"Apache2","readme":"smart-router [![Build Status](https://travis-ci.org/VirtuOz/smart-router.png)](https://travis-ci.org/VirtuOz/smart-router)\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be represented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define what to do\nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** endpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message, socket);\n      smartrouter.publish(message.ids.logger, 'log', message, socket);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message, socket);\n    }\n  }\n}\n```\n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connecting to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connecting to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n#### Queue cleaning\n\nThe smart-router will create queues with 'x-expires' argument.\nBy default, a queue will be deleted 15 minutes after the last actor has been disconnected from it.\nThis value configurable in the yaml properties file.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message, socket)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n        The `socket` argument is the actual socket where your actor is connected. By passing it as an argument of the\n        `publish()` method of the smart-router, the smart-router will be able to send back to your actor the errors which\n        might occur while publishing the message on RabbitMQ (Typically: The queue where your actor is trying to publish\n        does not exist).\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","readmeFilename":"README.md","_id":"smart-router@0.2.5","dist":{"shasum":"bc7f85bdb5008eea88446f4fbc444094d5dc593a","tarball":"https://registry.npmjs.org/smart-router/-/smart-router-0.2.5.tgz","integrity":"sha512-umFlj1KfJ9b7B0rR5SmObhyR8ahgO/qCuE8QnTC46TBkJnfDiZ+dHeAVcExh1iioayIMxqbsuaZtPlYc3Xj4WA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEMO6DRSmQSP23Y8VvFi55gUIOZwlFWWCq8JzUz/+3LCAiEA4qzbrhw+WyJpjQ43T2oksn/UCMU9r8aF9piwFTPUuBs="}]},"_from":"smart-router","_npmVersion":"1.2.10","_npmUser":{"name":"sylvain","email":"sylvain.bellone@gmail.com"},"maintainers":[{"name":"callixte","email":"callixte@gmail.com"},{"name":"sylvain","email":"sylvain.bellone@gmail.com"}]}},"readme":"smart-router\n============\n\nThe *smart-router* is a message routing system that routes messages based on their content. \nIt is meant to be light-weight and HA. Internally, it uses [RabbitMQ](http://www.rabbitmq.com/)\nto handle the messages and [socket.io](http://socket.io/) as its transport protocol. It can be \nused to connect server-side services as well as client-side applications.\n\nTo use it:\n```\nnpm install smart-router\n```\n\nConcepts\n--------\n### Endpoints\nThe *smart-router* will listen to several endpoints or sub-endpoints as defined in its config file. One end point can be \ndivided into sub-endpoints who will share the same route definitions, but if an endpoint has sub-endpoints, the *smart-router*\nwill listen to the sub-endpoints and not the endpoint itself. \n\n### Actors \nAn Actor is a client of the *smart-router*. It has its own unique Id. It will connect to an endpoint or a sub-endpoint\nto publish and receive messages. They can be configured to receive messages sent directly to them or sent to their \nendpoint.\n\n### Messages\nMessages are exchanged by the Actors through the *smart-router*. It will then introspect them to route them to the \nright actor or to the right endpoint for one actor to pick them up.\n\nA message has a type and a body which can be repesented like that:\n```javascript\n{ \n  ids: { },\n  metadata: { },\n  payload: { }\n}\n```\n**ids** contains the ids of the actors or endpoints concerned by the message. By looking, preferably, at the **metadata**,\nthe *smart-router* will choose which of these actors it will route the message to. The **payload** contains application \nspecific data, whereas **metadata** will contain data used by the routing. (The *smart-router* still has access to the \n**payload** and can decide using it, but it is better to have a clean separation between the two.)\n\n### Routes\nA Route is a function that is called when the *smart-router* receives a message of a specific type on a specific end point.\nIn this function, the *smart-router* can look at the endpoint, the message type and the message body to define wht to do \nwith it. Usually, it will publish it as-is to another and point or actor, but it can modify it, fork it and publish it to \nseveral endpoints.\nIn the following route, when we receive a message of type **business** from the **serviceA** endpoint, we check if it is\nimportant. If it is, we route it to **serviceC** enpoint as an **important** message and log it by sending it to the logger\nas a **log** message. If not, we forward it as-is to **serviceB**.\n```javascript\n{ \n  endpoint: 'serviceA', \n  messagetype: 'business',\n  action: function (message, socket, smartrouter) {  \n    if (message.ids.serviceC && message.metadata.isImportant) {\n      smartrouter.publish(message.ids.serviceC, 'important', message);\n      smartrouter.publish(message.ids.logger, 'log', message);\n    } \n    else {\n      smartrouter.publish(message.ids.serviceB, 'business', message); \n    }\n  }\n}\n``` \n\n### Queues and Exchanges\nQueues and Exchanges are an internal notion. Actors don't see the queues and don't know about them. Internally, the route \nfunctions will\npublish messages to some queues and when a new actor connects, it will subscribe to one or two queues. \nOne exchange is created per (sub)endpoint. Queues exist at the \n(sub)endpoint or actor level, depending on the flags used in the configuration of the endpoint.\n```javascript\n  endpoints: [ \n    { name: 'endpoint', queue: QUEUEFLAG.endpoint },\n    { name: 'subendpoint', sub: [ 456, 457 ], queue: QUEUEFLAG.endpoint },\n    { name: 'actoronly', sub: [ 'subactor' ], queue: QUEUEFLAG.actor }, // QUEUEFLAG.actor is the default value\n    { name: 'endpointandactor', queue: QUEUEFLAG.endpoint | QUEUEFLAG.actor }\n  ]\n```\nWith this configuration, the *smart-router* will listen to:\n* `/endpoint`\n* `/subendpoint/456`\n* `/subendpoint/457`\n* `/actoronly/subactor`\n* `/endpointandactor`\n\nand will use the following queues:\n* `endpoint` of exchange `endpoint`\n* `subendpoint/456` of exchange `subendpoint/456`\n* `subendpoint/457` of exchange `subendpoint/457`\n* `<actorid>` of exchange `actoronly/subactor` where _actorid_ is the unique id of the actors connectiong to the end point\n* `endpointandactor` of exchange `endpointandactor`\n* `<actorid>` of exchange `endpointandactor` where _actorid_ is the unique id of the actors connectiong to the end point\n\nDuring its transit inside the *smart-router*, a message will:\n1. be received on the endpoint\n2. routed using the corresponding route function \n3. queued on the queue selected by the routing function\n4. dequeued and\n5. sent to an actor.\n\n### High Availability\nInternally, the *smart-router* is composed of two modules:\n* a socket.io server written in node.js that handles the routing of the messages\n* a RabbitMQ cluster that handles the persistence and the publication of the messages.\nAny number of the node.js application can be deployed as long as they all connect to the same RabbitMQ cluster. A single message \ncan be queued by one instance and dequeued by another. As long as the RabbitMQ is correctly [set up](http://www.rabbitmq.com/clustering.html)\nto [mirror](http://www.rabbitmq.com/ha.html) the queues,\nthere is no SPoF.\n\nUsage\n-----\n\n### Smart-router configuration\n\nOn start, the smart-router will read a configuration object.\nThis configuration will contain:\n\n- `port` The port on which the smart-router will listen.\n- `amqp` The [amqp connection options](https://github.com/postwait/node-amqp#connection-options-and-url).\n- `endpoints` The endpoints configuration. Will define endpoints' names and the socket's namespaces\n    on which the smart-router will listen. Actors will connect on these endpoints.\n    This object will be an array of objects containing the following properties:\n    - `name` Endpoint's name.\n    - `sub` List containing endpoint's sub-endpoints. This will determine on which namespaces the smart-router will listen: If\n        no sub are present, it will listen on `/name`. If sub are set, it will listen on `/name/id1`, `/name/id2`, ...\n    - `queue` A flag to determine the queue(s) which will be created for the endpoint. Use ('./lib').const.QUEUEFLAG\n        to set it. If there is no flag or if `QUEUEFLAG.actor` is set, smart-router will create a queue named\n        with the actorId which has established a connection on the namespace.\n        If the flag `QUEUEFLAG.endpoint` is set, the smart-router will create a generic queue named `endpointName/subendpoint`.\n- `routes` Array of configuration objects which will define actions to do for each type of message received on an endpoint.\n    Each object will contains:\n    - `endpoint` Endpoint's name (one of those defined in `endpoints` configuration).\n    - `messagetype` The name of the event that the smart-router will listen for.\n    - `action: function(message, socket, smartrouter)` A function which will be called once we receive the event\n        `messagetype` on the `endpoint`. **It's here that you need to route the received message.** Typically,\n        you will do something like: `smartrouter.publish(queueId, 'messagetype', message)` which will publish a\n        message of type `messagetype` to the queue `queueid`.\n\n### Handshake protocol\nIf you develop your actors in JS, you only have to use the `Actor` class as describe in the next section.\n\nIn any other language, you would need to use a [socket.io](http://socket.io/) client and to implement the\nhandshake protocol:\n\n1. when a new Actor connects, the *smart-router* emits an empty `whoareyou` message.\n2. the Actor must respond with a `iam` message whose payload will be its unique id. These ids have to be unique \nthrough out the whole platform.\n3. the *smart-router* responds then with a `hello` empty message.\n4. when receiving a message from an unknown Actor (unknown unique id), the *smart-router* will emit a `whoareyou` message \ncontaining the previous message as a payload (`payload.type` being the message type, and `payload.message` the message body.)\n5. it is expected that the Actor then emits a `iam` with its id and re-emits the rejected message. \n\n### Writing actors\n\nIn JS, all actors need to extend the raw Actor class defined in `lib/actor.js`.\n\n```javascript\nvar Actor = require('smart-router').Actor;\n\nMyActor = new JS.Class(Actor, {\n\n  connect: function() {\n    var socket = this.callSuper();\n    socket.on('myactorevent', function(data) {\n      // do some awesome stuff\n      socket.emit('responseevent', message);\n    };\n    socket.on('otheractorevent', function(data) {\n      // do other stuff\n    };\n  },\n\n  my_actor_method : function() {\n  }\n});\n```\n\nAs you see, the only mandatory thing to do in an actor is to extends the `connect()`\nfunction, to get a reference on the socket by calling its parent, and to add listeners on it.\nOf course listeners must match the `messagetype` you have configured in `routes`.\n\nThen, you are able to instantiate your actor:\n\n```javascript\nnew MyActor('localhost:8080', 'endpoint', 'my_actor_id');\n```\n\n\n### Examples\n\n#### Basic\nAn example of basic actor can be found in `example/basic.js`.\nThe scenario is very simple:\n\n- Actor1 starts by sending a 'message' which will be published to the queue `actor/2` (subscribed by actor2).\n- The message is routed to actor2 which reply to the queue `actor/1/my_actor_id1` (subscribed by actor1)\n- The message is routed to actor1 which reply to the queue `actor/2/actor_id2` (subscribed by actor2)\n- ...\nIt stops after two back and forth.\n\n#### Tests\nThe test folder contains different actors used to test the behaviour of the *smart-router*.\n\n1. `agent` is the main actor. It will decide of the flow of the messages by adding some metadata.\n2. `ui` simulates a UI. It can request to *talk* to the external `service`.\n3. `service` is an external service to which some messages can get routed.\n\nUse `npm test` from the command line to launch the tests.\n\nLICENSE\n=======\n\nCopyright 2012 VirtuOz, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","maintainers":[{"name":"callixte","email":"callixte@gmail.com"},{"name":"sylvain","email":"sylvain.bellone@gmail.com"}],"time":{"modified":"2022-06-26T21:20:06.221Z","created":"2012-12-27T19:33:51.032Z","0.1.0":"2012-12-27T19:33:51.964Z","0.1.1":"2013-01-03T17:30:20.306Z","0.1.2":"2013-01-11T18:16:48.707Z","0.1.3":"2013-02-01T16:50:31.146Z","0.2.0":"2013-03-05T00:55:20.470Z","0.2.1":"2013-03-05T15:32:34.021Z","0.2.2":"2013-04-24T14:42:19.023Z","0.2.3":"2013-05-23T16:30:31.847Z","0.2.4":"2013-06-05T15:47:04.429Z","0.2.5":"2013-06-25T08:25:12.846Z"},"author":{"name":"Callixte","email":"ccauchois@virtuoz.com"},"repository":{"type":"git","url":"https://github.com/VirtuOz/smart-router.git"}}