nutella_framework 0.4.23 → 0.4.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/framework_components/monitoring-bot/monitoring-bot.rb +11 -2
  4. data/framework_components/monitoring-interface/.gitignore +2 -0
  5. data/framework_components/monitoring-interface/README.md +1 -0
  6. data/framework_components/monitoring-interface/bower.json +29 -0
  7. data/framework_components/monitoring-interface/bower_components/bower-mqttws/.bower.json +23 -0
  8. data/framework_components/monitoring-interface/bower_components/bower-mqttws/bower.json +14 -0
  9. data/framework_components/monitoring-interface/bower_components/bower-mqttws/mqttws31.js +2081 -0
  10. data/framework_components/monitoring-interface/bower_components/bower-mqttws/readme.md +4 -0
  11. data/framework_components/monitoring-interface/bower_components/nutella_lib/.bower.json +37 -0
  12. data/framework_components/monitoring-interface/bower_components/nutella_lib/LICENSE +21 -0
  13. data/framework_components/monitoring-interface/bower_components/nutella_lib/README.md +15 -0
  14. data/framework_components/monitoring-interface/bower_components/nutella_lib/bower.json +28 -0
  15. data/framework_components/monitoring-interface/bower_components/nutella_lib/examples/browser/mqtt_client_hello_world.html +23 -0
  16. data/framework_components/monitoring-interface/bower_components/nutella_lib/examples/browser/nutella_hello_world.html +52 -0
  17. data/framework_components/monitoring-interface/bower_components/nutella_lib/examples/node/mqtt_client_hello_world.js +14 -0
  18. data/framework_components/monitoring-interface/bower_components/nutella_lib/examples/node/nutella_hello_world.js +38 -0
  19. data/framework_components/monitoring-interface/bower_components/nutella_lib/nutella_lib.js +789 -0
  20. data/framework_components/monitoring-interface/bower_components/nutella_lib/package.json +30 -0
  21. data/framework_components/monitoring-interface/css/Monitoring Interface.html +215 -0
  22. data/framework_components/monitoring-interface/css/Monitoring Interface_files/animations.js +27 -0
  23. data/framework_components/monitoring-interface/css/Monitoring Interface_files/application-view-controller.js +232 -0
  24. data/framework_components/monitoring-interface/css/Monitoring Interface_files/applications-model.js +61 -0
  25. data/framework_components/monitoring-interface/css/Monitoring Interface_files/bootstrap.min.js +7 -0
  26. data/framework_components/monitoring-interface/css/Monitoring Interface_files/cursor.css +7 -0
  27. data/framework_components/monitoring-interface/css/Monitoring Interface_files/d3.v3.min.js +5 -0
  28. data/framework_components/monitoring-interface/css/Monitoring Interface_files/graphics.js +156 -0
  29. data/framework_components/monitoring-interface/css/Monitoring Interface_files/grid-layout.js +103 -0
  30. data/framework_components/monitoring-interface/css/Monitoring Interface_files/highlight.min.js +2 -0
  31. data/framework_components/monitoring-interface/css/Monitoring Interface_files/instance-view-controller.js +104 -0
  32. data/framework_components/monitoring-interface/css/Monitoring Interface_files/jquery-1.10.0.min.js +6 -0
  33. data/framework_components/monitoring-interface/css/Monitoring Interface_files/notification-center.js +63 -0
  34. data/framework_components/monitoring-interface/css/Monitoring Interface_files/notifications.js +14 -0
  35. data/framework_components/monitoring-interface/css/Monitoring Interface_files/page.css +33 -0
  36. data/framework_components/monitoring-interface/css/Monitoring Interface_files/radial-layout.js +175 -0
  37. data/framework_components/monitoring-interface/css/Monitoring Interface_files/tab-table.js +8 -0
  38. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-application.css +0 -0
  39. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-application.js +320 -0
  40. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-connection-view.css +10 -0
  41. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-connection-view.js +426 -0
  42. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-element.js +205 -0
  43. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-notification.js +94 -0
  44. data/framework_components/monitoring-interface/css/Monitoring Interface_files/ui-tab.js +229 -0
  45. data/framework_components/monitoring-interface/css/Monitoring Interface_files/underscore-min.js +5 -0
  46. data/framework_components/monitoring-interface/css/Monitoring Interface_files/view-controller.js +68 -0
  47. data/framework_components/monitoring-interface/css/Monitoring Interface_files/window-view-controller.js +169 -0
  48. data/framework_components/monitoring-interface/css/alerts.css +3 -0
  49. data/framework_components/monitoring-interface/css/bootstrap.min.css +5 -0
  50. data/framework_components/monitoring-interface/css/cursor.css +7 -0
  51. data/framework_components/monitoring-interface/css/highlight.default.min.css +1 -0
  52. data/framework_components/monitoring-interface/css/page.css +41 -0
  53. data/framework_components/monitoring-interface/css/ui-application.css +0 -0
  54. data/framework_components/monitoring-interface/css/ui-connection-view.css +10 -0
  55. data/framework_components/monitoring-interface/css/ui-legend-view.css +7 -0
  56. data/framework_components/monitoring-interface/data/alert.json +8 -0
  57. data/framework_components/monitoring-interface/data/data.json +2118 -0
  58. data/framework_components/monitoring-interface/data/data2.json +814 -0
  59. data/framework_components/monitoring-interface/data/data3.json +823 -0
  60. data/framework_components/monitoring-interface/data/data4.json +848 -0
  61. data/framework_components/monitoring-interface/data/message.json +999 -0
  62. data/framework_components/monitoring-interface/gulpfile.js +29 -0
  63. data/framework_components/monitoring-interface/img/arrow_white.svg +120 -0
  64. data/framework_components/monitoring-interface/img/arrow_white_right.svg +104 -0
  65. data/framework_components/monitoring-interface/img/back.svg +164 -0
  66. data/framework_components/monitoring-interface/img/cross_red_border_white.svg +143 -0
  67. data/framework_components/monitoring-interface/img/cross_red_border_white_mouseover.svg +143 -0
  68. data/framework_components/monitoring-interface/img/email.svg +89 -0
  69. data/framework_components/monitoring-interface/img/email_highlighted.svg +89 -0
  70. data/framework_components/monitoring-interface/index.html +144 -0
  71. data/framework_components/monitoring-interface/js/d3/layout/grid-layout.js +103 -0
  72. data/framework_components/monitoring-interface/js/d3/layout/radial-layout.js +184 -0
  73. data/framework_components/monitoring-interface/js/d3/plugin/graphics.js +156 -0
  74. data/framework_components/monitoring-interface/js/d3/plugin/tab-table.js +8 -0
  75. data/framework_components/monitoring-interface/js/d3/ui/animations.js +27 -0
  76. data/framework_components/monitoring-interface/js/d3/ui/ui-application.js +471 -0
  77. data/framework_components/monitoring-interface/js/d3/ui/ui-connection-view.js +847 -0
  78. data/framework_components/monitoring-interface/js/d3/ui/ui-element.js +245 -0
  79. data/framework_components/monitoring-interface/js/d3/ui/ui-legend.js +174 -0
  80. data/framework_components/monitoring-interface/js/d3/ui/ui-notification.js +90 -0
  81. data/framework_components/monitoring-interface/js/d3/ui/ui-tab.js +309 -0
  82. data/framework_components/monitoring-interface/js/lib/JSXTransformer-0.12.2.js +15199 -0
  83. data/framework_components/monitoring-interface/js/lib/bootstrap.min.js +7 -0
  84. data/framework_components/monitoring-interface/js/lib/d3.v3.min.js +5 -0
  85. data/framework_components/monitoring-interface/js/lib/highlight.min.js +2 -0
  86. data/framework_components/monitoring-interface/js/lib/jquery-1.10.0.min.js +6 -0
  87. data/framework_components/monitoring-interface/js/lib/nutella_lib.js +5121 -0
  88. data/framework_components/monitoring-interface/js/lib/react-with-addons-0.12.2.js +19822 -0
  89. data/framework_components/monitoring-interface/js/lib/underscore-min.js +5 -0
  90. data/framework_components/monitoring-interface/js/model/alerts-model.js +74 -0
  91. data/framework_components/monitoring-interface/js/model/applications-model.js +78 -0
  92. data/framework_components/monitoring-interface/js/model/messages-model.js +112 -0
  93. data/framework_components/monitoring-interface/js/notification/notification-center.js +63 -0
  94. data/framework_components/monitoring-interface/js/notification/notifications.js +21 -0
  95. data/framework_components/monitoring-interface/js/react/dist/ui-alerts.js +178 -0
  96. data/framework_components/monitoring-interface/js/react/dist/ui-message-send.js +389 -0
  97. data/framework_components/monitoring-interface/js/react/dist/ui-messages.js +103 -0
  98. data/framework_components/monitoring-interface/js/react/src/ui-alerts.js +178 -0
  99. data/framework_components/monitoring-interface/js/react/src/ui-message-send.js +389 -0
  100. data/framework_components/monitoring-interface/js/react/src/ui-messages.js +103 -0
  101. data/framework_components/monitoring-interface/js/view-controller/application-view-controller.js +256 -0
  102. data/framework_components/monitoring-interface/js/view-controller/instance-view-controller.js +112 -0
  103. data/framework_components/monitoring-interface/js/view-controller/view-controller.js +74 -0
  104. data/framework_components/monitoring-interface/js/view-controller/window-view-controller.js +169 -0
  105. data/framework_components/monitoring-interface/nutella.json +6 -0
  106. data/framework_components/order.json +1 -0
  107. data/framework_components/roomcast-bot/roomcast_bot.rb +139 -117
  108. data/framework_components/roomcast-channel-creator/dist/app.js +9 -7
  109. data/framework_components/roomcast-channel-creator/index.html +1 -1
  110. data/framework_components/roomcast-channel-creator/src/app/components/main.js +8 -6
  111. data/framework_components/roomcast-package-creator/dist/app.js +4 -4
  112. data/framework_components/roomcast-package-creator/index.html +1 -1
  113. data/framework_components/roomcast-package-creator/package.json +3 -3
  114. data/framework_components/roomcast-package-creator/src/app/components/ConfigurationsPanel.js +2 -2
  115. data/framework_components/roomcast-package-creator/src/app/components/PoolRow.js +1 -1
  116. data/framework_components/roomcast-teacher-controls/.gitignore +2 -0
  117. data/framework_components/roomcast-teacher-controls/README.md +9 -0
  118. data/framework_components/roomcast-teacher-controls/dist/app.js +38327 -0
  119. data/framework_components/roomcast-teacher-controls/dist/main.css +3052 -0
  120. data/framework_components/roomcast-teacher-controls/dist/nutella_lib.js +5121 -0
  121. data/framework_components/roomcast-teacher-controls/gulp/config.js +51 -0
  122. data/framework_components/roomcast-teacher-controls/gulp/tasks/browserify.js +77 -0
  123. data/framework_components/roomcast-teacher-controls/gulp/tasks/build.js +3 -0
  124. data/framework_components/roomcast-teacher-controls/gulp/tasks/css.js +7 -0
  125. data/framework_components/roomcast-teacher-controls/gulp/tasks/default.js +3 -0
  126. data/framework_components/roomcast-teacher-controls/gulp/tasks/fonts.js +7 -0
  127. data/framework_components/roomcast-teacher-controls/gulp/tasks/less.js +16 -0
  128. data/framework_components/roomcast-teacher-controls/gulp/tasks/mui-fonts.js +7 -0
  129. data/framework_components/roomcast-teacher-controls/gulp/tasks/nutella.js +7 -0
  130. data/framework_components/roomcast-teacher-controls/gulp/tasks/setWatch.js +5 -0
  131. data/framework_components/roomcast-teacher-controls/gulp/tasks/svgs.js +7 -0
  132. data/framework_components/roomcast-teacher-controls/gulp/tasks/watch.js +12 -0
  133. data/framework_components/roomcast-teacher-controls/gulp/util/bundleLogger.js +21 -0
  134. data/framework_components/roomcast-teacher-controls/gulp/util/handleErrors.js +15 -0
  135. data/framework_components/roomcast-teacher-controls/gulpfile.js +16 -0
  136. data/framework_components/roomcast-teacher-controls/index.html +51 -0
  137. data/framework_components/roomcast-teacher-controls/nutella.json +6 -0
  138. data/framework_components/roomcast-teacher-controls/package.json +38 -0
  139. data/framework_components/roomcast-teacher-controls/src/app/app.js +22 -0
  140. data/framework_components/roomcast-teacher-controls/src/app/components/ActivitiesGrid.js +87 -0
  141. data/framework_components/roomcast-teacher-controls/src/app/components/ActivityCard.js +141 -0
  142. data/framework_components/roomcast-teacher-controls/src/app/components/Channel.js +70 -0
  143. data/framework_components/roomcast-teacher-controls/src/app/components/Footer.js +34 -0
  144. data/framework_components/roomcast-teacher-controls/src/app/components/main.js +74 -0
  145. data/framework_components/roomcast-teacher-controls/src/less/main.less +186 -0
  146. data/framework_components/roomcast-teacher-controls/src/less/my_overrides.less +14 -0
  147. data/lib/commands/meta/run_command.rb +11 -9
  148. metadata +135 -2
@@ -0,0 +1,789 @@
1
+ /******************
2
+ * nutella_lib.js *
3
+ ******************/
4
+
5
+ (function() {
6
+ "use strict";
7
+
8
+ // Establish the root object, `window` in the browser, or `exports` on the server.
9
+ var root = this;
10
+
11
+ // Save the previous value of the `nutella` variable for noConflict().
12
+ var previousNutella = root.NUTELLA;
13
+
14
+ // Internal reference to this library (used below)
15
+ var nutella = {};
16
+
17
+ // Detect if we are in the browser or in node and
18
+ // load the appropriate dependencies
19
+ var isNode;
20
+ var mqtt_lib;
21
+ if (typeof window === 'undefined') {
22
+ isNode = true; // Node
23
+ mqtt_lib = require('mqtt');
24
+ if( typeof mqtt_lib === 'undefined' )
25
+ throw new Error('This MQTT client requires the mqtt library (https://www.npmjs.com/package/mqtt)');
26
+ } else {
27
+ isNode = false; // Browser
28
+ mqtt_lib = root.Paho.MQTT;
29
+ if( typeof mqtt_lib === 'undefined' )
30
+ throw new Error('This MQTT client requires the mqtt-ws library (https://github.com/M2MConnections/mqtt-ws) a wrapper of Paho.js');
31
+
32
+ }
33
+
34
+
35
+
36
+ /**
37
+ * Runs nutella.js in noConflict mode by
38
+ * returning the NUTELLA variable to its previous owner.
39
+ *
40
+ * @return a reference to the nutella object defined by this library.
41
+ */
42
+ nutella.noConflict = function() {
43
+ root.NUTELLA = previousNutella;
44
+ return nutella;
45
+ };
46
+
47
+
48
+
49
+ /**
50
+ * Parses URL parameters.
51
+ * Note: this function is not defined if we are not in the browser.
52
+ *
53
+ * @return {Object} An object containing all the URL query parameters
54
+ */
55
+ if (!isNode) {
56
+ nutella.parseURLParameters = function () {
57
+ var str = location.search;
58
+ var queries = str.replace(/^\?/, '').split('&');
59
+ var searchObject = {};
60
+ for( var i = 0; i < queries.length; i++ ) {
61
+ var split = queries[i].split('=');
62
+ searchObject[split[0]] = split[1];
63
+ }
64
+ return searchObject;
65
+ }
66
+ }
67
+
68
+
69
+ /**
70
+ * Creates a new instance of nutella
71
+ * and initialize it
72
+ * This is a factory method.
73
+ *
74
+ *
75
+ * @param {string} run_id - the run_id this component is launched in
76
+ * @param {string} broker_hostname - the hostname of the broker.
77
+ * @param {string} component_id - the name of this component
78
+ */
79
+ nutella.init = function(run_id, broker_hostname, component_id) {
80
+ if (run_id===undefined || broker_hostname===undefined || component_id=== undefined) {
81
+ console.warn("Couldn't initialize nutella. Make sure you are setting all three the required parameters (runId, broker_hostname, componentId'");
82
+ }
83
+ return new NutellaInstance(run_id, broker_hostname, component_id);
84
+ };
85
+
86
+
87
+
88
+ /**
89
+ * Defines a nutella instance.
90
+ *
91
+ * @param {string} run_id - the run_id this component is launched in
92
+ * @param {string} broker_hostname - the hostname of the broker.
93
+ * @param {string} component_id - the name of this component
94
+ */
95
+ var NutellaInstance = function (run_id, broker_hostname, component_id) {
96
+
97
+ this.mqtt_client = new SimpleMQTTClient(broker_hostname);
98
+ this.runId = run_id;
99
+ this.componentId = component_id;
100
+
101
+ // Initialized the various sub-modules
102
+ this.net = new NetSubModule(this);
103
+ this.persist = new PersistSubModule(this);
104
+ // ... other sub-modules here
105
+ };
106
+
107
+
108
+
109
+ /**
110
+ * Sets the resource id for this instance of nutella
111
+ *
112
+ * @param {string} resource_id - the resource_id associated to this instance of nutella
113
+ */
114
+ NutellaInstance.prototype.setResourceId = function(resource_id){
115
+ this.resourceId = resource_id;
116
+ };
117
+
118
+
119
+
120
+
121
+ //
122
+ // END OF: main nutella protocol module
123
+ //
124
+
125
+
126
+
127
+ // --------------------------------------------------------------------------------------------
128
+ // net sub-module
129
+ // --------------------------------------------------------------------------------------------
130
+
131
+
132
+ var NetSubModule = function(main_nutella) {
133
+ // Store a reference to the main module
134
+ this.main_nutella = main_nutella;
135
+
136
+ // Store the subscriptions and the relative callbacks
137
+ this.subscriptions = [];
138
+ this.callbacks = [];
139
+ };
140
+
141
+
142
+
143
+ /**
144
+ * Subscribes to a channel or filter.
145
+ *
146
+ * @param channel
147
+ * @param callback
148
+ * @param done_callback
149
+ */
150
+ NetSubModule.prototype.subscribe = function(channel, callback, done_callback) {
151
+ // Prevent multiple subscriptions to the same channel
152
+ if (this.subscriptions.indexOf(channel)!==-1)
153
+ throw new Error('You can`t subscribe twice to the same channel');
154
+ // Pad the channel
155
+ var runId = this.main_nutella.runId;
156
+ var new_channel = runId + '/' + channel;
157
+ // Define callbacks
158
+ var mqtt_cb;
159
+ if (isChannelWildcard(channel))
160
+ mqtt_cb = function(mqtt_message, mqtt_channel) {
161
+ // Ignore anything that is not JSON or
162
+ // doesn't comply to the nutella protocol
163
+ try {
164
+ var f = extractFieldsFromMessage(mqtt_message);
165
+ var clean_channel = mqtt_channel.replace(runId+'/', '');
166
+ if (f.type==='publish')
167
+ callback(f.payload, clean_channel, f.componentId, f.resourceId);
168
+ } catch(err) {
169
+ }
170
+ };
171
+ else
172
+ mqtt_cb = function(mqtt_message) {
173
+ // Ignore anything that is not JSON or
174
+ // doesn't comply to the nutella protocol
175
+ try {
176
+ var f = extractFieldsFromMessage(mqtt_message);
177
+ if (f.type==='publish')
178
+ callback(f.payload, f.componentId, f.resourceId);
179
+ } catch(err) {
180
+ }
181
+ };
182
+ // Update subscriptions, callbacks and subscribe
183
+ this.subscriptions.push(channel);
184
+ this.callbacks.push(mqtt_cb);
185
+ this.main_nutella.mqtt_client.subscribe(new_channel, mqtt_cb, done_callback);
186
+ };
187
+
188
+
189
+
190
+ /**
191
+ * Unsubscribes from a channel
192
+ *
193
+ * @param channel
194
+ * @param done_callback
195
+ */
196
+ NetSubModule.prototype.unsubscribe = function(channel, done_callback) {
197
+ // Find index of subscription and retrieve relative callback
198
+ var idx = this.subscriptions.indexOf(channel);
199
+ var cbAtIdx = this.callbacks[idx];
200
+ // Pad the channel
201
+ var new_channel = this.main_nutella.runId + '/' + channel;
202
+ // Unsubscribe
203
+ this.subscriptions.splice(idx, 1);
204
+ this.callbacks.splice(idx, 1);
205
+ this.main_nutella.mqtt_client.unsubscribe(new_channel, cbAtIdx, done_callback);
206
+ };
207
+
208
+
209
+
210
+ /**
211
+ * Publishes a message to a channel
212
+ *
213
+ * @param channel
214
+ * @param message
215
+ */
216
+ NetSubModule.prototype.publish = function(channel, message) {
217
+ // Pad the channel
218
+ var new_channel = this.main_nutella.runId + '/' + channel;
219
+ var m = prepareMessageForPublish(message, this.main_nutella.componentId, this.main_nutella.resourceId);
220
+ this.main_nutella.mqtt_client.publish(new_channel, m);
221
+ };
222
+
223
+
224
+
225
+ /**
226
+ * Sends a request.
227
+ *
228
+ * @param channel
229
+ * @param message
230
+ * @param callback
231
+ * @param done_callback
232
+ */
233
+ NetSubModule.prototype.request = function(channel, message, callback, done_callback) {
234
+ // Handle optional message parameter
235
+ if (typeof message==='function') {
236
+ if (callback!==undefined)
237
+ done_callback = callback;
238
+ callback = message;
239
+ message = undefined;
240
+ }
241
+ // Pad channel
242
+ var new_channel = this.main_nutella.runId + '/' + channel;
243
+ // Prepare request
244
+ var request_id = Math.floor((Math.random() * 100000) + 1).toString();
245
+ var mqtt_request = prepareRequest(message, request_id, this.main_nutella.componentId, this.main_nutella.resourceId);
246
+ // Prepare callback to handle response
247
+ var mqtt_cb = function(mqtt_response) {
248
+ // Ignore anything that is not JSON or
249
+ // doesn't comply to the nutella protocol
250
+ try {
251
+ var f = extractFieldsFromMessage(mqtt_response);
252
+ var response_id = extractIdFromMessage(mqtt_response);
253
+ // Only handle responses that have proper id set
254
+ if (f.type==='response' && response_id===request_id) {
255
+ // Execute callback
256
+ callback(f.payload);
257
+ }
258
+ } catch(err) {
259
+ }
260
+ };
261
+ // Subscribe to response
262
+ var mqtt_cli = this.main_nutella.mqtt_client;
263
+ mqtt_cli.subscribe(new_channel, mqtt_cb, function() {
264
+ // Once we are subscribed we publish the request
265
+ mqtt_cli.publish(new_channel, mqtt_request);
266
+ // Execute optional done callback
267
+ if (done_callback!==undefined) done_callback();
268
+ });
269
+ };
270
+
271
+
272
+
273
+ /**
274
+ * Handles requests.
275
+ *
276
+ * @param channel
277
+ * @param callback
278
+ * @param done_callback
279
+ */
280
+ NetSubModule.prototype.handle_requests = function(channel, callback, done_callback) {
281
+ // Pad the channel
282
+ var new_channel = this.main_nutella.runId + '/' + channel;
283
+ // Prepare callback
284
+ var c_id = this.main_nutella.componentId;
285
+ var r_id = this.main_nutella.resourceId;
286
+ var mqtt_cli = this.main_nutella.mqtt_client;
287
+ var mqtt_cb = function(mqtt_request) {
288
+ // Ignore anything that is not JSON or
289
+ // doesn't comply to the nutella protocol
290
+ try {
291
+ var f = extractFieldsFromMessage(mqtt_request);
292
+ var id = extractIdFromMessage(mqtt_request);
293
+ } catch(err) {
294
+ return;
295
+ }
296
+ // Only handle requests that have proper id set
297
+ if (f.type!=='request' || id===undefined) return;
298
+ // Execute callback, assemble the response and publish
299
+ var res_json = callback(f.payload, f.componentId, f.resourceId);
300
+ var mqtt_response = prepareResponse(res_json, id, c_id, r_id);
301
+ mqtt_cli.publish(new_channel, mqtt_response);
302
+ };
303
+ // Subscribe
304
+ this.main_nutella.mqtt_client.subscribe(new_channel, mqtt_cb, done_callback);
305
+ };
306
+
307
+
308
+
309
+ //
310
+ // Helper function
311
+ // Extracts nutella parameters from a received message
312
+ //
313
+ function extractFieldsFromMessage(message) {
314
+ var params = JSON.parse(message);
315
+ var s = params.from.split('/');
316
+ delete params.from;
317
+ params.componentId = s[0];
318
+ if (s.length===2)
319
+ params.resourceId = s[1];
320
+ return params;
321
+ }
322
+
323
+
324
+
325
+ //
326
+ // Helper function
327
+ // Extracts request id from a received message
328
+ //
329
+ function extractIdFromMessage(message) {
330
+ var params = JSON.parse(message);
331
+ return params.id;
332
+ }
333
+
334
+
335
+
336
+ //
337
+ // Helper function
338
+ // Pads a message with the nutella protocol fields
339
+ //
340
+ function prepareMessageForPublish(message, componentId, resourceId) {
341
+ var from = resourceId===undefined ? componentId : (componentId + '/' + resourceId);
342
+ if (message===undefined)
343
+ return JSON.stringify({type: 'publish', from: from});
344
+ return JSON.stringify({type: 'publish', from: from, payload: message});
345
+ }
346
+
347
+
348
+
349
+ //
350
+ // Helper function
351
+ // Pads a request with the nutella protocol fields
352
+ //
353
+ function prepareRequest(message, request_id, componentId, resourceId) {
354
+ var from = resourceId===undefined ? componentId : (componentId + '/' + resourceId);
355
+ if (message===undefined)
356
+ return JSON.stringify({id: request_id, type: 'request', from: from});
357
+ return JSON.stringify({id: request_id, type: 'request', from: from, payload: message});
358
+ }
359
+
360
+
361
+
362
+ //
363
+ // Helper function
364
+ // Pads a response with the nutella protocol fields
365
+ //
366
+ function prepareResponse(message, request_id, componentId, resourceId) {
367
+ var from = resourceId===undefined ? componentId : (componentId + '/' + resourceId);
368
+ if (message===undefined)
369
+ return JSON.stringify({id: request_id, type: 'response', from: from});
370
+ return JSON.stringify({id: request_id, type: 'response', from: from, payload: message});
371
+ }
372
+
373
+
374
+
375
+ // Helper function to test if a channel is wildcard or not.
376
+ // Returns true if it is Returns true is.
377
+ // See MQTT specification for wildcard channels
378
+ // {http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106 here
379
+ //
380
+ function isChannelWildcard(channel) {
381
+ return channel.indexOf('#')!==-1 || channel.indexOf('+')!==-1;
382
+ }
383
+
384
+
385
+ //
386
+ // END OF: net sub-module
387
+ //
388
+
389
+
390
+
391
+ // --------------------------------------------------------------------------------------------
392
+ // persist sub-module
393
+ // --------------------------------------------------------------------------------------------
394
+
395
+
396
+ var PersistSubModule = function(main_nutella) {
397
+ // Store a reference to the main module
398
+ this.main_nutella = main_nutella;
399
+ };
400
+
401
+
402
+
403
+ PersistSubModule.prototype.persist = function () {
404
+ console.log("This is just a test method for the persist sub-module");
405
+ };
406
+
407
+
408
+
409
+
410
+ //
411
+ // END OF: persist sub-module
412
+ //
413
+
414
+
415
+
416
+
417
+ // --------------------------------------------------------------------------------------------
418
+ // Simple MQTT client
419
+ // --------------------------------------------------------------------------------------------
420
+
421
+
422
+ /**
423
+ * Defines a Simple MQTT client.
424
+ *
425
+ * @param {string} host - the hostname of the broker.
426
+ * @param {string} [clientId] - the unique name of this client. If no ID is provided a random one is generated
427
+ */
428
+ var SimpleMQTTClient = function (host, clientId) {
429
+
430
+ // Initializes the object that stores subscriptions
431
+ this.subscriptions = {};
432
+ // Initializes the object that holds the internal client
433
+ this.client = {};
434
+ // Functions backlog
435
+ this.backlog = [];
436
+
437
+ // Handles the optional clientId parameter
438
+ if (arguments.length === 1 || clientId === undefined) {
439
+ clientId = generateRandomClientId();
440
+ }
441
+
442
+ // Connect
443
+ if (isNode)
444
+ this.client = connectNode(this.subscriptions, host, clientId);
445
+ else
446
+ this.client = connectBrowser(this.subscriptions, this.backlog, host, clientId);
447
+ };
448
+
449
+
450
+ //
451
+ // Helper function that connects the MQTT client in node
452
+ //
453
+ function connectNode (subscriptions, host, clientId) {
454
+ // Create client
455
+ var url = "tcp://" + host + ":1883";
456
+ var client = mqtt_lib.connect(url, {clientId : clientId});
457
+ // Register incoming message callback
458
+ client.on('message', function(channel, message) {
459
+ // Executes the appropriate channel callback
460
+ var cbs = findCallbacks(subscriptions, channel);
461
+ if (cbs!==undefined) {
462
+ if (Object.keys(subscriptions).indexOf(channel)!==-1)
463
+ cbs.forEach(function(cb) {
464
+ cb(message);
465
+ });
466
+ else
467
+ cbs.forEach(function(cb) {
468
+ cb(message, channel);
469
+ });
470
+
471
+ }
472
+ });
473
+ return client;
474
+ }
475
+
476
+
477
+ //
478
+ // Helper function that connects the MQTT client in the browser
479
+ //
480
+ function connectBrowser (subscriptions, backlog, host, clientId) {
481
+ // Create client
482
+ var client = new mqtt_lib.Client(host, Number(1884), clientId);
483
+ // Register callback for connection lost
484
+ client.onConnectionLost = function() {
485
+ // TODO try to reconnect
486
+ };
487
+ // Register callback for received message
488
+ client.onMessageArrived = function (message) {
489
+ // Executes the appropriate channel callback
490
+ var cbs = findCallbacks(subscriptions, message.destinationName);
491
+ if (cbs!==undefined) {
492
+ if (Object.keys(subscriptions).indexOf(message.destinationName)!==-1)
493
+ cbs.forEach(function(cb) {
494
+ cb(message.payloadString);
495
+ });
496
+ else
497
+ cbs.forEach(function(cb) {
498
+ cb(message.payloadString, message.destinationName);
499
+ });
500
+ }
501
+ };
502
+ // Connect
503
+ client.connect({onSuccess: function() {
504
+ // Execute the backlog of operations performed while the client wasn't connected
505
+ backlog.forEach(function(e) {
506
+ e.op.apply(this, e.params);
507
+ });
508
+ }});
509
+ return client;
510
+ }
511
+
512
+
513
+
514
+ /**
515
+ * Disconnects from the MQTT client.
516
+ */
517
+ SimpleMQTTClient.prototype.disconnect = function () {
518
+ if (isNode)
519
+ this.client.end();
520
+ else
521
+ this.client.disconnect();
522
+ this.subscriptions = {};
523
+ };
524
+
525
+
526
+
527
+ /**
528
+ * Subscribes to a channel and registers a callback.
529
+ *
530
+ * @param {string} channel - the channel we are subscribing to.
531
+ * @param {callback} callback - A function that is executed every time a message is received on that channel.
532
+ * @param {callback} [done_callback] - A function that is executed once the subscribe operation has completed successfully.
533
+ */
534
+ SimpleMQTTClient.prototype.subscribe = function (channel, callback, done_callback) {
535
+ // Subscribe
536
+ if( isNode )
537
+ subscribeNode(this.client, this.subscriptions, channel, callback, done_callback);
538
+ else
539
+ subscribeBrowser(this.client, this.subscriptions, this.backlog, channel, callback, done_callback);
540
+ };
541
+
542
+
543
+ //
544
+ // Helper function that subscribes to a channel in node
545
+ //
546
+ function subscribeNode (client, subscriptions, channel, callback, done_callback) {
547
+ if (subscriptions[channel]===undefined) {
548
+ subscriptions[channel] = [callback];
549
+ client.subscribe(channel, {qos: 0}, function() {
550
+ // If there is a done_callback defined, execute it
551
+ if (done_callback!==undefined) done_callback();
552
+ });
553
+ } else {
554
+ subscriptions[channel].push(callback);
555
+ }
556
+ }
557
+
558
+
559
+ //
560
+ // Helper function that subscribes to a channel in the browser
561
+ //
562
+ function subscribeBrowser (client, subscriptions, backlog, channel, callback, done_callback) {
563
+ if ( addToBacklog(client, backlog, subscribeBrowser, [client, subscriptions, backlog, channel, callback, done_callback]) ) return;
564
+ if (subscriptions[channel]===undefined) {
565
+ subscriptions[channel] = [callback];
566
+ client.subscribe(channel, {qos: 0, onSuccess: function() {
567
+ // If there is a done_callback defined, execute it
568
+ if (done_callback!==undefined) done_callback();
569
+ }});
570
+ } else {
571
+ subscriptions[channel].push(callback);
572
+ // If there is a done_callback defined, execute it
573
+ if (done_callback!==undefined) done_callback();
574
+ }
575
+ }
576
+
577
+
578
+
579
+ /**
580
+ * Unsubscribe from a channel.
581
+ *
582
+ * @param {string} channel - the channel we are un-subscribing from.
583
+ * @param {function} callback - the callback we are trying to de-register
584
+ * @param {callback} [done_callback] - A function that is executed once the unsubscribe operation has completed successfully.
585
+ */
586
+ SimpleMQTTClient.prototype.unsubscribe = function (channel, callback, done_callback) {
587
+ if( isNode )
588
+ unsubscribeNode(this.client, this.subscriptions, channel, callback, done_callback);
589
+ else
590
+ unsubscribeBrowser(this.client, this.subscriptions, this.backlog, channel, callback, done_callback);
591
+ };
592
+
593
+
594
+ //
595
+ // Helper function that unsubscribes from a channel in node
596
+ //
597
+ var unsubscribeNode = function(client, subscriptions, channel, callback, done_callback) {
598
+ if (subscriptions[channel]===undefined)
599
+ return;
600
+ subscriptions[channel].splice(subscriptions[channel].indexOf(callback), 1);
601
+ if (subscriptions[channel].length===0) {
602
+ delete subscriptions[channel];
603
+ client.unsubscribe(channel, function() {
604
+ // If there is a done_callback defined, execute it
605
+ if (done_callback!==undefined) done_callback();
606
+ });
607
+ }
608
+ };
609
+
610
+
611
+ //
612
+ // Helper function that unsubscribes from a channel in the browser
613
+ //
614
+ var unsubscribeBrowser = function(client, subscriptions, backlog, channel, callback, done_callback) {
615
+ if ( addToBacklog(client, backlog, unsubscribeBrowser, [client, subscriptions, backlog, channel, callback, done_callback]) ) return;
616
+ if (subscriptions[channel]===undefined)
617
+ return;
618
+ subscriptions[channel].splice(subscriptions[channel].indexOf(callback), 1);
619
+ if (subscriptions[channel].length===0) {
620
+ delete subscriptions[channel];
621
+ client.unsubscribe(channel, {onSuccess : function() {
622
+ // If there is a done_callback defined, execute it
623
+ if (done_callback!==undefined) done_callback();
624
+ }});
625
+ }
626
+ };
627
+
628
+
629
+ /**
630
+ * Lists all the channels we are currently subscribed to.
631
+ *
632
+ * @returns {Array} a lists of all the channels we are currently subscribed to.
633
+ */
634
+ SimpleMQTTClient.prototype.getSubscriptions = function () {
635
+ return Object.keys(this.subscriptions);
636
+ };
637
+
638
+
639
+ /**
640
+ * Publishes a message to a channel.
641
+ *
642
+ * @param {string} channel - the channel we are publishing to.
643
+ * @param {string} message - the message we are publishing.
644
+ */
645
+ SimpleMQTTClient.prototype.publish = function (channel, message) {
646
+ if (isNode)
647
+ publishNode(this.client, channel, message);
648
+ else
649
+ publishBrowser(this.client, this.backlog, channel, message)
650
+ };
651
+
652
+
653
+ //
654
+ // Helper function that publishes to a channel in node
655
+ //
656
+ var publishNode = function (client, channel, message) {
657
+ client.publish(channel, message);
658
+ };
659
+
660
+
661
+ //
662
+ // Helper function that publishes to a channel in the browser
663
+ //
664
+ var publishBrowser = function (client, backlog, channel, message) {
665
+ if ( addToBacklog(client, backlog, publishBrowser, [client, backlog, channel, message]) ) return;
666
+ message = new mqtt_lib.Message(message);
667
+ message.destinationName = channel;
668
+ client.send(message);
669
+ };
670
+
671
+
672
+ //
673
+ // Helper functions for Simple MQTT client
674
+ //
675
+
676
+
677
+ //
678
+ // Helper function that generates a random client ID
679
+ //
680
+ function generateRandomClientId () {
681
+ var length = 22;
682
+ var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
683
+ var result = '';
684
+ for (var i = length; i > 0; --i) {
685
+ result += chars[Math.round(Math.random() * (chars.length - 1))];
686
+ }
687
+ return result;
688
+ };
689
+
690
+
691
+ //
692
+ // Helper function that selects the right callback when a message is received
693
+ //
694
+ function findCallbacks (subscriptions, channel) {
695
+ // First try to see if a callback for the exact channel exists
696
+ if(Object.keys(subscriptions).indexOf(channel)!==-1)
697
+ return subscriptions[channel];
698
+ // If it doesn't then let's try to see if the channel matches a wildcard callback
699
+ var pattern = matchesWildcard(subscriptions, channel);
700
+ if (pattern!== undefined) {
701
+ return subscriptions[pattern];
702
+ }
703
+ // If there's no exact match or wildcard we have to return undefined
704
+ return undefined;
705
+ };
706
+
707
+
708
+ //
709
+ // Helper function that tries to match a channel with each subscription
710
+ // it returns undefined if no match is found
711
+ //
712
+ function matchesWildcard (subscriptions, channel) {
713
+ var i;
714
+ var subs = Object.keys(subscriptions);
715
+ for (i=0; i < subs.length; i++) {
716
+ if (matchesFilter(subs[i], channel)) {
717
+ return subs[i];
718
+ }
719
+ }
720
+ return undefined;
721
+ };
722
+
723
+
724
+ //
725
+ // Helper function that checks a certain channel and see if it matches a wildcard pattern
726
+ // Returns true if the channel matches a pattern (including the exact pattern)
727
+ //
728
+ function matchesFilter (pattern, channel) {
729
+ // If multi-level wildcard is the only character in pattern, then any string will match
730
+ if (pattern==="#") {
731
+ return true;
732
+ }
733
+ // Handle all other multi-level wildcards
734
+ // FROM SPEC: The number sign (‘#’ U+0023) is a wildcard character that matches any number of levels within a topic. The multi-level wildcard represents the parent and any number of child levels. The multi-level wildcard character MUST be specified either on its own or following a topic level separator. In either case it MUST be the last character specified in the Topic Filter
735
+ var p_wo_wildcard = pattern.substring(0, pattern.length-2);
736
+ var str_wo_details = channel.substring(0, pattern.length-2);
737
+ if (pattern.slice(-1)=='#' && p_wo_wildcard==str_wo_details) {
738
+ return true;
739
+ }
740
+ // TODO Handle single-level wildcards (+)
741
+ // FROM SPEC: The single-level wildcard can be used at any level in the Topic Filter, including first and last levels. Where it is used it MUST occupy an entire level of the filter [MQTT-4.7.1-3]. It can be used at more than one level in the Topic Filter and can be used in conjunction with the multilevel wildcard.
742
+ // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718107
743
+ return false;
744
+ };
745
+
746
+
747
+ //
748
+ // Helper method that queues operations into the backlog.
749
+ // This method is used to make `connect` "synchronous" by
750
+ // queueing up operations on the client until it is connected.
751
+ //
752
+ // @param {string} method - the method that needs to be added to the backlog
753
+ // @param {Array} parameters - parameters to the method being added to the backlog
754
+ // @returns {boolean} true if the method was successfully added, false otherwise
755
+ //
756
+ function addToBacklog (client, backlog, method, parameters) {
757
+ if (!client.isConnected() ) {
758
+ backlog.push({
759
+ op : method,
760
+ params : parameters
761
+ });
762
+ return true;
763
+ }
764
+ return false;
765
+ };
766
+
767
+
768
+
769
+
770
+ //
771
+ // End of methods definition for SimpleMQTTClient
772
+ //
773
+
774
+
775
+ // Export the nutella object
776
+ // For node.js, also with backwards-compatibility for the old `require()` API.
777
+ // If we're in the browser, add `NUTELLA` as a global object.
778
+ if (typeof exports !== 'undefined') {
779
+ if (typeof module !== 'undefined' && module.exports) {
780
+ exports = module.exports = nutella;
781
+ }
782
+ exports.NUTELLA = nutella;
783
+ } else {
784
+ root.NUTELLA = nutella;
785
+ }
786
+
787
+
788
+
789
+ }.call(this));