mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-23 21:55:52 -05:00
Improved server UI, new Auto-Remote agent feature.
This commit is contained in:
parent
f04752f1cb
commit
dcab344df6
21
db.js
21
db.js
@ -121,6 +121,27 @@ module.exports.CreateDB = function (parent) {
|
||||
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); };
|
||||
obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
|
||||
|
||||
// Get the number of records in the database for various types, this is the slow NeDB way. TODO: MongoDB can use group() to do this faster.
|
||||
obj.getStats = function (func) {
|
||||
obj.file.count({ type: 'node' }, function (err, nodeCount) {
|
||||
obj.file.count({ type: 'mesh' }, function (err, meshCount) {
|
||||
obj.file.count({ type: 'power' }, function (err, powerCount) {
|
||||
obj.file.count({ type: 'user' }, function (err, userCount) {
|
||||
obj.file.count({ type: 'ifinfo' }, function (err, nodeInterfaceCount) {
|
||||
obj.file.count({ type: 'note' }, function (err, noteCount) {
|
||||
obj.file.count({ type: 'lastconnect' }, function (err, nodeLastConnectCount) {
|
||||
obj.file.count({ }, function (err, totalCount) {
|
||||
func({ nodes: nodeCount, meshes: meshCount, powerEvents: powerCount, users: userCount, nodeInterfaces: nodeInterfaceCount, notes: noteCount, connectEvent: nodeLastConnectCount, total: totalCount });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// This is used to rate limit a number of operation per day. Returns a startValue each new days, but you can substract it and save the value in the db.
|
||||
obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if (docs.length == 1) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); };
|
||||
|
||||
|
@ -56,10 +56,14 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
delete obj.parent.wsagents[obj.dbNodeKey];
|
||||
obj.parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
|
||||
}
|
||||
|
||||
// Get the current mesh
|
||||
var mesh = obj.parent.meshes[obj.dbMeshKey];
|
||||
|
||||
// Other clean up may be needed here
|
||||
if (obj.unauth) { delete obj.unauth; }
|
||||
if (obj.agentUpdate != null) { obj.fs.close(obj.agentUpdate.fd); obj.agentUpdate = null; }
|
||||
if ((obj.agentInfo) && (obj.agentInfo.capabilities) && (obj.agentInfo.capabilities & 0x20)) { // This is a temporary agent, remote it
|
||||
if (((obj.agentInfo) && (obj.agentInfo.capabilities) && (obj.agentInfo.capabilities & 0x20)) || ((mesh) && (mesh.flags) && (mesh.flags & 1))) { // This is a temporary agent, remote it
|
||||
// Delete this node including network interface information and events
|
||||
obj.db.Remove(obj.dbNodeKey); // Remove node with that id
|
||||
obj.db.Remove('if' + obj.dbNodeKey); // Remove interface information
|
||||
@ -597,7 +601,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Check if anything changes
|
||||
if (command.name && (command.name != device.name)) { change = 1; device.name = command.name; changes.push('name'); }
|
||||
if (device.agent.core != command.value) { if ((command.value == null) && (device.agent.core != null)) { delete device.agent.core; } else { device.agent.core = command.value; } change = 1; changes.push('agent core'); }
|
||||
if ((command.caps != null) && (device.agent.core != command.value)) { if ((command.value == null) && (device.agent.core != null)) { delete device.agent.core; } else { device.agent.core = command.value; } change = 1; changes.push('agent core'); }
|
||||
if ((command.caps != null) && ((device.agent.caps & 0xFFFFFFE7) != (command.caps & 0xFFFFFFE7))) { device.agent.caps = ((device.agent.caps & 24) + (command.caps & 0xFFFFFFE7)); change = 1; changes.push('agent capabilities'); } // Allow Javascript on the agent to change all capabilities except console and javascript support
|
||||
if ((command.osdesc != null) && (device.osdesc != command.osdesc)) { device.osdesc = command.osdesc; change = 1; changes.push('os desc'); }
|
||||
if (command.intelamt) {
|
||||
|
@ -57,7 +57,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.currentVer = null;
|
||||
obj.serverKey = new Buffer(obj.crypto.randomBytes(32), 'binary');
|
||||
obj.loginCookieEncryptionKey = null;
|
||||
obj.serverSelfWriteAllowed = false;
|
||||
obj.serverSelfWriteAllowed = true;
|
||||
try { obj.currentVer = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } // Fetch server version
|
||||
|
||||
// Setup the default configuration and files paths
|
||||
@ -1096,9 +1096,10 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
var r = 'time=' + Date.now() + '\r\n';
|
||||
for (var i in meshServerState) { r += (i + '=' + meshServerState[i] + '\r\n'); }
|
||||
obj.fs.writeFileSync(obj.getConfigFilePath('serverstate.txt'), r); // Try to write the server state, this may fail if we don't have permission.
|
||||
obj.serverSelfWriteAllowed = true;
|
||||
} catch (ex) { obj.serverSelfWriteAllowed = false; } // Do nothing since this is not a critical feature.
|
||||
try {
|
||||
obj.fs.writeFileSync(obj.getConfigFilePath('serverstate.txt'), r); // Try to write the server state, this may fail if we don't have permission.
|
||||
} catch (ex) { obj.serverSelfWriteAllowed = false; }
|
||||
} catch (ex) { } // Do nothing since this is not a critical feature.
|
||||
};
|
||||
|
||||
// Logging funtions
|
||||
|
42
meshuser.js
42
meshuser.js
@ -24,6 +24,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
obj.common = parent.common;
|
||||
obj.fs = require('fs');
|
||||
obj.path = require('path');
|
||||
obj.serverStatsTimer = null;
|
||||
|
||||
// Send a message to the user
|
||||
//obj.send = function (data) { try { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } } catch (e) { } }
|
||||
@ -122,6 +123,19 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
user.subscriptions = obj.parent.subscribe(user._id, ws); // Subscribe to events
|
||||
obj.ws._socket.setKeepAlive(true, 240000); // Set TCP keep alive
|
||||
|
||||
// Send current server statistics
|
||||
obj.SendServerStats = function () {
|
||||
obj.db.getStats(function (data) {
|
||||
var os = require('os');
|
||||
var stats = { action: 'serverstats', totalmem: os.totalmem(), freemem: os.freemem() };
|
||||
if (obj.parent.parent.platform != 'win32') { stats.cpuavg = os.loadavg(); } //else { stats.cpuavg = [ 0.2, 0.5, 0.6 ]; }
|
||||
var serverStats = { "User Accounts": Object.keys(obj.parent.users).length, "Device Groups": Object.keys(obj.parent.meshes).length, "Connected Agents": Object.keys(obj.parent.wsagents).length, "Connected Users": Object.keys(obj.parent.wssessions2).length };
|
||||
if (obj.parent.parent.mpsserver != null) { serverStats['Connected Intel® AMT'] = Object.keys(obj.parent.parent.mpsserver.ciraConnections).length; }
|
||||
stats.values = { "Server State": serverStats, "Database": { "Records": data.total, "Users": data.users, "Device Groups": data.meshes, "Devices": data.nodes, "Device NetInfo": data.nodeInterfaces, "Device Power Event": data.powerEvents, "Notes": data.notes, "Connection Records": data.connectEvents } }
|
||||
try { ws.send(JSON.stringify(stats)); } catch (ex) { }
|
||||
});
|
||||
}
|
||||
|
||||
// When data is received from the web socket
|
||||
ws.on('message', function (msg) {
|
||||
var command, user = obj.parent.users[req.session.userid], i = 0, mesh = null, meshid = null, nodeid = null, meshlinks = null, change = 0;
|
||||
@ -130,6 +144,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
switch (command.action) {
|
||||
case 'ping': { try { ws.send(JSON.stringify({ action: 'pong' })); } catch (ex) { } break; }
|
||||
case 'serverstats':
|
||||
{
|
||||
if ((user.siteadmin) != 0) {
|
||||
if (obj.common.validateInt(command.interval, 1000, 1000000) == false) {
|
||||
// Clear the timer
|
||||
if (obj.serverStatsTimer != null) { clearInterval(obj.serverStatsTimer); obj.serverStatsTimer = null; }
|
||||
} else {
|
||||
// Set the timer
|
||||
obj.SendServerStats();
|
||||
obj.serverStatsTimer = setInterval(obj.SendServerStats, command.interval);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'meshes':
|
||||
{
|
||||
// Request a list of all meshes this user as rights to
|
||||
@ -683,9 +711,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) return;
|
||||
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
|
||||
if ((obj.common.validateString(command.meshname, 1, 64) == true) && (command.meshname != mesh.name)) { change = 'Mesh name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
|
||||
if ((obj.common.validateString(command.desc, 0, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Mesh "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
|
||||
if (change != '') { obj.db.Set(obj.common.escapeLinksFieldName(mesh)); obj.parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }); }
|
||||
if ((obj.common.validateString(command.meshname, 1, 64) == true) && (command.meshname != mesh.name)) { change = 'Group name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
|
||||
if ((obj.common.validateString(command.desc, 0, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Group "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
|
||||
if ((obj.common.validateInt(command.flags) == true) && (command.flags != mesh.flags)) { if (change != '') change += ' and flags changed'; else change += 'Group "' + mesh.name + '" flags changed'; mesh.flags = command.flags; }
|
||||
if (change != '') { obj.db.Set(obj.common.escapeLinksFieldName(mesh)); obj.parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1180,7 +1209,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.common.validateString(command.notes, 1) == false) {
|
||||
obj.db.Remove('nt' + command.id); // Delete the note for this node
|
||||
} else {
|
||||
obj.db.Set({ _id: 'nt' + command.id, value: command.notes }); // Set the note for this node
|
||||
obj.db.Set({ _id: 'nt' + command.id, type: 'note', value: command.notes }); // Set the note for this node
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1196,7 +1225,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.common.validateString(command.notes, 1) == false) {
|
||||
obj.db.Remove('nt' + command.id); // Delete the note for this node
|
||||
} else {
|
||||
obj.db.Set({ _id: 'nt' + command.id, value: command.notes }); // Set the note for this node
|
||||
obj.db.Set({ _id: 'nt' + command.id, type: 'note', value: command.notes }); // Set the note for this mesh
|
||||
}
|
||||
}
|
||||
} else if ((idtype == 'user') && ((user.siteadmin & 2) != 0)) {
|
||||
@ -1204,7 +1233,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.common.validateString(command.notes, 1) == false) {
|
||||
obj.db.Remove('nt' + command.id); // Delete the note for this node
|
||||
} else {
|
||||
obj.db.Set({ _id: 'nt' + command.id, value: command.notes }); // Set the note for this node
|
||||
obj.db.Set({ _id: 'nt' + command.id, type: 'note', value: command.notes }); // Set the note for this user
|
||||
}
|
||||
}
|
||||
|
||||
@ -1276,6 +1305,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
// If the web socket is closed
|
||||
ws.on('close', function (req) {
|
||||
obj.parent.parent.RemoveAllEventDispatch(ws);
|
||||
if (obj.serverStatsTimer != null) { clearInterval(obj.serverStatsTimer); obj.serverStatsTimer = null; }
|
||||
if (req.session && req.session.ws && req.session.ws == ws) { delete req.session.ws; }
|
||||
if (obj.parent.wssessions2[ws.sessionId]) { delete obj.parent.wssessions2[ws.sessionId]; }
|
||||
if (obj.parent.wssessions[ws.userid]) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.2.1-c",
|
||||
"version": "0.2.1-x",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 55 KiB |
BIN
public/images/server-200.png
Normal file
BIN
public/images/server-200.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
18923
public/scripts/charts.js
Normal file
18923
public/scripts/charts.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -236,6 +236,14 @@ a {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.lb6 {
|
||||
background: url(../images/leftbar-62.png) -360px 0px;
|
||||
height: 62px;
|
||||
width: 62px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.m0 { background : url(../images/images16.png) -32px 0px; height : 16px; width : 16px; border:none; float:left }
|
||||
.m1 { background : url(../images/images16.png) -16px 0px; height : 16px; width : 16px; border:none; float:left }
|
||||
.m2 { background : url(../images/images16.png) -96px 0px; height : 16px; width : 16px; border:none; float:left }
|
||||
|
File diff suppressed because one or more lines are too long
@ -23,6 +23,7 @@
|
||||
<script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0.js"></script>
|
||||
<script type="text/javascript" src="scripts/agent-redir-ws-0.1.0.js"></script>
|
||||
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/charts.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/filesaver.1.1.20151003.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/ol.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/ol3-contextmenu.js"></script>
|
||||
@ -79,6 +80,9 @@
|
||||
<div id=LeftMenuMyUsers class="lbbutton" title="My Users" onclick=go(4)>
|
||||
<div class="lb5" style="position:absolute;top:6px;left:6px"></div>
|
||||
</div>
|
||||
<div id=LeftMenuMyServer class="lbbutton" title="My Server" onclick=go(6) style="display:none">
|
||||
<div class="lb6" style="position:absolute;top:6px;left:6px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="page_content" style="max-height:calc(100vh - 130px)">
|
||||
<div id=topbarmaster>
|
||||
@ -95,6 +99,7 @@
|
||||
<td id=MainMenuMyEvents style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(3)>My Events</td>
|
||||
<td id=MainMenuMyFiles style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(5)>My Files</td>
|
||||
<td id=MainMenuMyUsers style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(4)>My Users</td>
|
||||
<td id=MainMenuMyServer style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(6)>My Server</td>
|
||||
<td class=style3 style="text-align:right;height:24px"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -237,13 +242,6 @@
|
||||
<a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br />
|
||||
</p>
|
||||
</div>
|
||||
<p id="p2ServerActions"><strong>Server actions</strong></p>
|
||||
<p style="margin-left:40px">
|
||||
<a id="p2ServerActionsBackup" href="/backup.zip" target="_blank" style="cursor:pointer">Download server backup</a><br />
|
||||
<a id="p2ServerActionsRestore" onclick="server_showRestoreDlg()" style="cursor:pointer">Restore server with backup</a><br />
|
||||
<a id="p2ServerActionsVersion" onclick="server_showVersionDlg()" style="cursor:pointer">Check server version</a><br />
|
||||
<a id="p2ServerActionsErrors" onclick="server_showErrorsDlg()" style="cursor:pointer">Show server error log</a><br />
|
||||
</p>
|
||||
<br style=clear:both />
|
||||
<strong>Device Groups</strong>
|
||||
( <a onclick=account_createMesh() style=cursor:pointer><img height=12 src="images/icon-addnew.png" width=12 border=0 /> New</a> )
|
||||
@ -342,6 +340,29 @@
|
||||
<tr><td class=style6 style="text-align:left;padding:3px"> <span id="p5bottomstatus"></span></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id=p6 style=display:none>
|
||||
<img id=MainMeshImage src="serverpic.ashx" style=border-width:0px;height:200px;width:200px;float:right>
|
||||
<h1>My Server</h1>
|
||||
<p id="p2ServerActions"><strong>Server actions</strong></p>
|
||||
<p style="margin-left:40px">
|
||||
<a id="p2ServerActionsBackup" href="/backup.zip" target="_blank" style="cursor:pointer">Download server backup</a><br />
|
||||
<a id="p2ServerActionsRestore" onclick="server_showRestoreDlg()" style="cursor:pointer">Restore server with backup</a><br />
|
||||
<a id="p2ServerActionsVersion" onclick="server_showVersionDlg()" style="cursor:pointer">Check server version</a><br />
|
||||
<a id="p2ServerActionsErrors" onclick="server_showErrorsDlg()" style="cursor:pointer">Show server error log</a><br />
|
||||
</p>
|
||||
<br /><strong>Server Statistics</strong><br /><br />
|
||||
<div id="serverStats" style="margin-left:40px">
|
||||
<div id="serverCpuChartView" style="display:none">
|
||||
<div style="width:60px;display:inline-block"><canvas id="serverCpuChart" style="width:60px;height:60px"></canvas></div>
|
||||
<div style="width:160px;display:inline-block" id="serverCpuChartText"></div>
|
||||
</div>
|
||||
<div id="serverMemoryChartView" style="display:none">
|
||||
<div style="width:60px;display:inline-block"><canvas id="serverMemoryChart" style="width:60px;height:60px"></canvas></div>
|
||||
<div style="width:160px;display:inline-block" id="serverMemoryChartText"></div>
|
||||
</div><br /><br />
|
||||
<div id="serverStatsTable"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id=p10 style="display:none">
|
||||
<table style="width:100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
@ -916,6 +937,9 @@
|
||||
var x = '';
|
||||
for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
|
||||
QH('specialkeylist', x);
|
||||
|
||||
// Setup server stats panel
|
||||
setupServerStats();
|
||||
}
|
||||
|
||||
// Toggle the web page to full screen
|
||||
@ -1016,7 +1040,9 @@
|
||||
|
||||
// Update account actions
|
||||
QV('p2AccountActions', (features & 4) == 0); // Hide Account Actions if in single user mode
|
||||
QV('p2ServerActions', siteRights & 5);
|
||||
QV('p2ServerActions', siteRights & 21);
|
||||
QV('LeftMenuMyServer', siteRights & 21);
|
||||
QV('MainMenuMyServer', siteRights & 21);
|
||||
QV('p2ServerActionsBackup', siteRights & 1);
|
||||
QV('p2ServerActionsRestore', siteRights & 4);
|
||||
QV('p2ServerActionsVersion', siteRights & 16);
|
||||
@ -1039,10 +1065,17 @@
|
||||
}
|
||||
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
|
||||
QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
|
||||
|
||||
// If we are site administrator, register to get server statistics
|
||||
if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
|
||||
}
|
||||
|
||||
function onMessage(server, message) {
|
||||
switch (message.action) {
|
||||
case 'serverstats': {
|
||||
updateServerStats(message);
|
||||
break;
|
||||
}
|
||||
case 'serverinfo': {
|
||||
serverinfo = message.serverinfo;
|
||||
break;
|
||||
@ -1116,7 +1149,7 @@
|
||||
if (node != null) {
|
||||
node.lastconnect = message.time;
|
||||
if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '')) {
|
||||
QH('MainComputerState', '<span style=font-size:12px>Last connected:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>');
|
||||
QH('MainComputerState', '<span style=font-size:12px>Last seen:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>');
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1289,6 +1322,7 @@
|
||||
// This is an existing mesh
|
||||
meshes[message.event.meshid].name = message.event.name;
|
||||
meshes[message.event.meshid].desc = message.event.desc;
|
||||
meshes[message.event.meshid].flags = message.event.flags;
|
||||
meshes[message.event.meshid].links = message.event.links;
|
||||
|
||||
// Check if we lost rights to this mesh in this change.
|
||||
@ -3139,7 +3173,7 @@
|
||||
if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Agent connected">Agent connected</span>'; }
|
||||
if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel® AMT connected">Intel® AMT connected</span>'; }
|
||||
if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel® AMT detected">Intel® AMT detected</span>'; }
|
||||
if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>Last connected:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>'; }
|
||||
if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>Last seen:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>'; }
|
||||
QH('MainComputerState', powerstate);
|
||||
|
||||
// Set the node icon
|
||||
@ -4900,9 +4934,19 @@
|
||||
var x = '';
|
||||
x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
|
||||
x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'<i>None</i>'), 'p20editmesh(2)', (meshrights & 1) != 0));
|
||||
x += addHtmlValue('Type', meshtype);
|
||||
x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
|
||||
|
||||
// Display features
|
||||
var meshFeatures = [];
|
||||
if (currentMesh.flags) { if (currentMesh.flags & 1) { meshFeatures.push('Auto-Remove'); } }
|
||||
meshFeatures = meshFeatures.join(', ');
|
||||
if (meshFeatures == '') { meshFeatures = '<i>None</i>'; }
|
||||
x += addHtmlValue('Features', addLinkConditional(meshFeatures, 'p20editmeshfeatures()', (meshrights & 1) != 0));
|
||||
|
||||
// Display group type
|
||||
x += addHtmlValue('Type', meshtype);
|
||||
//x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
|
||||
|
||||
// Display group note support
|
||||
x += '<br><input type=button value=Notes title="View notes about this device group" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
|
||||
|
||||
x += '<br style=clear:both><br>';
|
||||
@ -4996,6 +5040,19 @@
|
||||
QE('idx_dlgOkButton', Q('dp20meshname').value.length > 0);
|
||||
}
|
||||
|
||||
function p20editmeshfeatures() {
|
||||
if (xxdialogMode) return;
|
||||
var flags = (currentMesh.flags)?currentMesh.flags:0;
|
||||
var x = "<div><input type=checkbox id=d20flag1 " + ((flags & 1)?'checked':'') + ">Remove device on disconnect<br></div>";
|
||||
setDialogMode(2, "Edit Device Group Features", 3, p20editmeshfeaturesEx, x);
|
||||
}
|
||||
|
||||
function p20editmeshfeaturesEx() {
|
||||
var flags = 0;
|
||||
if (Q('d20flag1').checked) { flags += 1; }
|
||||
meshserver.send({ action: 'editmesh', meshid: currentMesh._id, flags: flags });
|
||||
}
|
||||
|
||||
function p20showAddMeshUserDialog() {
|
||||
if (xxdialogMode) return;
|
||||
var x = "Allow a user to manage this device group and devices in this group<br /><br />";
|
||||
@ -5171,6 +5228,14 @@
|
||||
return Math.round(bytes / 1024 / 1024 / 1024) + ' gigabytes remaining';
|
||||
}
|
||||
|
||||
function getNiceSize2(bytes) {
|
||||
if (bytes <= 0) return 'None';
|
||||
if (bytes < 2048) return bytes + ' b';
|
||||
if (bytes < 2097152) return Math.round(bytes / 1024) + ' Kb';
|
||||
if (bytes < 2147483648) return Math.round(bytes / 1024 / 1024) + ' Mb';
|
||||
return Math.round(bytes / 1024 / 1024 / 1024) + ' Gb';
|
||||
}
|
||||
|
||||
function p5getQuotabar(f) {
|
||||
while (f.t > 1 && f.t != 4) { f = f.parent; }
|
||||
if ((f.t != 1 && f.t != 4) || (f.maxbytes == null)) return '';
|
||||
@ -5950,6 +6015,60 @@
|
||||
QV('notifiyBox', false);
|
||||
}
|
||||
|
||||
//
|
||||
// Server Statistics
|
||||
//
|
||||
|
||||
function setupServerStats() {
|
||||
window.serverStatCpu = new Chart(document.getElementById('serverCpuChart').getContext('2d'), {
|
||||
type: 'doughnut',
|
||||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
|
||||
options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
|
||||
});
|
||||
window.serverStatMemory = new Chart(document.getElementById('serverMemoryChart').getContext('2d'), {
|
||||
type: 'doughnut',
|
||||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
|
||||
options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
|
||||
});
|
||||
}
|
||||
|
||||
var lastServerStats = null;
|
||||
function updateServerStats(message) {
|
||||
if (message != null) { lastServerStats = message; } else { message = lastServerStats; }
|
||||
if (message == null) return;
|
||||
|
||||
// Paint the pie graphs
|
||||
if (typeof message.cpuavg == 'object') {
|
||||
var m = Math.min(message.cpuavg[0], 1);
|
||||
window.serverStatCpu.config.data.datasets[0].data = [m, 1 - m];
|
||||
QH('serverCpuChartText', '<div style=margin-bottom:5px>CPU Load</div><div><b title="CPU load in the last minute">' + message.cpuavg[0] + '</b>%, <b title="CPU load in the last 5 minutes">' + message.cpuavg[1] + '</b>%, <b title="CPU load in the 15 minutes">' + message.cpuavg[2] + '</b>%</div>');
|
||||
QS('serverCpuChartView')['display'] = 'inline-block';
|
||||
window.serverStatCpu.update();
|
||||
}
|
||||
if ((typeof message.totalmem == 'number') && (typeof message.freemem == 'number')) {
|
||||
window.serverStatMemory.config.data.datasets[0].data = [message.totalmem - message.freemem, message.freemem];
|
||||
QH('serverMemoryChartText', '<div style=margin-bottom:5px>Memory</div><div><b>' + getNiceSize2(message.freemem) + '</b> free, <b>' + getNiceSize2(message.totalmem) + '</b> total</div>');
|
||||
QS('serverMemoryChartView')['display'] = 'inline-block';
|
||||
window.serverStatMemory.update();
|
||||
}
|
||||
|
||||
// Display all of the server values
|
||||
var x = '<div style=width:100% cellpadding=0 cellspacing=0>';
|
||||
if (typeof message.values == 'object') {
|
||||
for (var i in message.values) {
|
||||
x += '<div class=userTableHeader style=margin-bottom:4px;width:200px>' + i + '</div>';
|
||||
for (var j in message.values[i]) {
|
||||
x += '<div style=width:300px;display:inline-block><div class=bar style=height:24px;width:100%;font-size:medium>';
|
||||
x += '<div class=g1 style=height:24px;float:left></div><div class=g2 style=height:24px;float:right></div>';
|
||||
x += '<div><span>' + j + '</span><span style=float:right>' + message.values[i][j] + '</span></div></div></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
x += '</div>';
|
||||
|
||||
QH('serverStatsTable', x);
|
||||
}
|
||||
|
||||
//
|
||||
// POPUP DIALOG
|
||||
//
|
||||
@ -5998,7 +6117,7 @@
|
||||
xxcurrentView = x;
|
||||
|
||||
// Remove left bar selection
|
||||
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers'];
|
||||
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers', 'LeftMenuMyServer'];
|
||||
for (var i in leftBarItems) { Q(leftBarItems[i]).classList.remove('lbbuttonsel'); Q(leftBarItems[i]).classList.remove('lbbuttonsel2'); }
|
||||
|
||||
// My Devices
|
||||
@ -6025,6 +6144,10 @@
|
||||
QS('MainMenuMyFiles').backgroundColor = ((x == 5) ? "#003366" : "#808080");
|
||||
if (x == 5) { Q('LeftMenuMyFiles').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||||
|
||||
// My Server
|
||||
QS('MainMenuMyServer').backgroundColor = ((x == 6) ? "#003366" : "#808080");
|
||||
if (x == 6) { Q('LeftMenuMyServer').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||||
|
||||
// column_l max-height
|
||||
if (webPageFullScreen) {
|
||||
QS('column_l')["max-height"] = 'calc(100vh - 135px)';
|
||||
@ -6059,7 +6182,8 @@
|
||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||||
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||||
function addLink(x, f) { return "<a style=cursor:pointer;color:darkblue;text-decoration:none onclick='" + f + "'>♦ " + x + "</a>"; }
|
||||
//function addLink(x, f) { return "<a style=cursor:pointer;color:darkblue;text-decoration:none onclick='" + f + "'>♦ " + x + "</a>"; }
|
||||
function addLink(x, f) { return "<span style=cursor:pointer;text-decoration:none onclick='" + f + "'>" + x + " <img class=hoverButton src=images/link5.png></span>"; }
|
||||
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
||||
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||
function addOption(q, t, i) { var option = document.createElement("option"); option.text = t; option.value = i; Q(q).add(option); }
|
||||
|
16
webserver.js
16
webserver.js
@ -717,6 +717,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Give the web page a list of supported server features
|
||||
features = 0;
|
||||
user = obj.users[req.session.userid];
|
||||
if (obj.args.wanonly == true) { features += 1; } // WAN-only mode
|
||||
if (obj.args.lanonly == true) { features += 2; } // LAN-only mode
|
||||
if (obj.args.nousers == true) { features += 4; } // Single user mode
|
||||
@ -728,7 +729,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (obj.args.clickonce !== false) { features += 256; } // Enable ClickOnce (Default true)
|
||||
if (obj.args.allowhighqualitydesktop == true) { features += 512; } // Enable AllowHighQualityDesktop (Default false)
|
||||
if (obj.args.lanonly == true || obj.args.mpsport == 0) { features += 1024; } // No CIRA
|
||||
if ((obj.serverSelfWriteAllowed == true) && (user.siteadmin == 0xFFFFFFFF)) { features += 2048; } // Server can self-write (Allows self-update)
|
||||
if ((obj.parent.serverSelfWriteAllowed == true) && (user != null) && (user.siteadmin == 0xFFFFFFFF)) { features += 2048; } // Server can self-write (Allows self-update)
|
||||
|
||||
// Send the master web application
|
||||
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||
@ -1813,6 +1814,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.app.ws(url + 'echo.ashx', handleEchoWebSocket);
|
||||
obj.app.ws(url + 'meshrelay.ashx', function (ws, req) { try { obj.meshRelayHandler.CreateMeshRelay(obj, ws, req, getDomain(req)); } catch (e) { console.log(e); } });
|
||||
|
||||
// Server picture
|
||||
obj.app.get(url + 'serverpic.ashx', function (req, res) {
|
||||
// Check if we have "server.png" in the data folder, if so, use that.
|
||||
var p = obj.path.join(obj.parent.datapath, 'server.png');
|
||||
if (obj.fs.existsSync(p)) {
|
||||
// Use the data folder server picture
|
||||
try { res.sendFile(p); } catch (e) { res.sendStatus(404); }
|
||||
} else {
|
||||
// Use the default server picture
|
||||
try { res.sendFile(obj.path.join(__dirname, 'public/images/server-200.png')); } catch (e) { res.sendStatus(404); }
|
||||
}
|
||||
});
|
||||
|
||||
// Receive mesh agent connections
|
||||
obj.app.ws(url + 'agent.ashx', function (ws, req) {
|
||||
//console.log(++obj.agentConnCount);
|
||||
|
Loading…
Reference in New Issue
Block a user