Added two-way push messaging support.
Ylian Saint-Hilaire committed
Jan 31, 2021 at 02:44 UTC
2248cb0a6d1e971ceb979f08c92a56ee5efd325d
6 files changed
+104
-32
MeshCentralServer.njsproj
+7
@@ -97,6 +97,7 @@
97
<Compile Include="amt\amt-xml.js" />
98
<Compile Include="amt\amt.js" />
99
<Compile Include="exeHandler.js" />
100
+ <Compile Include="firebase.js" />
101
<Compile Include="letsencrypt.js" />
102
<Compile Include="mcrec.js" />
103
<Compile Include="meshaccelerator.js" />
@@ -618,25 +619,31 @@
619
<Folder Include="translate\" />
620
<Folder Include="typings\" />
621
<Folder Include="typings\globals\" />
622
+ <Folder Include="typings\globals\ajv\" />
623
<Folder Include="typings\globals\connect-redis\" />
624
<Folder Include="typings\globals\cookie-session\" />
625
<Folder Include="typings\globals\express-handlebars\" />
626
<Folder Include="typings\globals\express-session\" />
627
+ <Folder Include="typings\globals\jsbn\" />
628
<Folder Include="typings\globals\node-forge\" />
629
<Folder Include="typings\globals\nodemailer\" />
630
<Folder Include="typings\globals\node\" />
631
<Folder Include="typings\globals\passport\" />
632
+ <Folder Include="typings\globals\uuid\" />
633
<Folder Include="views\" />
634
</ItemGroup>
635
<ItemGroup>
636
+ <TypeScriptCompile Include="typings\globals\ajv\index.d.ts" />
637
<TypeScriptCompile Include="typings\globals\connect-redis\index.d.ts" />
638
<TypeScriptCompile Include="typings\globals\cookie-session\index.d.ts" />
639
<TypeScriptCompile Include="typings\globals\express-handlebars\index.d.ts" />
640
<TypeScriptCompile Include="typings\globals\express-session\index.d.ts" />
641
+ <TypeScriptCompile Include="typings\globals\jsbn\index.d.ts" />
642
<TypeScriptCompile Include="typings\globals\node-forge\index.d.ts" />
643
<TypeScriptCompile Include="typings\globals\nodemailer\index.d.ts" />
644
<TypeScriptCompile Include="typings\globals\node\index.d.ts" />
645
<TypeScriptCompile Include="typings\globals\passport\index.d.ts" />
646
+ <TypeScriptCompile Include="typings\globals\uuid\index.d.ts" />
647
<TypeScriptCompile Include="typings\index.d.ts" />
648
</ItemGroup>
649
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
firebase.js
new
+72
@@ -0,0 +1,72 @@
1
+/**
2
+* @description MeshCentral Firebase communication module
3
+* @author Ylian Saint-Hilaire
4
+* @copyright Intel Corporation 2018-2021
5
+* @license Apache-2.0
6
+* @version v0.0.1
7
+*/
8
+
9
+/*xjslint node: true */
10
+/*xjslint plusplus: true */
11
+/*xjslint maxlen: 256 */
12
+/*jshint node: true */
13
+/*jshint strict: false */
14
+/*jshint esversion: 6 */
15
+"use strict";
16
+
17
+// Construct the Firebase object
18
+module.exports.CreateFirebase = function (parent, senderid, serverkey) {
19
+ var obj = {};
20
+ obj.messageId = 1;
21
+
22
+ const Sender = require('node-xcs').Sender;
23
+ const Message = require('node-xcs').Message;
24
+ const Notification = require('node-xcs').Notification;
25
+ const xcs = new Sender(senderid, serverkey);
26
+
27
+ // Messages received from client (excluding receipts)
28
+ xcs.on('message', function (messageId, from, data, category) {
29
+ console.log('Firebase-Message', messageId, from, data, category);
30
+ });
31
+
32
+ // Only fired for messages where options.delivery_receipt_requested = true
33
+ /*
34
+ xcs.on('receipt', function (messageId, from, data, category) { console.log('Firebase-Receipt', messageId, from, data, category); });
35
+ xcs.on('connected', function () { console.log('Connected'); });
36
+ xcs.on('disconnected', function () { console.log('disconnected'); });
37
+ xcs.on('online', function () { console.log('online'); });
38
+ xcs.on('error', function (e) { console.log('error', e); });
39
+ xcs.on('message-error', function (e) { console.log('message-error', e); });
40
+ */
41
+
42
+ xcs.start();
43
+
44
+ //var payload = { notification: { title: command.title, body: command.msg }, data: { url: obj.msgurl } };
45
+ //var options = { priority: 'High', timeToLive: 5 * 60 }; // TTL: 5 minutes, priority 'Normal' or 'High'
46
+
47
+ // Send an outbound push notification
48
+ obj.sendToDevice = function (token, payload, options, func) {
49
+ // Built the on-screen notification
50
+ var notification = null;
51
+ if (payload.notification) {
52
+ var notification = new Notification('ic_launcher')
53
+ .title(payload.notification.title)
54
+ .body(payload.notification.body)
55
+ .build();
56
+ }
57
+
58
+ // Build the message
59
+ var message = new Message('msg_' + (++obj.messageId));
60
+ if (options.priority) { message.priority(options.priority); }
61
+ if (payload.data) { for (var i in payload.data) { message.addData(i, payload.data[i]); } }
62
+ if (notification) { message.notification(notification) }
63
+ message.build();
64
+
65
+ // Send the message
66
+ function callback(result) { callback.func(result.getMessageId(), result.getError(), result.getErrorDescription()) }
67
+ callback.func = func;
68
+ xcs.sendNoRetry(message, token, callback);
69
+ }
70
+
71
+ return obj;
72
+};
\ No newline at end of file
meshcentral.js
+3
-10
@@ -1545,15 +1545,8 @@ function CreateMeshCentralServer(config, args) {
1545
}
1546
1547
// Setup Firebase
1548
- if (config.firebase != null) {
1549
- try {
1550
- obj.firebase = require('firebase-admin');
1551
- var firebaseServiceAccount = require(obj.path.join(obj.datapath, config.firebase.serviceaccountkeyfile));
1552
- obj.firebase.initializeApp({ credential: obj.firebase.credential.cert(firebaseServiceAccount) });
1553
- } catch (ex) {
1554
- console.log('Unable to setup Firebase: ' + ex);
1555
- delete obj.firebase;
1556
- }
1548
+ if ((config.firebase != null) && (typeof config.firebase.senderid == 'string') && (typeof config.firebase.serverkey == 'string')) {
1549
+ obj.firebase = require('./firebase').CreateFirebase(this, config.firebase.senderid, config.firebase.serverkey);
1550
}
1551
1552
// Start periodic maintenance
@@ -3066,7 +3059,7 @@ function mainStart() {
3059
}
3060
3061
// Firebase Support
3069
- if (config.firebase != null) { modules.push('firebase-admin'); }
3062
+ if (config.firebase != null) { modules.push('node-xcs'); }
3063
3064
// Syslog support
3065
if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog'); }
meshrelay.js
+8
-7
@@ -414,11 +414,12 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
414
}
415
}
416
});
417
+ parent.wsrelays[obj.id] = { peer1: obj, state: 1 }; // No timeout on connections with push notification.
418
} else {
419
ws._socket.pause(); // Hold traffic until the other connection
420
parent.parent.debug('relay', 'Relay holding: ' + obj.id + ' (' + obj.req.clientIp + ') ' + (obj.authenticated ? 'Authenticated' : ''));
421
+ parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(closeBothSides, 60000) };
422
}
421
- parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(closeBothSides, 30000) };
423
424
// Check if a peer server has this connection
425
if (parent.parent.multiServer != null) {
@@ -485,15 +486,15 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
486
command.title = (domain.title ? domain.title : 'MeshCentral');
487
var payload = { notification: { title: command.title, body: command.msg }, data: { url: obj.msgurl } };
488
var options = { priority: 'High', timeToLive: 5 * 60 }; // TTL: 5 minutes, priority 'Normal' or 'High'
488
- parent.parent.firebase.messaging().sendToDevice(obj.pmt, payload, options)
489
- .then(function (response) {
489
+ parent.parent.firebase.sendToDevice(obj.pmt, payload, options, function (id, err, errdesc) {
490
+ if (err == null) {
491
parent.parent.debug('email', 'Successfully send push message to device ' + obj.nodename + ', title: ' + command.title + ', msg: ' + command.msg);
492
try { ws.send(JSON.stringify({ action: 'ctrl', value: 1 })); } catch (ex) { } // Push notification success
492
- })
493
- .catch(function (error) {
494
- parent.parent.debug('email', 'Failed to send push message to device ' + obj.nodename + ', title: ' + command.title + ', msg: ' + command.msg + ', error: ' + error);
493
+ } else {
494
+ parent.parent.debug('email', 'Failed to send push message to device ' + obj.nodename + ', title: ' + command.title + ', msg: ' + command.msg + ', error: ' + errdesc);
495
try { ws.send(JSON.stringify({ action: 'ctrl', value: 2 })); } catch (ex) { } // Push notification failed
496
- });
496
+ }
497
+ });
498
}
499
}
500
});
meshuser.js
+13
-13
@@ -5207,13 +5207,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5207
// Send out a push message to the device
5208
var payload = { notification: { title: command.title, body: command.msg } };
5209
var options = { priority: "Normal", timeToLive: 5 * 60 }; // TTL: 5 minutes
5210
- parent.parent.firebase.messaging().sendToDevice(node.pmt, payload, options)
5211
- .then(function (response) {
5210
+ parent.parent.firebase.sendToDevice(node.pmt, payload, options, function (id, err, errdesc) {
5211
+ if (err == null) {
5212
parent.parent.debug('email', 'Successfully send push message to device ' + node.name + ', title: ' + command.title + ', msg: ' + command.msg);
5213
- })
5214
- .catch(function (error) {
5215
- parent.parent.debug('email', 'Failed to send push message to device ' + node.name + ', title: ' + command.title + ', msg: ' + command.msg + ', error: ' + error);
5216
- });
5213
+ } else {
5214
+ parent.parent.debug('email', 'Failed to send push message to device ' + node.name + ', title: ' + command.title + ', msg: ' + command.msg + ', error: ' + errdesc);
5215
+ }
5216
+ });
5217
}
5218
}
5219
});
@@ -5231,14 +5231,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5231
// Send out a push message to the device
5232
var payload = { data: { console: command.console, session: ws.sessionId } };
5233
var options = { priority: "Normal", timeToLive: 60 }; // TTL: 1 minutes, priority 'Normal' or 'High'
5234
- parent.parent.firebase.messaging().sendToDevice(node.pmt, payload, options)
5235
- .then(function (response) {
5234
+ parent.parent.firebase.sendToDevice(node.pmt, payload, options, function (id, err, errdesc) {
5235
+ if (err == null) {
5236
try { ws.send(JSON.stringify({ action: 'msg', type: 'console', nodeid: node._id, value: 'OK' })); } catch (ex) { }
5237
- })
5238
- .catch(function (error) {
5239
- try { ws.send(JSON.stringify({ action: 'msg', type: 'console', nodeid: node._id, value: 'Failed: ' + error })); } catch (ex) { }
5240
- parent.parent.debug('email', 'Failed to send push console message to device ' + node.name + ', command: ' + command.console + ', error: ' + error);
5241
- });
5237
+ } else {
5238
+ try { ws.send(JSON.stringify({ action: 'msg', type: 'console', nodeid: node._id, value: 'Failed: ' + errdesc })); } catch (ex) { }
5239
+ parent.parent.debug('email', 'Failed to send push console message to device ' + node.name + ', command: ' + command.console + ', error: ' + errdesc);
5240
+ }
5241
+ });
5242
}
5243
}
5244
});
package.json
+1
-2
@@ -18,7 +18,7 @@
18
"author": "Ylian Saint-Hilaire <ylianst@gmail.com>",
19
"main": "meshcentral.js",
20
"bin": {
21
- "meshcentral": "./bin/meshcentral"
21
+ "meshcentral": "bin/meshcentral"
22
},
23
"license": "Apache-2.0",
24
"files": [
@@ -53,7 +53,6 @@
53
"xmldom": "^0.1.27",
54
"yauzl": "^2.10.0"
55
},
56
- "devDependencies": {},
56
"repository": {
57
"type": "git",
58
"url": "https://github.com/Ylianst/MeshCentral.git"