Shinobi/libs/connectToManagementServer/utils.js

264 lines
11 KiB
JavaScript

const { Worker } = require('worker_threads')
module.exports = (s,config,lang) => {
const { getConnectionDetails } = require('./libs/connectDetails.js')(s,config,lang)
const { modifyConfiguration, getConfiguration } = require('../system/utils.js')(config)
const sshDisabled = config.noCentralSsh === true;
const queuedSshRestart = {}
if(!s.connectedMgmtServers)s.connectedMgmtServers = {}
function parseNewConnectionAddress(serverIp){
let parsedIp = `${serverIp}`
if(parsedIp.indexOf('://') === -1)parsedIp = `ws://${parsedIp}`
if(parsedIp.split(':').length === 2)parsedIp = `ws://${parsedIp}:8663`
return parsedIp;
}
function getManagementServers(){
const response = { ok: true }
response.mgmtServers = config.mgmtServers || {};
return response
}
async function setManagementServers(mgmtServers){
const response = { ok: true }
config = Object.assign(config,{ mgmtServers })
const currentConfig = await getConfiguration()
currentConfig.mgmtServer = mgmtServers;
const configError = await modifyConfiguration(currentConfig)
if(configError){
response.ok = false;
response.err = configError
s.systemLog(configError)
}
return response
}
async function addManagementServer(serverIp, p2pKey){
const response = { ok: true }
const parsedIp = parseNewConnectionAddress(serverIp)
const currentConfig = await getConfiguration();
if(!currentConfig.mgmtServers)currentConfig.mgmtServers = {};
currentConfig.mgmtServers[serverIp] = p2pKey;
config = Object.assign(config, { mgmtServers: currentConfig.mgmtServers })
const configError = await modifyConfiguration(currentConfig)
if(configError){
response.ok = false;
response.err = configError
s.systemLog(configError)
}
return response
}
async function removeManagementServer(serverIp, p2pKey){
const response = { ok: true }
let foundMatching = false;
const currentConfig = await getConfiguration();
if(!currentConfig.mgmtServers)currentConfig.mgmtServers = {};
const currentPeerConnectKey = currentConfig.mgmtServers[serverIp];
if(currentPeerConnectKey === p2pKey){
foundMatching = true
delete(currentConfig.mgmtServers[serverIp])
config = Object.assign(config, { mgmtServers: currentConfig.mgmtServers })
const configError = await modifyConfiguration(currentConfig)
if(configError){
response.ok = false;
response.err = configError
s.systemLog(configError)
}
}else{
response.ok = false;
response.msg = 'Peer Connect Key not matching! Cannot disconnect.';
}
return response
}
function terminateSshToManagement(serverIp){
if(s.connectedMgmtServers[serverIp]){
s.connectedMgmtServers[serverIp].sshWorker.terminate()
delete(s.connectedMgmtServers[serverIp].sshWorker)
}
}
async function queueToggleSshToManagement(serverIp, p2pKey, onlyClose){
if(sshDisabled)return;
clearTimeout(queuedSshRestart[serverIp])
queuedSshRestart[serverIp] = setTimeout(() => {
delete(queuedSshRestart[serverIp])
if(onlyClose){
terminateSshToManagement(serverIp)
}else{
provideSshToManagement(serverIp, p2pKey)
}
},1000 * 60)
}
async function provideSshToManagement(serverIp, p2pKey){
if(sshDisabled)return;
if(queuedSshRestart[serverIp]){
clearTimeout(queuedSshRestart[serverIp]);
return s.connectedMgmtServers[serverIp].sshWorker
}
const configFromFile = await getConfiguration()
const wsServerParts = serverIp.split(':')
wsServerParts[serverIp.includes('://') ? 2 : 1] = configFromFile.sshSocketPort || 9021
const wsServer = wsServerParts.join(':')
console.log('Central SSH Connector Starting...', wsServer)
const worker = new Worker(`${__dirname}/libs/centralConnect/ssh.js`, {
workerData: {
config: configFromFile,
wsServer: wsServer,
peerConnectKey: p2pKey,
}
});
worker.on('message', async (data) => {
switch(data.f){
case'restart':
s.systemLog('Restarting SSH Connection...', serverIp)
worker.terminate()
break;
}
});
worker.on('error', (err) => {
console.error('cameraPeer SSH Error', serverIp, err)
});
worker.on('exit', (code) => {
if(!s.connectedMgmtServers[serverIp].wantTerminate){
console.log('cameraPeer SSH Exited, Restarting...', serverIp, code)
s.connectedMgmtServers[serverIp].sshWorker = provideSshToManagement(serverIp, p2pKey)
}else{
console.log('cameraPeer SSH Exited, NOT Restarting...', serverIp, code)
}
});
return worker
}
async function connectToManagementServer(serverIp, p2pKey){
if(!config.userHasSubscribed){
return console.log(lang.centralManagementNotEnabled)
}
if(s.connectedMgmtServers[serverIp]){
disconnectFromManagmentServer(serverIp)
}
s.connectedMgmtServers[serverIp] = {}
const configFromFile = await getConfiguration()
configFromFile.timezone = config.timezone;
console.log('Central Worker Starting...', serverIp)
const worker = new Worker(`${__dirname}/libs/centralConnect/index.js`, {
workerData: {
config: configFromFile,
serverIp,
p2pKey,
}
});
worker.on('message', async (data) => {
switch(data.f){
case'authenticated':
const sshWorker = await provideSshToManagement(serverIp, p2pKey)
s.connectedMgmtServers[serverIp].sshWorker = sshWorker;
break;
case'connectDetailsRequest':
getConnectionDetails().then((connectDetails) => {
worker.postMessage({ f: 'connectDetails', connectDetails })
}).catch((error) => {
console.error('FAILED TO GET connectDetails', serverIp, error)
worker.postMessage({ f: 'connectDetails', connectDetails: {} })
})
break;
case'modifyConfiguration':
console.log('Editing Configuration...', serverIp, data.data.form)
const configFromFile = await getConfiguration()
const mgmtServers = JSON.stringify(configFromFile.mgmtServers)
const newConfig = data.data.form;
const mgmtServersFromNewConfig = JSON.stringify(configFromFile.mgmtServers)
if(mgmtServers !== mgmtServersFromNewConfig){
resetAllManagementServers()
}
modifyConfiguration(newConfig)
break;
case'restart':
s.systemLog('Restarting Central Connection...', serverIp)
worker.terminate()
break;
}
});
worker.on('error', (err) => {
console.error('cameraPeer Error', serverIp, err)
});
worker.on('exit', (code) => {
console.log('cameraPeer Exited, Restarting...', serverIp, code)
if(!s.connectedMgmtServers[serverIp].wantTerminate)connectToManagementServer(serverIp, p2pKey)
});
s.connectedMgmtServers[serverIp].worker = worker;
s.connectedMgmtServers[serverIp].wantTerminate = false;
}
function disconnectFromManagmentServer(serverIp){
const mgmtConnection = s.connectedMgmtServers[serverIp];
try{
if(!mgmtConnection)return;
mgmtConnection.wantTerminate = true;
mgmtConnection.worker.terminate();
}catch(err){
s.debugLog('disconnectFromManagmentServer ERR',err)
}
try{
terminateSshToManagement(serverIp);
}catch(err){
s.debugLog('disconnectFromManagmentSshServer ERR',err)
}
}
function resetConnectionToManagementServer(serverIp){
const mgmtConnection = s.connectedMgmtServers[serverIp];
if(!mgmtConnection)return;
mgmtConnection.wantTerminate = false;
mgmtConnection.worker.terminate();
try{
terminateSshToManagement(serverIp);
}catch(err){
s.debugLog('resetConnectionToManagementSshServer ERR',err)
}
}
function resetAllManagementServers(){
for(serverIp in s.connectedMgmtServers){
disconnectFromManagmentServer(serverIp)
}
connectAllManagementServers()
}
async function connectAllManagementServers(){
const configFromFile = await getConfiguration()
const mgmtServers = configFromFile.mgmtServers
if(mgmtServers){
for(serverIp in mgmtServers){
var p2pKey = mgmtServers[serverIp]
await connectToManagementServer(serverIp, p2pKey)
}
}else{
console.log(`Management Server Connection Not Configured!`)
}
}
async function migrateOldConfiguration(){
await addManagementServer(config.managementServer, config.peerConnectKey)
await connectToManagementServer(config.managementServer, config.peerConnectKey)
const configFromFile = await getConfiguration()
delete(configFromFile.managementServer)
delete(configFromFile.peerConnectKey)
modifyConfiguration(configFromFile)
}
async function sendMessageToAllConnectedServers(data){
for(let serverIp in s.connectedMgmtServers){
try{
s.connectedMgmtServers[serverIp].worker.postMessage(data)
}catch(err){
s.debugLog(err.toString())
}
}
}
if(config.autoRestartManagementConnectionInterval){
setInterval(() => {
resetAllManagementServers()
}, 1000 * 60 * 15)
}
return {
getManagementServers,
addManagementServer,
removeManagementServer,
connectToManagementServer,
disconnectFromManagmentServer,
resetConnectionToManagementServer,
resetAllManagementServers,
connectAllManagementServers,
migrateOldConfiguration,
sendMessageToAllConnectedServers,
}
}