mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Bug fixes and fixed database performance problem.
This commit is contained in:
parent
b7df070bd2
commit
b824499b40
47
db.js
47
db.js
@ -41,6 +41,13 @@ module.exports.CreateDB = function (parent) {
|
||||
var dbcollection = 'meshcentral';
|
||||
if (obj.parent.args.mongodbcol) { dbcollection = obj.parent.args.mongodbcol; }
|
||||
obj.file = db.collection(dbcollection);
|
||||
|
||||
// Setup MongoDB indexes
|
||||
obj.file.createIndex({ type: 1, domain: 1, meshid: 1 }, { sparse: 1 }); // Speeds up GetAllTypeNoTypeField() and GetAllTypeNoTypeFieldMeshFiltered()
|
||||
obj.file.createIndex({ email: 1 }, { sparse: 1 }); // Speeds up GetUserWithEmail() and GetUserWithVerifiedEmail()
|
||||
obj.file.createIndex({ ids: 1, time: -1 }, { sparse: 1 }); // Speeds up GetEvents() and GetEventsWithLimit()
|
||||
obj.file.createIndex({ type: 1, node: 1, time: -1 }, { sparse: 1 }); // Speeds up getPowerTimeline()
|
||||
obj.file.createIndex({ mesh: 1 }, { sparse: 1 }); // Speeds up RemoveMesh()
|
||||
} else {
|
||||
// Use NeDB (The default)
|
||||
obj.databaseType = 1;
|
||||
@ -72,6 +79,13 @@ module.exports.CreateDB = function (parent) {
|
||||
// Start NeDB
|
||||
obj.file = new Datastore(datastoreOptions);
|
||||
obj.file.persistence.setAutocompactionInterval(3600);
|
||||
|
||||
// Setup NeDB indexes
|
||||
obj.file.ensureIndex({ fieldName: 'type' });
|
||||
obj.file.ensureIndex({ fieldName: 'domain' });
|
||||
obj.file.ensureIndex({ fieldName: 'meshid' });
|
||||
obj.file.ensureIndex({ fieldName: 'node' });
|
||||
obj.file.ensureIndex({ fieldName: 'email' });
|
||||
}
|
||||
|
||||
obj.SetupDatabase = function (func) {
|
||||
@ -232,27 +246,30 @@ module.exports.CreateDB = function (parent) {
|
||||
} catch (ex) { return null; }
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Get the number of records in the database for various types, this is the slow NeDB way.
|
||||
// WARNING: This is a terrible query for database performance. Only do this when needed. This query will look at almost every document in the database.
|
||||
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: 'smbios' }, function (err, nodeSmbiosCount) {
|
||||
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, smbios: nodeSmbiosCount, total: totalCount });
|
||||
});
|
||||
});
|
||||
});
|
||||
if (obj.databaseType == 2) {
|
||||
// MongoDB version
|
||||
obj.file.aggregate([{ "$group": { _id: "$type", count: { $sum: 1 } } }], function (err, docs) {
|
||||
var counters = {}, totalCount = 0;
|
||||
for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } }
|
||||
func({ nodes: counters['node'], meshes: counters['mesh'], powerEvents: counters['power'], users: counters['user'], total: totalCount });
|
||||
})
|
||||
} else {
|
||||
// NeDB version
|
||||
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({}, function (err, totalCount) {
|
||||
func({ nodes: nodeCount, meshes: meshCount, powerEvents: powerCount, users: userCount, nodeInterfaces: nodeInterfaceCount, notes: noteCount, connectEvent: nodeLastConnectCount, smbios: nodeSmbiosCount, 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.
|
||||
|
91
meshuser.js
91
meshuser.js
@ -178,15 +178,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
|
||||
// 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.2435345, 0.523234234, 0.6435345345 ]; }
|
||||
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, "SMBios": data.smbios } }
|
||||
try { ws.send(JSON.stringify(stats)); } catch (ex) { }
|
||||
});
|
||||
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.2435345, 0.523234234, 0.6435345345 ]; }
|
||||
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 }
|
||||
try { ws.send(JSON.stringify(stats)); } catch (ex) { }
|
||||
}
|
||||
|
||||
// When data is received from the web socket
|
||||
@ -256,7 +254,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
}
|
||||
case 'serverstats':
|
||||
{
|
||||
if ((user.siteadmin) != 0) {
|
||||
if ((user.siteadmin & 21) != 0) { // Only site administrators with "site backup" or "site restore" or "site update" permissions can use this.
|
||||
if (obj.common.validateInt(command.interval, 1000, 1000000) == false) {
|
||||
// Clear the timer
|
||||
if (obj.serverStatsTimer != null) { clearInterval(obj.serverStatsTimer); obj.serverStatsTimer = null; }
|
||||
@ -1438,38 +1436,65 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
}
|
||||
case 'uploadagentcore':
|
||||
{
|
||||
if (user.siteadmin != 0xFFFFFFFF) break;
|
||||
if (obj.common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if (obj.common.validateString(command.type, 1, 40) == false) break; // Check path
|
||||
if (command.type == 'default') {
|
||||
// Send the default core to the agent
|
||||
obj.parent.parent.updateMeshCore(function () { obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'default'); });
|
||||
} else if (command.type == 'clear') {
|
||||
// Clear the mesh agent core on the mesh agent
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'clear');
|
||||
} else if (command.type == 'recovery') {
|
||||
// Send the recovery core to the agent
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'recovery');
|
||||
} else if ((command.type == 'custom') && (obj.common.validateString(command.path, 1, 2048) == true)) {
|
||||
// Send a mesh agent core to the mesh agent
|
||||
var file = obj.parent.getServerFilePath(user, domain, command.path);
|
||||
if (file != null) {
|
||||
obj.parent.parent.fs.readFile(file.fullpath, 'utf8', function (err, data) {
|
||||
if (err != null) {
|
||||
data = obj.common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'custom', data);
|
||||
|
||||
// Change the device
|
||||
obj.db.Get(command.nodeid, function (err, nodes) {
|
||||
if (nodes.length != 1) return;
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
if (mesh.links[user._id] == null || (((mesh.links[user._id].rights & 16) == 0) && (user.siteadmin != 0xFFFFFFFF))) { return; }
|
||||
|
||||
if (command.type == 'default') {
|
||||
// Send the default core to the agent
|
||||
obj.parent.parent.updateMeshCore(function () { obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'default'); });
|
||||
} else if (command.type == 'clear') {
|
||||
// Clear the mesh agent core on the mesh agent
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'clear');
|
||||
} else if (command.type == 'recovery') {
|
||||
// Send the recovery core to the agent
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'recovery');
|
||||
} else if ((command.type == 'custom') && (obj.common.validateString(command.path, 1, 2048) == true)) {
|
||||
// Send a mesh agent core to the mesh agent
|
||||
var file = obj.parent.getServerFilePath(user, domain, command.path);
|
||||
if (file != null) {
|
||||
obj.parent.parent.fs.readFile(file.fullpath, 'utf8', function (err, data) {
|
||||
if (err != null) {
|
||||
data = obj.common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, 'custom', data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'agentdisconnect':
|
||||
{
|
||||
// Force mesh agent disconnection
|
||||
if (obj.common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if (obj.common.validateInt(command.disconnectMode) == false) break; // Check disconnect mode
|
||||
obj.parent.forceMeshAgentDisconnect(user, domain, command.nodeid, command.disconnectMode);
|
||||
if (obj.common.validateInt(command.disconnectMode) == false) return; // Check disconnect mode
|
||||
|
||||
// Change the device
|
||||
obj.db.Get(command.nodeid, function (err, nodes) {
|
||||
if (nodes.length != 1) return;
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
if (mesh.links[user._id] == null || (((mesh.links[user._id].rights & 16) == 0) && (user.siteadmin != 0xFFFFFFFF))) return;
|
||||
|
||||
// Force mesh agent disconnection
|
||||
obj.parent.forceMeshAgentDisconnect(user, domain, command.nodeid, command.disconnectMode);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'close':
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.2.8-m",
|
||||
"version": "0.2.8-o",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
File diff suppressed because one or more lines are too long
@ -3539,7 +3539,7 @@
|
||||
QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
|
||||
QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
|
||||
QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
|
||||
QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0) && (userinfo.siteadmin == 0xFFFFFFFF));
|
||||
QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
|
||||
QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
|
||||
|
||||
// Setup/Refresh Intel AMT tab
|
||||
|
@ -2411,7 +2411,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Check we have agent rights
|
||||
var rights = user.links[agent.dbMeshKey].rights;
|
||||
if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) && (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
|
||||
if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) || (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
|
||||
};
|
||||
|
||||
// Send the core module to the mesh agent
|
||||
@ -2426,7 +2426,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Check we have agent rights
|
||||
var rights = user.links[agent.dbMeshKey].rights;
|
||||
if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) && (user.siteadmin == 0xFFFFFFFF)) {
|
||||
if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) || (user.siteadmin == 0xFFFFFFFF)) {
|
||||
if (coretype == 'clear') {
|
||||
// Clear the mesh agent core
|
||||
agent.agentCoreCheck = 1000; // Tell the agent object we are using a custom core.
|
||||
|
Loading…
Reference in New Issue
Block a user