nutella_framework 0.4.5 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
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
+ })