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.
- 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
|
+
})
|