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.
- checksums.yaml +4 -4
- data/Gemfile +14 -15
- data/VERSION +1 -1
- data/framework_components/beacon-cloud-bot/README.md +27 -0
- data/framework_components/beacon-cloud-bot/beacon_cloud_bot.rb +154 -0
- data/framework_components/beacon-cloud-bot/nutella.json +6 -0
- data/framework_components/beacon-cloud-bot/startup +4 -0
- data/framework_components/beacon-cloud-interface/LICENSE +21 -0
- data/framework_components/beacon-cloud-interface/Readme.md +0 -0
- data/framework_components/beacon-cloud-interface/bower.json +29 -0
- data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/.bower.json +23 -0
- data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/bower.json +14 -0
- data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/mqttws31.js +2081 -0
- data/framework_components/beacon-cloud-interface/bower_components/bower-mqttws/readme.md +4 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/.bower.json +37 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/LICENSE +21 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/README.md +15 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/bower.json +28 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/browser/mqtt_client_hello_world.html +23 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/browser/nutella_hello_world.html +52 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/node/mqtt_client_hello_world.js +14 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/examples/node/nutella_hello_world.js +38 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/nutella_lib.js +789 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/package.json +30 -0
- data/framework_components/beacon-cloud-interface/bower_components/nutella_lib/simple-js-mqtt-client.js +428 -0
- data/framework_components/beacon-cloud-interface/css/animation.css +17 -0
- data/framework_components/beacon-cloud-interface/css/cursor.css +16 -0
- data/framework_components/beacon-cloud-interface/css/page_layout.css +73 -0
- data/framework_components/beacon-cloud-interface/index.html +157 -0
- data/framework_components/beacon-cloud-interface/js/lib/nutella_lib.js +4039 -0
- data/framework_components/beacon-cloud-interface/js/react/beacon-add.js +102 -0
- data/framework_components/beacon-cloud-interface/js/react/beacon-table.js +73 -0
- data/framework_components/beacon-cloud-interface/js/react/beacon.js +97 -0
- data/framework_components/beacon-cloud-interface/nutella.json +6 -0
- data/framework_components/example_framework_web_interface/index.html +11 -2
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/.npmignore +10 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/.travis.yml +5 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/LICENSE +21 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/README.md +27 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/dist/nutella_lib.js +4039 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/dist/nutella_lib.js.map +1 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/examples/browser_hello_world.html +67 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/examples/node_hello_world.js +51 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/gulpfile.js +31 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/package.json +41 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_core.js +19 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_core_browser.js +17 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_log.js +50 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_net.js +279 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/app_persist.js +20 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_core_browser.js +17 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_log.js +50 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/fr_net.js +499 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_i.js +74 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_i_browser.js +130 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_lib.js +91 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/nutella_lib_browser.js +90 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_log.js +51 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_net.js +84 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_persist.js +20 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/util/net.js +327 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/test/nutella.test.js +16 -0
- data/framework_components/example_framework_web_interface/node_modules/nutella_lib/test/runner.html +22 -0
- data/framework_components/example_framework_web_interface/package.json +15 -0
- data/framework_components/{order.json.example → order.json} +0 -0
- data/framework_components/runs_list_bot/{app_runs_list_bot.rb → runs_list_bot.rb} +9 -3
- data/framework_components/runs_list_bot/startup +1 -1
- data/lib/commands/meta/run_command.rb +21 -36
- data/lib/commands/start.rb +9 -199
- data/lib/commands/util/components_list.rb +68 -0
- data/lib/commands/util/components_starter.rb +169 -0
- data/nutella_framework.gemspec +109 -47
- data/nutella_lib/framework_net.rb +17 -13
- 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;
|
data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_log.js
ADDED
|
@@ -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;
|
data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/run_net.js
ADDED
|
@@ -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;
|
data/framework_components/example_framework_web_interface/node_modules/nutella_lib/src/util/net.js
ADDED
|
@@ -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
|
+
})
|