{"_id":"54377e6889a8760800093eaf","__v":26,"githubsync":"","is_link":false,"project":"54377e6889a8760800093ea9","version":{"_id":"54377e6889a8760800093eac","project":"54377e6889a8760800093ea9","__v":1,"createdAt":"2014-10-10T06:36:24.755Z","releaseDate":"2014-10-10T06:36:24.755Z","categories":["54377e6889a8760800093ead"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"category":{"_id":"54377e6889a8760800093ead","project":"54377e6889a8760800093ea9","version":"54377e6889a8760800093eac","__v":3,"pages":["54377e6889a8760800093eaf","5437979d89a8760800093f81","550b2605c99ce62500e3bfb1"],"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2014-10-10T06:36:24.786Z","from_sync":false,"order":9999,"slug":"documentation","title":"Documentation"},"user":"54377e04efdba90800c8f142","updates":["550c00f208dd8e25006dba44","550fe3050f12ba0d00b2e102","560c22ced1084b2300c6df30","58c932929396340f003e740e"],"next":{"pages":[],"description":""},"createdAt":"2014-10-10T06:36:24.818Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"basic_auth":false,"results":{"codes":[]},"settings":"","try":true,"auth":"never","params":[],"url":""},"isReference":false,"order":0,"body":"[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/hD6m0DyIQsWdW4cetwMu_susi-header.png\",\n        \"susi-header.png\",\n        \"1440\",\n        \"532\",\n        \"#042d3e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nFirst you will have to get a working copy of Susi. You can get it either via one of the prebuild packages from the release branches of our Github repository, or you can build Susi on your own.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Get Susi\"\n}\n[/block]\nTo clone the whole repository and checkout the bleeding edge branch do this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"git clone --recursive https://github.com/webvariants/susi\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nNow we will go on to compile the core of susi, the susi server. We will call the directory where you cloned the repository to $SUSI.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Build Susi\"\n}\n[/block]\nOK, lets create a build directory and init it with cmake: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"mkdir ~/susi-build\\ncd ~/susi-build\\ncmake $SUSI\\nmake -j4\\nsudo make install\\nsudo ldconfig\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Start the susi-core server\"\n}\n[/block]\nThe main component of SUSI is its core-server. This is the server which does all event dispatching, and serves as a communication base for all other components.\nYou need to specify a valid TLS key / certificate pair to let the server start. To create a slef signed certificate run the following command:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"openssl req -nodes -x509 -newkey rsa:2048 -keyout server_key.pem -out server_cert.pem -days 36500\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nAfter this, you can start the susi-core server:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi-core --key server_key.pem --cert server_cert.pem --port 4000\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nThis starts the susi-core server accepting TLS-connection on port 4000\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Start one or more services\"\n}\n[/block]\nOnce your core-server is started, you can start other components which connects to it.\nOne example would be, that you start the susi-duktape component, a server side javascript interpreter.\nTo do so, create a Javascript source file. This could look like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi.registerProcessor('.*', function (evt) {\\n\\tconsole.debug('in processor');\\n\\tevt.payload = {};\\n\\tsusi.ack(evt);\\n});\\n\\nsusi.registerProcessor('foo', function (evt) {\\n\\tconsole.debug('in foo proc 1');\\n\\tevt.payload.a = 'foo';\\n\\tsusi.ack(evt);\\n});\\n\\nsusi.registerProcessor('foo', function (evt) {\\n\\tconsole.debug('in foo proc 2');\\n\\tevt.payload.b = 'bar';\\n\\tsusi.dismiss(evt);\\n});\\n\\nsusi.registerProcessor('foo', function (evt) {\\n\\tconsole.debug('in foo proc 3 (should never be called)');\\n\\tevt.payload.c = 'baz';\\n\\tsusi.ack(evt);\\n});\\n\\nsusi.registerConsumer('foo', function (evt) {\\n\\tconsole.log('consumer:', evt.payload);\\n});\\n\\nsusi.publish({ topic: 'foo' }, function (evt) {\\n\\tconsole.log('finish:', evt.payload);\\n});\\n\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nPlace this file somewhere in your filesystem with the name susi-sample.js.\nYou can use the same key/certificate pair you used to start the server, but you can create another pair:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"openssl req -nodes -x509 -newkey rsa:2048 -keyout duktape_key.pem -out duktape_cert.pem -days 36500\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nNow its time to start susi-duktape. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi-duktape --src susi-sample.js --addr localhost --port 4000 --key duktape_key.pem --cert duktape_cert.pem \\n> started Susi::duktape engine and loaded source.js\\n> 2015-08-25T09:35:31.934Z DBG susi-js: source.js:2: in processor\\n> 2015-08-25T09:35:31.934Z DBG susi-js: source.js:8: in foo proc 1\\n> 2015-08-25T09:35:31.934Z DBG susi-js: source.js:14: in foo proc 2\\n> 2015-08-25T09:35:31.934Z INF susi-js: consumer: {a:\\\"foo\\\",b:\\\"bar\\\"}\\n> 2015-08-25T09:35:31.935Z INF susi-js: finish: {a:\\\"foo\\\",b:\\\"bar\\\"}\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nIf you see an output like this, everything's fine :)\nIf you have a look at the supplied JS sources, you can see how SUSI works.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Understand the code\"\n}\n[/block]\nThere are 5 essential actions you need to know about:\n\n* registerProcessor()\n\t* This attaches an active event handler to a specific topic.\n\t* All active event handlers run sequentially in the order they are declared.\n* registerConsumer()\n\t* This attaches an passive event handler to a specific topic\n\t* All passive event handlers run after all active event handlers finished.\n* publish()\n\t* This publishes an event.\n\t* The event is firstly processed by all processors\n\t* After all processors finished, the consumers for this topic are called\n* ack()\n\t* This needs to be called when an processor finished.\n\t* It tells susi, to continue with the event processing.\n* dismiss()\n\t* This can also be called if a processor finished\n\t* It tells SUSI to stop the event processing -> no active handlers will be called after this\n\t* It will NOT stop passive handlers or the finish callback from being called\n\nAs you see in the example, we register four processors one consumer and call publish: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi.registerProcessor('foo', function (evt) {\\n\\tconsole.debug('in foo proc 1');\\n\\tevt.payload.a = 'foo';\\n\\tsusi.ack(evt);\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThis is the second processor. It matches all events with the topic 'foo'.\nIt attaches the string 'foo' to the payload field 'a'. After this, it acknoledges the event back to susi.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi.registerProcessor('foo', function (evt) {\\n\\tconsole.debug('in foo proc 2');\\n\\tevt.payload.b = 'bar';\\n\\tsusi.dismiss(evt);\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThis is the third processor. It also matches all events with the topic 'foo'.\nNotice that we call dismiss() in the end of the callback. This prevents all later declared processors to be called.\nEspecially fourth processor we declared after this, will NOT be called.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi.registerProcessor('foo', function (evt) {\\n\\tconsole.debug('in foo proc 3 (should never be called)');\\n\\tevt.payload.c = 'baz';\\n\\tsusi.ack(evt);\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThis is the fourth processor. It will never be called due to the dismiss() statement in the third processor.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi.registerConsumer('foo', function (evt) {\\n\\tconsole.log('consumer:', evt.payload);\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nHere we declared a Consumer / passive event handler.\nIt gets called after all processors, which are interested in this event, finished.\nIn the callback we simply log the event payload to stdout.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"susi.publish({ topic: 'foo' }, function (evt) {\\n\\tconsole.log('finish:', evt.payload);\\n});\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nNow after the setup of all those processors and consumers, we can finally publish an event!\npublish() takes the event as first parameter. All events MUST have a topic field. Additionally they can have a payload field\nwhich can contain arbitary data. As a second argument you can specify a finish callback. This is somewhat a one-time-consumer.\nIt gets called after all processors for this event finished, but gets immediatly deleted afterwards.","excerpt":"This page will help you get started with Susi. You'll be up and running in a few minutes!","slug":"getting-started","type":"basic","title":"Getting Started with Susi"}

Getting Started with Susi

This page will help you get started with Susi. You'll be up and running in a few minutes!

[block:image] { "images": [ { "image": [ "https://files.readme.io/hD6m0DyIQsWdW4cetwMu_susi-header.png", "susi-header.png", "1440", "532", "#042d3e", "" ] } ] } [/block] First you will have to get a working copy of Susi. You can get it either via one of the prebuild packages from the release branches of our Github repository, or you can build Susi on your own. [block:api-header] { "type": "basic", "title": "Get Susi" } [/block] To clone the whole repository and checkout the bleeding edge branch do this: [block:code] { "codes": [ { "code": "git clone --recursive https://github.com/webvariants/susi", "language": "shell" } ] } [/block] Now we will go on to compile the core of susi, the susi server. We will call the directory where you cloned the repository to $SUSI. [block:api-header] { "type": "basic", "title": "Build Susi" } [/block] OK, lets create a build directory and init it with cmake: [block:code] { "codes": [ { "code": "mkdir ~/susi-build\ncd ~/susi-build\ncmake $SUSI\nmake -j4\nsudo make install\nsudo ldconfig", "language": "shell" } ] } [/block] [block:api-header] { "type": "basic", "title": "Start the susi-core server" } [/block] The main component of SUSI is its core-server. This is the server which does all event dispatching, and serves as a communication base for all other components. You need to specify a valid TLS key / certificate pair to let the server start. To create a slef signed certificate run the following command: [block:code] { "codes": [ { "code": "openssl req -nodes -x509 -newkey rsa:2048 -keyout server_key.pem -out server_cert.pem -days 36500", "language": "shell" } ] } [/block] After this, you can start the susi-core server: [block:code] { "codes": [ { "code": "susi-core --key server_key.pem --cert server_cert.pem --port 4000", "language": "shell" } ] } [/block] This starts the susi-core server accepting TLS-connection on port 4000 [block:api-header] { "type": "basic", "title": "Start one or more services" } [/block] Once your core-server is started, you can start other components which connects to it. One example would be, that you start the susi-duktape component, a server side javascript interpreter. To do so, create a Javascript source file. This could look like this: [block:code] { "codes": [ { "code": "susi.registerProcessor('.*', function (evt) {\n\tconsole.debug('in processor');\n\tevt.payload = {};\n\tsusi.ack(evt);\n});\n\nsusi.registerProcessor('foo', function (evt) {\n\tconsole.debug('in foo proc 1');\n\tevt.payload.a = 'foo';\n\tsusi.ack(evt);\n});\n\nsusi.registerProcessor('foo', function (evt) {\n\tconsole.debug('in foo proc 2');\n\tevt.payload.b = 'bar';\n\tsusi.dismiss(evt);\n});\n\nsusi.registerProcessor('foo', function (evt) {\n\tconsole.debug('in foo proc 3 (should never be called)');\n\tevt.payload.c = 'baz';\n\tsusi.ack(evt);\n});\n\nsusi.registerConsumer('foo', function (evt) {\n\tconsole.log('consumer:', evt.payload);\n});\n\nsusi.publish({ topic: 'foo' }, function (evt) {\n\tconsole.log('finish:', evt.payload);\n});\n", "language": "javascript" } ] } [/block] Place this file somewhere in your filesystem with the name susi-sample.js. You can use the same key/certificate pair you used to start the server, but you can create another pair: [block:code] { "codes": [ { "code": "openssl req -nodes -x509 -newkey rsa:2048 -keyout duktape_key.pem -out duktape_cert.pem -days 36500", "language": "shell" } ] } [/block] Now its time to start susi-duktape. [block:code] { "codes": [ { "code": "susi-duktape --src susi-sample.js --addr localhost --port 4000 --key duktape_key.pem --cert duktape_cert.pem \n> started Susi::duktape engine and loaded source.js\n> 2015-08-25T09:35:31.934Z DBG susi-js: source.js:2: in processor\n> 2015-08-25T09:35:31.934Z DBG susi-js: source.js:8: in foo proc 1\n> 2015-08-25T09:35:31.934Z DBG susi-js: source.js:14: in foo proc 2\n> 2015-08-25T09:35:31.934Z INF susi-js: consumer: {a:\"foo\",b:\"bar\"}\n> 2015-08-25T09:35:31.935Z INF susi-js: finish: {a:\"foo\",b:\"bar\"}", "language": "shell" } ] } [/block] If you see an output like this, everything's fine :) If you have a look at the supplied JS sources, you can see how SUSI works. [block:api-header] { "type": "basic", "title": "Understand the code" } [/block] There are 5 essential actions you need to know about: * registerProcessor() * This attaches an active event handler to a specific topic. * All active event handlers run sequentially in the order they are declared. * registerConsumer() * This attaches an passive event handler to a specific topic * All passive event handlers run after all active event handlers finished. * publish() * This publishes an event. * The event is firstly processed by all processors * After all processors finished, the consumers for this topic are called * ack() * This needs to be called when an processor finished. * It tells susi, to continue with the event processing. * dismiss() * This can also be called if a processor finished * It tells SUSI to stop the event processing -> no active handlers will be called after this * It will NOT stop passive handlers or the finish callback from being called As you see in the example, we register four processors one consumer and call publish: [block:code] { "codes": [ { "code": "susi.registerProcessor('foo', function (evt) {\n\tconsole.debug('in foo proc 1');\n\tevt.payload.a = 'foo';\n\tsusi.ack(evt);\n});", "language": "javascript" } ] } [/block] This is the second processor. It matches all events with the topic 'foo'. It attaches the string 'foo' to the payload field 'a'. After this, it acknoledges the event back to susi. [block:code] { "codes": [ { "code": "susi.registerProcessor('foo', function (evt) {\n\tconsole.debug('in foo proc 2');\n\tevt.payload.b = 'bar';\n\tsusi.dismiss(evt);\n});", "language": "javascript" } ] } [/block] This is the third processor. It also matches all events with the topic 'foo'. Notice that we call dismiss() in the end of the callback. This prevents all later declared processors to be called. Especially fourth processor we declared after this, will NOT be called. [block:code] { "codes": [ { "code": "susi.registerProcessor('foo', function (evt) {\n\tconsole.debug('in foo proc 3 (should never be called)');\n\tevt.payload.c = 'baz';\n\tsusi.ack(evt);\n});", "language": "javascript" } ] } [/block] This is the fourth processor. It will never be called due to the dismiss() statement in the third processor. [block:code] { "codes": [ { "code": "susi.registerConsumer('foo', function (evt) {\n\tconsole.log('consumer:', evt.payload);\n});", "language": "javascript" } ] } [/block] Here we declared a Consumer / passive event handler. It gets called after all processors, which are interested in this event, finished. In the callback we simply log the event payload to stdout. [block:code] { "codes": [ { "code": "susi.publish({ topic: 'foo' }, function (evt) {\n\tconsole.log('finish:', evt.payload);\n});", "language": "javascript" } ] } [/block] Now after the setup of all those processors and consumers, we can finally publish an event! publish() takes the event as first parameter. All events MUST have a topic field. Additionally they can have a payload field which can contain arbitary data. As a second argument you can specify a finish callback. This is somewhat a one-time-consumer. It gets called after all processors for this event finished, but gets immediatly deleted afterwards.