nutella_framework 0.4.5 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -15
  3. data/VERSION +1 -1
  4. data/framework_components/beacon-cloud-bot/README.md +27 -0
  5. data/framework_components/beacon-cloud-bot/beacon_cloud_bot.rb +154 -0
  6. data/framework_components/beacon-cloud-bot/nutella.json +6 -0
  7. data/framework_components/beacon-cloud-bot/startup +4 -0
  8. data/framework_components/beacon-cloud-interface/LICENSE +21 -0
  9. data/framework_components/beacon-cloud-interface/Readme.md +0 -0
  10. data/framework_components/beacon-cloud-interface/bower.json +29 -0
  11. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/.bower.json +23 -0
  12. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/bower.json +14 -0
  13. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/mqttws31.js +2081 -0
  14. data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/readme.md +4 -0
  15. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/.bower.json +37 -0
  16. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/LICENSE +21 -0
  17. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/README.md +15 -0
  18. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/bower.json +28 -0
  19. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/browser/mqtt_client_hello_world.html +23 -0
  20. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/browser/nutella_hello_world.html +52 -0
  21. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/node/mqtt_client_hello_world.js +14 -0
  22. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/node/nutella_hello_world.js +38 -0
  23. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/nutella_lib.js +789 -0
  24. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/package.json +30 -0
  25. data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/simple-js-mqtt-client.js +428 -0
  26. data/framework_components/beacon-cloud-interface/css/animation.css +17 -0
  27. data/framework_components/beacon-cloud-interface/css/cursor.css +16 -0
  28. data/framework_components/beacon-cloud-interface/css/page_layout.css +73 -0
  29. data/framework_components/beacon-cloud-interface/index.html +157 -0
  30. data/framework_components/beacon-cloud-interface/js/lib/nutella_lib.js +4039 -0
  31. data/framework_components/beacon-cloud-interface/js/react/beacon-add.js +102 -0
  32. data/framework_components/beacon-cloud-interface/js/react/beacon-table.js +73 -0
  33. data/framework_components/beacon-cloud-interface/js/react/beacon.js +97 -0
  34. data/framework_components/beacon-cloud-interface/nutella.json +6 -0
  35. data/framework_components/example_framework_web_interface/index.html +11 -2
  36. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/.npmignore +10 -0
  37. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/.travis.yml +5 -0
  38. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/LICENSE +21 -0
  39. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/README.md +27 -0
  40. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/dist/nutella_lib.js +4039 -0
  41. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/dist/nutella_lib.js.map +1 -0
  42. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/examples/browser_hello_world.html +67 -0
  43. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/examples/node_hello_world.js +51 -0
  44. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/gulpfile.js +31 -0
  45. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/package.json +41 -0
  46. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_core.js +19 -0
  47. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_core_browser.js +17 -0
  48. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_log.js +50 -0
  49. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_net.js +279 -0
  50. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_persist.js +20 -0
  51. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_core_browser.js +17 -0
  52. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_log.js +50 -0
  53. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_net.js +499 -0
  54. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_i.js +74 -0
  55. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_i_browser.js +130 -0
  56. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_lib.js +91 -0
  57. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_lib_browser.js +90 -0
  58. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_log.js +51 -0
  59. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_net.js +84 -0
  60. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_persist.js +20 -0
  61. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/util/net.js +327 -0
  62. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/test/nutella.test.js +16 -0
  63. data/framework_components/example_framework_web_interface/node_modules/nutella_lib/test/runner.html +22 -0
  64. data/framework_components/example_framework_web_interface/package.json +15 -0
  65. data/framework_components/{order.json.example → order.json} +0 -0
  66. data/framework_components/runs_list_bot/{app_runs_list_bot.rb → runs_list_bot.rb} +9 -3
  67. data/framework_components/runs_list_bot/startup +1 -1
  68. data/lib/commands/meta/run_command.rb +21 -36
  69. data/lib/commands/start.rb +9 -199
  70. data/lib/commands/util/components_list.rb +68 -0
  71. data/lib/commands/util/components_starter.rb +169 -0
  72. data/nutella_framework.gemspec +109 -47
  73. data/nutella_lib/framework_net.rb +17 -13
  74. metadata +84 -106
@@ -0,0 +1,91 @@
1
+ /******************
2
+ * nutella_lib.js *
3
+ ******************/
4
+
5
+ "use strict";
6
+
7
+ /**
8
+ * Entry point for nutella_lib in node
9
+ */
10
+
11
+ var nutella_i = require('./nutella_i');
12
+
13
+ // Internal reference to this library (used below)
14
+ var nutella = {};
15
+
16
+
17
+ /**
18
+ * Creates a new instance of nutella
19
+ * and initialize it. This is a factory method.
20
+ *
21
+ * @param {string} broker_hostname - the hostname of the broker.*
22
+ * @param {string} app_id - the app_id this component belongs to
23
+ * @param {string} run_id - the run_id this component is launched in
24
+ * @param {string} component_id - the name of this component
25
+ */
26
+ nutella.init = function(broker_hostname, app_id, run_id, component_id) {
27
+ if (broker_hostname===undefined || app_id===undefined || run_id===undefined || component_id=== undefined) {
28
+ console.warn("Couldn't initialize nutella. Make sure you are setting all four the required parameters (broker_hostname, app_id, run_id, component_id)");
29
+ }
30
+ return new nutella_i.RunNutellaInstance(broker_hostname, app_id, run_id, component_id);
31
+ };
32
+
33
+
34
+ /**
35
+ * Creates a new instance of nutella
36
+ * and initialize it for an app-level component.
37
+ * This is a factory method.
38
+ *
39
+ * @param {string} broker_hostname - the hostname of the broker.*
40
+ * @param {string} app_id - the app_id this component belongs to
41
+ * @param {string} run_id - the run_id this component is launched in
42
+ * @param {string} component_id - the name of this component
43
+ */
44
+ nutella.initApp = function(broker_hostname, app_id, component_id) {
45
+ if (broker_hostname===undefined || app_id===undefined || component_id=== undefined) {
46
+ console.warn("Couldn't initialize nutella. Make sure you are setting all three the required parameters (broker_hostname, app_id, run_id, component_id)");
47
+ }
48
+ return new nutella_i.AppNutellaInstance(broker_hostname, app_id, component_id);
49
+ };
50
+
51
+
52
+ /**
53
+ * Utility method that parses CLI parameters.
54
+ * It is obviously only available in node.
55
+ *
56
+ * @return {Object} An object containing all the CLI parameters: broker, app_id, run_id
57
+ */
58
+ nutella.parseArgs = function() {
59
+ if (process.argv.length<5) {
60
+ console.warn("Couldn't read broker address, app_id and run_id from the command line, you might have troubles initializing nutella")
61
+ return;
62
+ }
63
+ var t = {};
64
+ t.broker = process.argv[2];
65
+ t.app_id = process.argv[3];
66
+ t.run_id = process.argv[4];
67
+ return t;
68
+ };
69
+
70
+
71
+ /**
72
+ * Utility method that parses CLI parameters for
73
+ * application level components.
74
+ * It is obviously only available in node.
75
+ *
76
+ * @return {Object} An object containing all the CLI parameters: broker, app_id, run_id
77
+ */
78
+ nutella.parseAppComponentArgs = function() {
79
+ if (process.argv.length<4) {
80
+ console.warn("Couldn't read broker address and app_id from the command line, you might have troubles initializing nutella")
81
+ return;
82
+ }
83
+ var t = {};
84
+ t.broker = process.argv[2];
85
+ t.app_id = process.argv[3];
86
+ return t;
87
+ };
88
+
89
+
90
+ // Exports nutella object
91
+ module.exports = nutella;
@@ -0,0 +1,90 @@
1
+ /******************
2
+ * nutella_lib.js *
3
+ ******************/
4
+
5
+ "use strict";
6
+
7
+ /**
8
+ * Entry point for nutella_lib in the browser
9
+ */
10
+
11
+ var nutella_i = require('./nutella_i_browser');
12
+
13
+ // Internal reference to this library (used below)
14
+ var nutella = {};
15
+
16
+
17
+ /**
18
+ * Creates a new instance of nutella
19
+ * and initialize it. This is a factory method.
20
+ *
21
+ * @param {string} broker_hostname - the hostname of the broker.*
22
+ * @param {string} app_id - the app_id this component belongs to
23
+ * @param {string} run_id - the run_id this component is launched in
24
+ * @param {string} component_id - the name of this component
25
+ */
26
+ nutella.init = function(broker_hostname, app_id, run_id, component_id) {
27
+ if (broker_hostname===undefined || app_id===undefined || run_id===undefined || component_id=== undefined) {
28
+ console.warn("Couldn't initialize nutella. Make sure you are setting all four required parameters (broker_hostname, app_id, run_id, component_id)");
29
+ }
30
+ return new nutella_i.RunNutellaInstance(broker_hostname, app_id, run_id, component_id);
31
+ };
32
+
33
+
34
+ /**
35
+ * Creates a new instance of nutella
36
+ * and initialize it for an app-level component.
37
+ * This is a factory method.
38
+ *
39
+ * @param {string} broker_hostname - the hostname of the broker.*
40
+ * @param {string} app_id - the app_id this component belongs to
41
+ * @param {string} component_id - the name of this component
42
+ */
43
+ nutella.initApp = function(broker_hostname, app_id, component_id) {
44
+ if (broker_hostname===undefined || app_id===undefined || component_id=== undefined) {
45
+ console.warn("Couldn't initialize nutella. Make sure you are setting all three required parameters (broker_hostname, app_id, component_id)");
46
+ }
47
+ return new nutella_i.AppNutellaInstance(broker_hostname, app_id, component_id);
48
+ };
49
+
50
+
51
+ /**
52
+ * Creates a new instance of nutella
53
+ * and initialize it for a framework-level component.
54
+ * This is a factory method.
55
+ *
56
+ * @param {string} broker_hostname - the hostname of the broker.*
57
+ * @param {string} component_id - the name of this component
58
+ */
59
+ nutella.initFramework = function(broker_hostname, component_id) {
60
+ if (broker_hostname===undefined || component_id=== undefined) {
61
+ console.warn("Couldn't initialize nutella. Make sure you are setting all two required parameters (broker_hostname, component_id)");
62
+ }
63
+ return new nutella_i.FrNutellaInstance(broker_hostname, component_id);
64
+ };
65
+
66
+
67
+
68
+ /**
69
+ * Utility method that parses URL parameters from the URL.
70
+ * It is obviously only available in the browser.
71
+ *
72
+ * @return {Object} An object containing all the URL query parameters
73
+ */
74
+ nutella.parseURLParameters = function () {
75
+ var str = location.search;
76
+ var queries = str.replace(/^\?/, '').split('&');
77
+ var searchObject = {};
78
+ for( var i = 0; i < queries.length; i++ ) {
79
+ var split = queries[i].split('=');
80
+ searchObject[split[0]] = split[1];
81
+ }
82
+ return searchObject;
83
+ };
84
+
85
+
86
+ nutella.version = '0.4.3';
87
+
88
+
89
+ // Exports nutella object
90
+ module.exports = nutella;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Run-level Logging APIs for nutella
3
+ */
4
+
5
+ var NetSubModule = require('./run_net');
6
+
7
+ var LogSubModule = function(main_nutella) {
8
+ this.net = new NetSubModule(main_nutella);
9
+ };
10
+
11
+
12
+ LogSubModule.prototype.debug = function(message, code) {
13
+ console.debug(message);
14
+ this.net.publish('logging', logToJson(message, code, 'debug'));
15
+ return code;
16
+ };
17
+
18
+ LogSubModule.prototype.info = function(message, code) {
19
+ console.info(message);
20
+ this.net.publish('logging', logToJson(message, code, 'info'));
21
+ return code;
22
+ };
23
+
24
+ LogSubModule.prototype.success = function(message, code) {
25
+ console.log('%c '+ message , 'color: #009933');
26
+ this.net.publish('logging', logToJson(message, code, 'success'));
27
+ return code;
28
+ };
29
+
30
+ LogSubModule.prototype.warn = function(message, code) {
31
+ console.warn(message);
32
+ this.net.publish('logging', logToJson(message, code, 'warn'));
33
+ return code;
34
+ };
35
+
36
+ LogSubModule.prototype.error = function(message, code) {
37
+ console.error(message);
38
+ this.net.publish('logging', logToJson(message, code, 'error'));
39
+ return code;
40
+ };
41
+
42
+
43
+ function logToJson( message, code, level) {
44
+ return (code===undefined) ? {level: level, message: message} : {level: level, message: message, code: code};
45
+ }
46
+
47
+
48
+
49
+
50
+
51
+ module.exports = LogSubModule;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Run-level Network APIs for nutella
3
+ */
4
+
5
+
6
+ var AbstractNet = require('./util/net');
7
+
8
+
9
+ /**
10
+ * Run-level network APIs for nutella
11
+ * @param main_nutella
12
+ * @constructor
13
+ */
14
+ var NetSubModule = function(main_nutella) {
15
+ // Store a reference to the main module
16
+ this.nutella = main_nutella;
17
+ this.net = new AbstractNet(main_nutella);
18
+ };
19
+
20
+
21
+
22
+ /**
23
+ * Subscribes to a channel or filter.
24
+ *
25
+ * @param channel
26
+ * @param callback
27
+ * @param done_callback
28
+ */
29
+ NetSubModule.prototype.subscribe = function(channel, callback, done_callback) {
30
+ this.net.subscribe_to(channel, callback, this.nutella.appId, this.nutella.runId, done_callback);
31
+ };
32
+
33
+
34
+
35
+ /**
36
+ * Unsubscribes from a channel
37
+ *
38
+ * @param channel
39
+ * @param done_callback
40
+ */
41
+ NetSubModule.prototype.unsubscribe = function(channel, done_callback) {
42
+ this.net.unsubscribe_from(channel, this.nutella.appId, this.nutella.runId, done_callback);
43
+ };
44
+
45
+
46
+
47
+ /**
48
+ * Publishes a message to a channel
49
+ *
50
+ * @param channel
51
+ * @param message
52
+ */
53
+ NetSubModule.prototype.publish = function(channel, message) {
54
+ this.net.publish_to(channel, message, this.nutella.appId, this.nutella.runId);
55
+ };
56
+
57
+
58
+
59
+ /**
60
+ * Sends a request.
61
+ *
62
+ * @param channel
63
+ * @param message
64
+ * @param callback
65
+ */
66
+ NetSubModule.prototype.request = function(channel, message, callback) {
67
+ this.net.request_to(channel, message, callback, this.nutella.appId, this.nutella.runId);
68
+ };
69
+
70
+
71
+
72
+ /**
73
+ * Handles requests.
74
+ *
75
+ * @param channel
76
+ * @param callback
77
+ * @param done_callback
78
+ */
79
+ NetSubModule.prototype.handle_requests = function(channel, callback, done_callback) {
80
+ this.net.handle_requests_on(channel, callback, this.nutella.appId, this.nutella.runId, done_callback);
81
+ };
82
+
83
+
84
+ module.exports = NetSubModule;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Run-level persistence APIs for nutella
3
+ */
4
+
5
+
6
+
7
+ var PersistSubModule = function(main_nutella) {
8
+ // Store a reference to the main module
9
+ this.main_nutella = main_nutella;
10
+ };
11
+
12
+
13
+
14
+ PersistSubModule.prototype.test = function () {
15
+ console.log("This is just a test method for the persist sub-module");
16
+ };
17
+
18
+
19
+
20
+ module.exports = PersistSubModule;
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Network APIs abstraction
3
+ */
4
+
5
+
6
+ var AbstractNet = function(main_nutella) {
7
+ this.subscriptions = [];
8
+ this.callbacks = [];
9
+ this.nutella = main_nutella;
10
+ };
11
+
12
+
13
+ /**
14
+ * This callback is fired whenever a message is received by the subscribe
15
+ *
16
+ * @callback subscribeCallback
17
+ * @param {string} message - the received message. Messages that are not JSON are discarded
18
+ * @param {string} [channel] - the channel the message was received on (optional, only for wildcard subscriptions)
19
+ * @param {Object} from - the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
20
+ */
21
+
22
+ /**
23
+ * Subscribes to a channel or to a set of channels
24
+ *
25
+ * @param {string} channel - the channel or filter we are subscribing to. Can contain wildcard(s)
26
+ * @param {subscribeCallback} callback - fired whenever a message is received
27
+ * @param {string|undefined} appId - used to pad channels
28
+ * @param {string|undefined} runId - used to pad channels
29
+ * @param {function} done_callback - fired whenever the subscribe is successful
30
+ */
31
+ AbstractNet.prototype.subscribe_to = function(channel, callback, appId, runId, done_callback) {
32
+ // Pad channel
33
+ var padded_channel = this.pad_channel(channel, appId, runId);
34
+ // Maintain unique subscriptions
35
+ if(this.subscriptions.indexOf(padded_channel)>-1)
36
+ throw 'You can`t subscribe twice to the same channel`';
37
+ // Depending on what type of channel we are subscribing to (wildcard or simple)
38
+ // register a different kind of callback
39
+ var mqtt_cb;
40
+ if(this.nutella.mqtt_client.isChannelWildcard(padded_channel))
41
+ mqtt_cb = function(mqtt_message, mqtt_channel) {
42
+ try {
43
+ var f = JSON.parse(mqtt_message);
44
+ if(f.type==='publish')
45
+ callback(f.payload, this.un_pad_channel(mqtt_channel, appId, runId), f.from);
46
+ } catch(e) {
47
+ if (e instanceof SyntaxError) {
48
+ // Message is not JSON, drop it
49
+ } else {
50
+ // Bubble up whatever exception is thrown
51
+ throw e;
52
+ }
53
+ }
54
+ };
55
+ else
56
+ mqtt_cb = function(mqtt_message) {
57
+ try {
58
+ var f = JSON.parse(mqtt_message);
59
+ if(f.type==='publish')
60
+ callback(f.payload, f.from);
61
+ } catch(e) {
62
+ if (e instanceof SyntaxError) {
63
+ // Message is not JSON, drop it
64
+ } else {
65
+ // Bubble up whatever exception is thrown
66
+ throw e;
67
+ }
68
+ }
69
+ };
70
+ // Add to subscriptions, save mqtt callback and subscribe
71
+ this.subscriptions.push(padded_channel);
72
+ this.callbacks.push(mqtt_cb);
73
+ this.nutella.mqtt_client.subscribe(padded_channel, mqtt_cb, done_callback);
74
+ // Notify subscription
75
+ this.publish_to('subscriptions', {type: 'subscribe', channel: padded_channel}, appId, runId);
76
+ };
77
+
78
+
79
+ /**
80
+ * Unsubscribes from a channel or a set of channels
81
+ *
82
+ * @param {string} channel - we want to unsubscribe from. Can contain wildcard(s)
83
+ * @param {string|undefined} appId - used to pad channels
84
+ * @param {string|undefined} runId - used to pad channels
85
+ * @param {function} done_callback - fired whenever the subscribe is successful
86
+ */
87
+ AbstractNet.prototype.unsubscribe_from = function(channel, appId, runId, done_callback ) {
88
+ // Pad channel
89
+ var padded_channel = this.pad_channel(channel, appId, run_id);
90
+ var idx = this.subscriptions.indexOf(padded_channel);
91
+ // If we are not subscribed to this channel, return (no error is given)
92
+ if(idx===-1) return;
93
+ // Fetch the mqtt_callback associated with this channel/subscription
94
+ var mqtt_cb = this.callbacks[idx];
95
+ // Remove from subscriptions, callbacks and unsubscribe
96
+ this.subscriptions.splice(idx, 1);
97
+ this.callbacks.splice(idx, 1);
98
+ this.nutella.mqtt_client.unsubscribe(padded_channel, mqtt_cb, done_callback);
99
+ };
100
+
101
+
102
+ /**
103
+ * Publishes a message to a channel
104
+ *
105
+ * @param {String} channel - the channel we want to publish the message to. *CANNOT* contain wildcard(s)!
106
+ * @param {Object} message - the message we are publishing. This can be any JS variable, even undefined.
107
+ * @param {String|undefined} appId - used to pad the channels
108
+ * @param {String|undefined} runId - used to pad the channels
109
+ */
110
+ AbstractNet.prototype.publish_to = function(channel, message, appId, runId) {
111
+ // Pad channel
112
+ var padded_channel = this.pad_channel(channel, appId, runId);
113
+ // Throw exception if trying to publish something that is not JSON
114
+ try {
115
+ var m = this.prepare_message_for_publish(message);
116
+ this.nutella.mqtt_client.publish(padded_channel, m);
117
+ } catch(e) {
118
+ console.error('Error: you are trying to publish something that is not JSON');
119
+ console.error(e.message);
120
+ }
121
+ };
122
+
123
+
124
+ /**
125
+ * This callback is fired whenever a response to a request is received
126
+ *
127
+ * @callback requestCallback
128
+ * @param {string} response - the body of the response
129
+ */
130
+
131
+ /**
132
+ * Performs an asynchronous request
133
+ *
134
+ * @param {string} channel - the channel we want to make the request to. *CANNOT* contain wildcard(s)!
135
+ * @param {string} message - the body of the request. This can be any JS variable, even undefined.
136
+ * @param {requestCallback} callback - the callback that is fired whenever a response is received
137
+ * @param {string|undefined} appId - used to pad channels
138
+ * @param {string|undefined} runId - used to pad channels
139
+ */
140
+ AbstractNet.prototype.request_to = function( channel, message, callback, appId, runId ) {
141
+ // Save nutella reference
142
+ var nut = this.nutella;
143
+ // Pad channel
144
+ var padded_channel = this.pad_channel(channel, appId, runId);
145
+ // Prepare message
146
+ var m = this.prepare_message_for_request(message);
147
+ //Prepare callback
148
+ var mqtt_cb = function(mqtt_message) {
149
+ var f = JSON.parse(mqtt_message);
150
+ if (f.id===m.id && f.type==='response') {
151
+ callback(f.payload);
152
+ nut.mqtt_client.unsubscribe(padded_channel, mqtt_cb);
153
+ }
154
+ };
155
+ // Subscribe
156
+ this.nutella.mqtt_client.subscribe(padded_channel, mqtt_cb, function() {
157
+ // Publish message
158
+ nut.mqtt_client.publish( padded_channel, m.message );
159
+ });
160
+
161
+ };
162
+
163
+
164
+ /**
165
+ * This callback is fired whenever a request is received that needs to be handled
166
+ *
167
+ * @callback handleCallback
168
+ * @param {string} request - the body of the received request (payload). Messages that are not JSON are discarded.
169
+ * @param {Object} from - the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
170
+ * @return {Object} The response sent back to the client that performed the request. Whatever is returned by the callback is marshaled into a JSON string and sent via MQTT.
171
+ */
172
+
173
+ /**
174
+ * Handles requests on a certain channel or a certain set of channels
175
+ *
176
+ * @param {string} channel - the channel we want to listen for requests on. Can contain wildcard(s).
177
+ * @param {handleCallback} callback - fired whenever a message is received
178
+ * @param {string|undefined} appId - used to pad channels
179
+ * @param {string|undefined} runId - used to pad channels
180
+ * @param {function} done_callback - fired whenever we are ready to handle requests
181
+ */
182
+ AbstractNet.prototype.handle_requests_on = function( channel, callback, appId, runId, done_callback) {
183
+ // Save nutella reference
184
+ var nut = this.nutella;
185
+ // Pad channel
186
+ var padded_channel = this.pad_channel(channel, appId, runId);
187
+ var mqtt_cb = function(request) {
188
+ try {
189
+ // Extract nutella fields
190
+ var f = JSON.parse(request);
191
+ // Only handle requests that have proper id set
192
+ if(f.type!=='request' || f.id===undefined) return;
193
+ // Execute callback and send response
194
+ var m = this.prepare_message_for_response(callback(f.payload, f.from), f.id);
195
+ nut.mqtt_client.publish( padded_channel, m );
196
+ } catch(e) {
197
+ if (e instanceof SyntaxError) {
198
+ // Message is not JSON, drop it
199
+ } else {
200
+ // Bubble up whatever exception is thrown
201
+ throw e;
202
+ }
203
+ }
204
+ };
205
+ // Subscribe to the channel
206
+ this.nutella.mqtt_client.subscribe(padded_channel, mqtt_cb, done_callback);
207
+ // Notify subscription
208
+ this.publish_to('subscriptions', {type: 'handle_requests', channel: padded_channel}, appId, runId);
209
+ };
210
+
211
+
212
+
213
+ /**
214
+ * Pads the channel with app_id and run_id
215
+ *
216
+ * @param channel
217
+ * @param app_id
218
+ * @param run_id
219
+ * @return {string} the padded channel
220
+ */
221
+ AbstractNet.prototype.pad_channel = function(channel, app_id, run_id) {
222
+ if (run_id!==undefined && app_id===undefined)
223
+ throw 'If the run_id is specified, app_id needs to also be specified';
224
+ if (app_id===undefined && run_id===undefined)
225
+ return '/nutella/' + channel;
226
+ if (app_id!==undefined && run_id===undefined)
227
+ return '/nutella/apps/' + app_id + '/' + channel;
228
+ return '/nutella/apps/' + app_id + '/runs/' + run_id + '/' + channel;
229
+ };
230
+
231
+
232
+ /**
233
+ * Un-pads the channel with app_id and run_id
234
+ *
235
+ * @param channel
236
+ * @param app_id
237
+ * @param run_id
238
+ * @return {string} the un-padded channel
239
+ */
240
+ AbstractNet.prototype.un_pad_channel = function(channel, app_id, run_id) {
241
+ if (run_id!==undefined && app_id===undefined)
242
+ throw 'If the run_id is specified, app_id needs to also be specified';
243
+ if (app_id===undefined && run_id===undefined)
244
+ return channel.replace('/nutella/', '');
245
+ if (app_id!==undefined && run_id===undefined)
246
+ return channel.replace("/nutella/apps/" + app_id + "/", '');
247
+ return channel.replace("/nutella/apps/" + app_id + "/runs/" + run_id + "/", '');
248
+ };
249
+
250
+
251
+ /**
252
+ * Assembles the unique ID of the component, starting from app_id, run_id, component_id and resource_id
253
+ *
254
+ * @return {Object} an object containing the unique ID of the component sending the message
255
+ */
256
+ AbstractNet.prototype.assemble_from = function() {
257
+ var from = {};
258
+ // Set type, run_id and app_id whenever appropriate
259
+ if(this.nutella.runId===undefined) {
260
+ if(this.nutella.appId===undefined) {
261
+ from.type = 'framework';
262
+ } else {
263
+ from.type = 'app';
264
+ from.app_id = this.nutella.appId;
265
+ }
266
+ } else {
267
+ from.type = 'run';
268
+ from.app_id = this.nutella.appId;
269
+ from.run_id = this.nutella.runId;
270
+ }
271
+ // Set the component_id
272
+ from.component_id = this.nutella.componentId;
273
+ // Set resource_id, if defined
274
+ if (this.nutella.resourceId!==undefined)
275
+ from.resource_id = this.nutella.resourceId;
276
+ return from;
277
+ };
278
+
279
+
280
+ /**
281
+ * Prepares a message for a publish
282
+ *
283
+ * @param {Object} message - the message content
284
+ * @return {string} the serialized message, ready to be shipped over the net
285
+ */
286
+ AbstractNet.prototype.prepare_message_for_publish = function (message) {
287
+ if(message===undefined)
288
+ return JSON.stringify({type: 'publish', from: this.assemble_from()});
289
+ return JSON.stringify({type: 'publish', from: this.assemble_from(), payload: message});
290
+ };
291
+
292
+
293
+ /**
294
+ * Prepares a message for a request
295
+ *
296
+ * @param {Object} message - the message content
297
+ * @return {Object} the serialized response, ready to be shipped over the net and the id of the response
298
+ */
299
+ AbstractNet.prototype.prepare_message_for_request = function (message) {
300
+ var id = Math.floor((Math.random() * 100000) + 1).toString();
301
+ var m = {};
302
+ m.id = id;
303
+ if(message===undefined)
304
+ m.message = JSON.stringify({id: id, type: 'request', from: this.assemble_from()});
305
+ else
306
+ m.message = JSON.stringify({id: id, type: 'request', from: this.assemble_from(), payload: message});
307
+ return m;
308
+ };
309
+
310
+
311
+ /**
312
+ * Prepares a message for a response
313
+ *
314
+ * @param {Object} response - the response content
315
+ * @param {string} id - the original request id
316
+ * @return {string} the serialized message, ready to be shipped over the net
317
+ */
318
+ AbstractNet.prototype.prepare_message_for_response = function (response, id) {
319
+ if(response===undefined)
320
+ return JSON.stringify({id: id, type: 'response', from: this.assemble_from()});
321
+ return JSON.stringify({id: id, type: 'response', from: this.assemble_from(), payload: response});
322
+ };
323
+
324
+
325
+
326
+ // Export module
327
+ module.exports = AbstractNet;
@@ -0,0 +1,16 @@
1
+ if( typeof NUTELLA === 'undefined' ) {
2
+ var NUTELLA = require('../src/nutella_lib');
3
+ var assert = require('chai').assert;
4
+ } else {
5
+ var assert = chai.assert;
6
+ }
7
+
8
+
9
+
10
+ describe('Nutella', function(){
11
+ describe('NUTELLA', function(){
12
+ it('should return defined when called', function(){
13
+ assert.notEqual(undefined, NUTELLA, 'NUTELLA is undefined!');
14
+ })
15
+ })
16
+ })