mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Completed server load-balancing support
This commit is contained in:
parent
1031eca853
commit
453383f851
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -26,7 +26,7 @@ function createMeshCore(agent) {
|
|||||||
var lastNetworkInfo = null;
|
var lastNetworkInfo = null;
|
||||||
var lastPublicLocationInfo = null;
|
var lastPublicLocationInfo = null;
|
||||||
var selfInfoUpdateTimer = null;
|
var selfInfoUpdateTimer = null;
|
||||||
obj.useNativePipes = (process.platform == 'win32');
|
obj.useNativePipes = true; //(process.platform == 'win32');
|
||||||
|
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
@ -158,7 +158,7 @@ function createMeshCore(agent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Replace a string with a number if the string is an exact number
|
// Replace a string with a number if the string is an exact number
|
||||||
function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) == x)) { x = parseInt(x); } return x; }
|
function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
|
||||||
|
|
||||||
// Convert decimal to hex
|
// Convert decimal to hex
|
||||||
function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
|
function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
|
||||||
@ -218,16 +218,48 @@ function createMeshCore(agent) {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parge a URL string into an options object
|
// Get server target url with a custom path
|
||||||
function parseUrl(url) {
|
function getServerTargetUrl(path) {
|
||||||
var x = url.split('/');
|
var x = mesh.ServerUrl;
|
||||||
if (x.length < 4) return null;
|
//sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
|
||||||
var y = x[2].split(':');
|
if (x == null) { return null; }
|
||||||
var options = {};
|
if (path == null) { path = ''; }
|
||||||
var options = { protocol: x[0], hostname: y[0], path: '/' + x.splice(3).join('/') };
|
x = http.parseUri(x);
|
||||||
if (y.length == 1) { options.port = ((x[0] == 'https:') || (x[0] == 'wss:')) ? 443 : 80; } else { options.port = parseInt(y[1]); }
|
if (x == null) return null;
|
||||||
if (isNaN(options.port) == true) return null;
|
return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
|
||||||
return options;
|
}
|
||||||
|
|
||||||
|
// Get server url. If the url starts with "*/..." change it, it not use the url as is.
|
||||||
|
function getServerTargetUrlEx(url) {
|
||||||
|
if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a wake-on-lan packet
|
||||||
|
function sendWakeOnLan(hexMac) {
|
||||||
|
var count = 0;
|
||||||
|
try {
|
||||||
|
var interfaces = require('os').networkInterfaces();
|
||||||
|
var magic = 'FFFFFFFFFFFF';
|
||||||
|
for (var x = 1; x <= 16; ++x) { magic += hexMac; }
|
||||||
|
var magicbin = Buffer.from(magic, 'hex');
|
||||||
|
|
||||||
|
for (var adapter in interfaces) {
|
||||||
|
if (interfaces.hasOwnProperty(adapter)) {
|
||||||
|
for (var i = 0; i < interfaces[adapter].length; ++i) {
|
||||||
|
var addr = interfaces[adapter][i];
|
||||||
|
if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
|
||||||
|
var socket = require('dgram').createSocket({ type: "udp4" });
|
||||||
|
socket.bind({ address: addr.address });
|
||||||
|
socket.setBroadcast(true);
|
||||||
|
socket.send(magicbin, 7, "255.255.255.255");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a mesh agent command
|
// Handle a mesh agent command
|
||||||
@ -245,21 +277,26 @@ function createMeshCore(agent) {
|
|||||||
else if (data.type == 'tunnel') { // Process a new tunnel connection request
|
else if (data.type == 'tunnel') { // Process a new tunnel connection request
|
||||||
if (data.value && data.sessionid) {
|
if (data.value && data.sessionid) {
|
||||||
// Create a new tunnel object
|
// Create a new tunnel object
|
||||||
var tunnel = http.request(parseUrl(data.value));
|
//sendConsoleText(data.value);
|
||||||
tunnel.upgrade = onTunnelUpgrade;
|
var xurl = getServerTargetUrlEx(data.value);
|
||||||
tunnel.sessionid = data.sessionid;
|
//sendConsoleText(xurl);
|
||||||
tunnel.rights = data.rights;
|
if (xurl != null) {
|
||||||
tunnel.state = 0;
|
var tunnel = http.request(http.parseUri(xurl));
|
||||||
tunnel.url = data.value;
|
tunnel.upgrade = onTunnelUpgrade;
|
||||||
tunnel.protocol = 0;
|
tunnel.sessionid = data.sessionid;
|
||||||
|
tunnel.rights = data.rights;
|
||||||
|
tunnel.state = 0;
|
||||||
|
tunnel.url = xurl;
|
||||||
|
tunnel.protocol = 0;
|
||||||
|
|
||||||
// Put the tunnel in the tunnels list
|
// Put the tunnel in the tunnels list
|
||||||
var index = 1;
|
var index = 1;
|
||||||
while (tunnels[index]) { index++; }
|
while (tunnels[index]) { index++; }
|
||||||
tunnel.index = index;
|
tunnel.index = index;
|
||||||
tunnels[index] = tunnel;
|
tunnels[index] = tunnel;
|
||||||
|
|
||||||
sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
|
sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -267,7 +304,7 @@ function createMeshCore(agent) {
|
|||||||
case 'wakeonlan': {
|
case 'wakeonlan': {
|
||||||
// Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
|
// Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
|
||||||
sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', '));
|
sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', '));
|
||||||
// TODO!!!!
|
for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'poweraction': {
|
case 'poweraction': {
|
||||||
@ -554,7 +591,7 @@ function createMeshCore(agent) {
|
|||||||
var response = null;
|
var response = null;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'help': { // Displays available commands
|
case 'help': { // Displays available commands
|
||||||
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power.';
|
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'notify': { // Send a notification message to the mesh
|
case 'notify': { // Send a notification message to the mesh
|
||||||
@ -569,7 +606,7 @@ function createMeshCore(agent) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'info': { // Return information about the agent and agent core module
|
case 'info': { // Return information about the agent and agent core module
|
||||||
response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.';
|
response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'selfinfo': { // Return self information block
|
case 'selfinfo': { // Return self information block
|
||||||
@ -628,10 +665,6 @@ function createMeshCore(agent) {
|
|||||||
response = 'Database compacted: ' + r;
|
response = 'Database compacted: ' + r;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'parseurl': {
|
|
||||||
response = objToString(parseUrl(args['_'][0]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'httpget': {
|
case 'httpget': {
|
||||||
if (consoleHttpRequest != null) {
|
if (consoleHttpRequest != null) {
|
||||||
response = 'HTTP operation already in progress.';
|
response = 'HTTP operation already in progress.';
|
||||||
@ -639,7 +672,7 @@ function createMeshCore(agent) {
|
|||||||
if (args['_'].length != 1) {
|
if (args['_'].length != 1) {
|
||||||
response = 'Proper usage: httpget (url)';
|
response = 'Proper usage: httpget (url)';
|
||||||
} else {
|
} else {
|
||||||
var options = parseUrl(args['_'][0]);
|
var options = http.parseUri(args['_'][0]);
|
||||||
options.method = 'GET';
|
options.method = 'GET';
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
response = 'Invalid url.';
|
response = 'Invalid url.';
|
||||||
@ -648,7 +681,7 @@ function createMeshCore(agent) {
|
|||||||
consoleHttpRequest.sessionid = sessionid;
|
consoleHttpRequest.sessionid = sessionid;
|
||||||
if (consoleHttpRequest != null) {
|
if (consoleHttpRequest != null) {
|
||||||
consoleHttpRequest.end();
|
consoleHttpRequest.end();
|
||||||
response = 'HTTPGET ' + options.protocol + '//' + options.hostname + ':' + options.port + options.path;
|
response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,7 +703,7 @@ function createMeshCore(agent) {
|
|||||||
} else {
|
} else {
|
||||||
var httprequest = null;
|
var httprequest = null;
|
||||||
try {
|
try {
|
||||||
httprequest = http.request(parseUrl(args['_'][0]));
|
httprequest = http.request(http.parseUri(args['_'][0]));
|
||||||
} catch (e) { response = 'Invalid HTTP websocket request'; }
|
} catch (e) { response = 'Invalid HTTP websocket request'; }
|
||||||
if (httprequest != null) {
|
if (httprequest != null) {
|
||||||
httprequest.upgrade = onWebSocketUpgrade;
|
httprequest.upgrade = onWebSocketUpgrade;
|
||||||
@ -756,7 +789,18 @@ function createMeshCore(agent) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'netinfo': { // Show network interface information
|
case 'netinfo': { // Show network interface information
|
||||||
response = objToString(mesh.NetInfo, 0, '.');
|
//response = objToString(mesh.NetInfo, 0, '.');
|
||||||
|
var interfaces = require('os').networkInterfaces();
|
||||||
|
response = objToString(interfaces, 0, '.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'wakeonlan': { // Send wake-on-lan
|
||||||
|
if ((args['_'].length != 1) || (args['_'][0].length != 12)) {
|
||||||
|
response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".';
|
||||||
|
} else {
|
||||||
|
var count = sendWakeOnLan(args['_'][0]);
|
||||||
|
response = 'Sent wake-on-lan on ' + count + ' interface(s).';
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'sendall': { // Send a message to all consoles on this mesh
|
case 'sendall': { // Send a message to all consoles on this mesh
|
||||||
@ -782,6 +826,10 @@ function createMeshCore(agent) {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'parseuri': {
|
||||||
|
response = JSON.stringify(http.parseUri(args['_'][0]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: { // This is an unknown command, return an error message
|
default: { // This is an unknown command, return an error message
|
||||||
response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
|
response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
|
||||||
break;
|
break;
|
||||||
|
@ -378,9 +378,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
|
delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
|
||||||
ws.send(JSON.stringify(command));
|
ws.send(JSON.stringify(command));
|
||||||
} else if (obj.parent.parent.multiServer != null) {
|
} else if (obj.parent.parent.multiServer != null) {
|
||||||
// We need to send this message to other servers
|
// See if we can send this to a peer server
|
||||||
command.fromNodeid = obj.dbNodeKey;
|
var serverid = obj.parent.wsPeerSessions2[command.sessionid];
|
||||||
obj.parent.parent.multiServer.DispatchMessage(command);
|
if (serverid != null) {
|
||||||
|
command.fromNodeid = obj.dbNodeKey;
|
||||||
|
obj.parent.parent.multiServer.DispatchMessageSingleServer(command, serverid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (command.userid != null) { // If this command has a userid, that is the target.
|
} else if (command.userid != null) { // If this command has a userid, that is the target.
|
||||||
|
@ -2017,3 +2017,60 @@ Error: not opened
|
|||||||
at Receiver.opcodes.2.finish (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:633:12)
|
at Receiver.opcodes.2.finish (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:633:12)
|
||||||
|
|
||||||
|
|
||||||
|
-------- 9/20/2017, 11:40:47 AM --------
|
||||||
|
|
||||||
|
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522
|
||||||
|
obj.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
|
||||||
|
^
|
||||||
|
|
||||||
|
TypeError: Cannot set property 'AmtMachine7' of undefined
|
||||||
|
at Object.obj.ProcessPeerServerMessage (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522:51)
|
||||||
|
at processServerData (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:377:32)
|
||||||
|
at WebSocket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:262:49)
|
||||||
|
at emitTwo (events.js:106:13)
|
||||||
|
at WebSocket.emit (events.js:191:7)
|
||||||
|
at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10)
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18
|
||||||
|
at Receiver.applyExtensions (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:371:5)
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:508:14
|
||||||
|
at Receiver.flush (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:347:3)
|
||||||
|
|
||||||
|
|
||||||
|
-------- 9/20/2017, 11:40:51 AM --------
|
||||||
|
|
||||||
|
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522
|
||||||
|
obj.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
|
||||||
|
^
|
||||||
|
|
||||||
|
TypeError: Cannot set property 'AmtMachine7' of undefined
|
||||||
|
at Object.obj.ProcessPeerServerMessage (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522:51)
|
||||||
|
at processServerData (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:377:32)
|
||||||
|
at WebSocket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:262:49)
|
||||||
|
at emitTwo (events.js:106:13)
|
||||||
|
at WebSocket.emit (events.js:191:7)
|
||||||
|
at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10)
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18
|
||||||
|
at Receiver.applyExtensions (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:371:5)
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:508:14
|
||||||
|
at Receiver.flush (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:347:3)
|
||||||
|
|
||||||
|
|
||||||
|
-------- 9/20/2017, 1:55:44 PM --------
|
||||||
|
|
||||||
|
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1155
|
||||||
|
for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
|
||||||
|
^
|
||||||
|
|
||||||
|
TypeError: Cannot read property 'domainid' of undefined
|
||||||
|
at WebSocket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1155:89)
|
||||||
|
at emitTwo (events.js:106:13)
|
||||||
|
at WebSocket.emit (events.js:191:7)
|
||||||
|
at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10)
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:368:7
|
||||||
|
at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\PerMessageDeflate.js:249:5
|
||||||
|
at afterWrite (_stream_writable.js:360:3)
|
||||||
|
at onwrite (_stream_writable.js:351:7)
|
||||||
|
at WritableState.onwrite (_stream_writable.js:89:5)
|
||||||
|
|
||||||
|
|
||||||
|
@ -472,17 +472,29 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
obj.SetupPeerServer = function (server, peerServerId) {
|
obj.SetupPeerServer = function (server, peerServerId) {
|
||||||
console.log('Connected to peer server ' + peerServerId + '.');
|
console.log('Connected to peer server ' + peerServerId + '.');
|
||||||
obj.peerServers[peerServerId] = server;
|
obj.peerServers[peerServerId] = server;
|
||||||
|
|
||||||
|
// Send the list of connections to the peer
|
||||||
server.send(JSON.stringify({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] }));
|
server.send(JSON.stringify({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] }));
|
||||||
|
|
||||||
|
// Send a list of user sessions to the peer
|
||||||
|
server.send(JSON.stringify({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We disconnected to a peer server, clean up everything
|
// We disconnected to a peer server, clean up everything
|
||||||
obj.ClearPeerServer = function (server, peerServerId) {
|
obj.ClearPeerServer = function (server, peerServerId) {
|
||||||
console.log('Disconnected from peer server ' + peerServerId + '.');
|
console.log('Disconnected from peer server ' + peerServerId + '.');
|
||||||
|
|
||||||
|
// Clean up the connectivity state
|
||||||
delete obj.peerServers[peerServerId];
|
delete obj.peerServers[peerServerId];
|
||||||
//delete obj.parent.peerConnectivityByMesh[peerServerId]; // TODO: We will need to re-adjust all of the node power states.
|
|
||||||
var oldList = obj.parent.peerConnectivityByNode[peerServerId];
|
var oldList = obj.parent.peerConnectivityByNode[peerServerId];
|
||||||
obj.parent.peerConnectivityByNode[peerServerId] = {};
|
obj.parent.peerConnectivityByNode[peerServerId] = {};
|
||||||
obj.parent.UpdateConnectivityState(oldList);
|
obj.parent.UpdateConnectivityState(oldList);
|
||||||
|
|
||||||
|
// Clean up the sessions list
|
||||||
|
for (var i in obj.parent.webserver.wsPeerSessions[peerServerId]) { delete obj.parent.webserver.wsPeerSessions2[obj.parent.webserver.wsPeerSessions[peerServerId][i]]; }
|
||||||
|
delete obj.parent.webserver.wsPeerSessions[peerServerId];
|
||||||
|
delete obj.parent.webserver.wsPeerSessions3[peerServerId];
|
||||||
|
obj.parent.webserver.recountSessions(); // Recount all sessions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process a message coming from a peer server
|
// Process a message coming from a peer server
|
||||||
@ -498,6 +510,43 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
obj.parent.UpdateConnectivityState(msg.connectivityTable);
|
obj.parent.UpdateConnectivityState(msg.connectivityTable);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'sessionsTable': {
|
||||||
|
obj.parent.webserver.wsPeerSessions[peerServerId] = msg.sessionsTable;
|
||||||
|
var userToSession = {};
|
||||||
|
for (var i in msg.sessionsTable) {
|
||||||
|
var sessionid = msg.sessionsTable[i];
|
||||||
|
obj.parent.webserver.wsPeerSessions2[sessionid] = peerServerId;
|
||||||
|
var userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion
|
||||||
|
if (userToSession[userid] == null) { userToSession[userid] = [sessionid]; } else { userToSession[userid].push(sessionid); } // UserId -> [ SessionId ]
|
||||||
|
}
|
||||||
|
obj.parent.webserver.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
|
||||||
|
obj.parent.webserver.recountSessions(); // Recount all sessions
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'sessionStart': {
|
||||||
|
obj.parent.webserver.wsPeerSessions[peerServerId].push(msg.sessionid);
|
||||||
|
obj.parent.webserver.wsPeerSessions2[msg.sessionid] = peerServerId;
|
||||||
|
var userid = msg.sessionid.split('/').slice(0, 3).join('/');
|
||||||
|
if (obj.parent.webserver.wsPeerSessions3[peerServerId] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId] = {}; }
|
||||||
|
if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId][userid] = [ msg.sessionid ]; } else { obj.parent.webserver.wsPeerSessions3[peerServerId][userid].push(msg.sessionid); }
|
||||||
|
obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'sessionEnd': {
|
||||||
|
var i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid);
|
||||||
|
if (i >= 0) { obj.parent.webserver.wsPeerSessions[peerServerId].splice(i, 1); }
|
||||||
|
delete obj.parent.webserver.wsPeerSessions2[msg.sessionid];
|
||||||
|
var userid = msg.sessionid.split('/').slice(0, 3).join('/');
|
||||||
|
if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] != null) {
|
||||||
|
i = obj.parent.webserver.wsPeerSessions3[peerServerId][userid].indexOf(msg.sessionid);
|
||||||
|
if (i >= 0) {
|
||||||
|
obj.parent.webserver.wsPeerSessions3[peerServerId][userid].splice(i, 1);
|
||||||
|
if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid].length == 0) { delete obj.parent.webserver.wsPeerSessions3[peerServerId][userid]; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'SetConnectivityState': {
|
case 'SetConnectivityState': {
|
||||||
obj.parent.SetConnectivityState(msg.meshid, msg.nodeid, msg.connectTime, msg.connectType, msg.powerState, peerServerId);
|
obj.parent.SetConnectivityState(msg.meshid, msg.nodeid, msg.connectTime, msg.connectType, msg.powerState, peerServerId);
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.0.7-y",
|
"version": "0.0.8-b",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
@ -24,7 +24,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
|||||||
|
|
||||||
obj.Start = function (nodeid) {
|
obj.Start = function (nodeid) {
|
||||||
var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?id=" + obj.tunnelid;
|
var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?id=" + obj.tunnelid;
|
||||||
if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; }
|
//if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; }
|
||||||
obj.nodeid = nodeid;
|
obj.nodeid = nodeid;
|
||||||
obj.connectstate = 0;
|
obj.connectstate = 0;
|
||||||
obj.socket = new WebSocket(url);
|
obj.socket = new WebSocket(url);
|
||||||
@ -33,7 +33,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
|||||||
obj.socket.onerror = function (e) { console.error(e); }
|
obj.socket.onerror = function (e) { console.error(e); }
|
||||||
obj.socket.onclose = obj.xxOnSocketClosed;
|
obj.socket.onclose = obj.xxOnSocketClosed;
|
||||||
obj.xxStateChange(1);
|
obj.xxStateChange(1);
|
||||||
obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
|
//obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
|
||||||
|
obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*/meshrelay.ashx?id=" + obj.tunnelid });
|
||||||
//obj.debug("Agent Redir Start: " + url);
|
//obj.debug("Agent Redir Start: " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
if ('{{loginmode}}' != '') { go({{loginmode}}); } else { go(1); }
|
if ('{{loginmode}}' != '') { go({{loginmode}}); } else { go(1); }
|
||||||
QV('newAccountDiv', '{{{newAccount}}}' != '0' );
|
QV('newAccountDiv', '{{{newAccount}}}' != '0' );
|
||||||
if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
|
if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
|
||||||
QV("anewaccountpass", (newAccountPass == 1));
|
QV("newAccountPass", (newAccountPass == 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPassHint() {
|
function showPassHint() {
|
||||||
|
115
webserver.js
115
webserver.js
@ -74,10 +74,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
|||||||
|
|
||||||
// Main lists
|
// Main lists
|
||||||
obj.wsagents = {};
|
obj.wsagents = {};
|
||||||
obj.wssessions = {}; // UserId --> Array Of Sessions
|
obj.wssessions = {}; // UserId --> Array Of Sessions
|
||||||
obj.wssessions2 = {}; // UserId + SessionId --> Session
|
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
||||||
obj.wsrelays = {}; // Id -> Relay
|
obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
|
||||||
obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
|
obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
|
||||||
|
obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
|
||||||
|
obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
|
||||||
|
obj.wsrelays = {}; // Id -> Relay
|
||||||
|
obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
|
||||||
|
|
||||||
// Setup randoms
|
// Setup randoms
|
||||||
obj.crypto.randomBytes(32, function (err, buf) { obj.httpAuthRandom = buf; });
|
obj.crypto.randomBytes(32, function (err, buf) { obj.httpAuthRandom = buf; });
|
||||||
@ -383,7 +387,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
|||||||
res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.certificates.CommonName, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass });
|
res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.certificates.CommonName, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass });
|
||||||
} else {
|
} else {
|
||||||
// Send back the login application
|
// Send back the login application
|
||||||
res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, newAccountPass: ((domain.newAccountsPass == null)?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
|
res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, newAccountPass: (((domain.newAccountsPass == null) || (domain.newAccountsPass == ''))?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,8 +945,15 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
|||||||
ws.sessionId = user._id + '/' + ('' + Math.random()).substring(2);
|
ws.sessionId = user._id + '/' + ('' + Math.random()).substring(2);
|
||||||
obj.wssessions2[ws.sessionId] = ws;
|
obj.wssessions2[ws.sessionId] = ws;
|
||||||
if (!obj.wssessions[user._id]) { obj.wssessions[user._id] = [ws]; } else { obj.wssessions[user._id].push(ws); }
|
if (!obj.wssessions[user._id]) { obj.wssessions[user._id] = [ws]; } else { obj.wssessions[user._id].push(ws); }
|
||||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[user._id].length, nolog: 1, domain: domain.id })
|
if (obj.parent.multiServer == null) {
|
||||||
|
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[user._id].length, nolog: 1, domain: domain.id })
|
||||||
|
} else {
|
||||||
|
obj.recountSessions(ws.sessionId); // Recount sessions
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have peer servers, inform them of the new session
|
||||||
|
if (obj.parent.multiServer != null) { obj.parent.multiServer.DispatchMessage({ action: 'sessionStart', sessionid: ws.sessionId }); }
|
||||||
|
|
||||||
// Handle events
|
// Handle events
|
||||||
ws.HandleEvent = function (source, event) {
|
ws.HandleEvent = function (source, event) {
|
||||||
if (!event.domain || event.domain == domain.id) {
|
if (!event.domain || event.domain == domain.id) {
|
||||||
@ -1136,11 +1147,17 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
|||||||
}
|
}
|
||||||
case 'wssessioncount':
|
case 'wssessioncount':
|
||||||
{
|
{
|
||||||
// Request a list of all web socket session count
|
// Request a list of all web socket user session count
|
||||||
if ((user.siteadmin & 2) == 0) break;
|
|
||||||
var wssessions = {};
|
var wssessions = {};
|
||||||
for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
|
if ((user.siteadmin & 2) == 0) break;
|
||||||
ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions }));
|
if (obj.parent.multiServer == null) {
|
||||||
|
// No peering, use simple session counting
|
||||||
|
for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
|
||||||
|
} else {
|
||||||
|
// We have peer servers, use more complex session counting
|
||||||
|
for (var userid in obj.sessionsCount) { if (userid.split('/')[1] == domain.id) { wssessions[userid] = obj.sessionsCount[userid]; } }
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions })); // wssessions is: userid --> count
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'deleteuser':
|
case 'deleteuser':
|
||||||
@ -1664,10 +1681,19 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
|||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
obj.wssessions[ws.userid].splice(i, 1);
|
obj.wssessions[ws.userid].splice(i, 1);
|
||||||
var user = obj.users[ws.userid];
|
var user = obj.users[ws.userid];
|
||||||
if (user) { obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[ws.userid].length, nolog: 1, domain: domain.id }) }
|
if (user) {
|
||||||
|
if (obj.parent.multiServer == null) {
|
||||||
|
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[ws.userid].length, nolog: 1, domain: domain.id })
|
||||||
|
} else {
|
||||||
|
obj.recountSessions(ws.sessionId); // Recount sessions
|
||||||
|
}
|
||||||
|
}
|
||||||
if (obj.wssessions[ws.userid].length == 0) { delete obj.wssessions[ws.userid]; }
|
if (obj.wssessions[ws.userid].length == 0) { delete obj.wssessions[ws.userid]; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have peer servers, inform them of the disconnected session
|
||||||
|
if (obj.parent.multiServer != null) { obj.parent.multiServer.DispatchMessage({ action: 'sessionEnd', sessionid: ws.sessionId }); }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send user information to web socket, this is the first thing we send
|
// Send user information to web socket, this is the first thing we send
|
||||||
@ -2126,5 +2152,70 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
|||||||
// Start server on a free port
|
// Start server on a free port
|
||||||
CheckListenPort(obj.args.port, StartWebServer);
|
CheckListenPort(obj.args.port, StartWebServer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
obj.wssessions = {}; // UserId --> Array Of Sessions
|
||||||
|
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
||||||
|
obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
|
||||||
|
obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
|
||||||
|
obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Count sessions and event any changes
|
||||||
|
obj.recountSessions = function (changedSessionId) {
|
||||||
|
if (changedSessionId == null) {
|
||||||
|
// Recount all sessions
|
||||||
|
|
||||||
|
// Calculate the session count for all userid's
|
||||||
|
var newSessionsCount = {};
|
||||||
|
for (var userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; }
|
||||||
|
for (var serverid in obj.wsPeerSessions3) {
|
||||||
|
for (var userid in obj.wsPeerSessions3[serverid]) {
|
||||||
|
var c = obj.wsPeerSessions3[serverid][userid].length;
|
||||||
|
if (newSessionsCount[userid] == null) { newSessionsCount[userid] = c; } else { newSessionsCount[userid] += c; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See what session counts have changed, event any changes
|
||||||
|
for (var userid in newSessionsCount) {
|
||||||
|
var newcount = newSessionsCount[userid];
|
||||||
|
var oldcount = obj.sessionsCount[userid];
|
||||||
|
if (oldcount == null) { oldcount = 0; } else { delete obj.sessionsCount[userid]; }
|
||||||
|
if (newcount != oldcount) {
|
||||||
|
var x = userid.split('/');
|
||||||
|
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are any counts left in the old counts, event to zero
|
||||||
|
for (var userid in obj.sessionsCount) {
|
||||||
|
var oldcount = obj.sessionsCount[userid];
|
||||||
|
if ((oldcount != null) && (oldcount != 0)) {
|
||||||
|
var x = userid.split('/');
|
||||||
|
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the new session counts
|
||||||
|
obj.sessionsCount = newSessionsCount;
|
||||||
|
} else {
|
||||||
|
// Figure out the userid
|
||||||
|
var userid = changedSessionId.split('/').slice(0, 3).join('/');
|
||||||
|
|
||||||
|
// Recount only changedSessionId
|
||||||
|
var newcount = 0;
|
||||||
|
if (obj.wssessions[userid] != null) { newcount = obj.wssessions[userid].length; }
|
||||||
|
for (var serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } }
|
||||||
|
var oldcount = obj.sessionsCount[userid];
|
||||||
|
if (oldcount == null) { oldcount = 0; }
|
||||||
|
|
||||||
|
// If the count changed, update and event
|
||||||
|
if (newcount != oldcount) {
|
||||||
|
var x = userid.split('/');
|
||||||
|
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
|
||||||
|
obj.sessionsCount[userid] = newcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user