var Database = require('../../../models/database'); var manifest = require('./manifest.json'); const { createWinstonLogger } = require('../../../utils/logging'); const Basedata = require('../../../models/basedata'); const Feedbackstates = require('../../../models/feedbackstates'); const Feedbackstore = require('../../../models/core/feedbackstore'); const Operations = require('../../../models/operationshelper'); const Groups = require('../../../models/groups'); // axios session const axios = require('axios').default; const { CookieJar } = require('tough-cookie'); const { wrapper } = require('axios-cookiejar-support'); const jar = new CookieJar(); const client = wrapper(axios.create({ jar })); global.manifest = manifest; global.apiAdress = null; var serviceState = 0; var config = null; var pulled_data = {}; const AUTH_ENDPOINT = "https://app.divera247.com/monitor/" const PULL_ENDPOINT = "https://app.divera247.com/api/pull" async function getFeedbackStateIDbyName(name){ return new Promise((resolve, reject) => { var feedbackstates = new Feedbackstates(global.logger); feedbackstates.getAllActiveStates((rows)=>{ if(rows !== null){ rows.forEach((e)=>{ if(name == e.stateLabel){ resolve(e.id) } }) } resolve(null) }) }); } function setFeedback(operationUUID, basedataUUID, feedbackState) { var feedbackstore = new Feedbackstore(global.logger); global.logger.debug('DIVERA_STATUS | FEEDBACK | ' + Math.floor(new Date().getTime()) + ' setFeedback | persisting feedback now ..'); feedbackstore.setFeedback(basedataUUID, operationUUID, feedbackState, (success) => { if (success) { global.logger.debug('DIVERA_STATUS | FEEDBACK | ' + Math.floor(new Date().getTime()) + ' setFeedback | successfully persisted feedback'); var feedbackInfo = { basedataUUID: basedataUUID, operationUUID: operationUUID, feedbackState: feedbackState } var sendMessage = { feedbackState : feedbackInfo } process.send(JSON.stringify(sendMessage)); } else { global.logger.debug('DIVERA_STATUS | FEEDBACK | ' + Math.floor(new Date().getTime()) + ' setFeedback | ERROR - Could not persist feedback'); } }) } async function getMemberByName(firstname,lastname){ return new Promise((resolve, reject) => { new Basedata(global.logger).getListOfBasedata((rows)=>{ if(rows !== null){ rows.forEach((e)=> { if(e.firstname == firstname && e.lastname == lastname){ resolve(e.uuid) } }) } resolve(null) }) }); } async function setGroupsMutedStateForMember(member_guid, muted = false){ var b= new Basedata(global.logger) b.getBaseDataForUUID(member_guid,(_rows)=> { if(_rows !== null){ _rows.forEach((_e)=>{ var g = new Groups(global.logger) g.setAllGroupsMutedStateForBasedata(_e.id,muted?1:0,(success)=>{}) }) } }) } async function getActiveOperation(){ return new Promise((resolve, reject) => { new Operations(global.logger).getListOfActiveOperations((rows)=>{ if(rows !== null && rows.length > 0){ resolve(rows[0].uuid) } resolve(null) }) }); } /** * Log Function for inter process communication */ function LogAtMain(msg) { process.send('{"logmessage" : "' + msg + '"}'); } /** * * Wire messages coming from Plugin base.js * */ process.on('message', (msg) => { if (typeof msg.config != 'undefined') { config = msg.config; global.apiAdress = config.apiAdress || null; serviceState = 1; LogAtMain('Recieved Configuration from CORE'); } else if (typeof msg.start != 'undefined') { if (msg.start === 1) { startAPI(); } } }); // GENERIC Error Handling process.on('unhandledRejection', (reason, p) => { console.log('PLUGIN | DIVERA_STATUS | Unhandled Rejection at: Promise', p, 'reason:', reason.stack); LogAtMain('Unhandled Rejection at: Promise', p, 'reason:', reason.stack); }); process.on('uncaughtException', function (err) { console.log('PLUGIN | DIVERA_STATUS | Caught exception: ' + err); process.send('{"error" : "' + err.message + '"}'); }); /** * Start API Logger */ // create a rolling file logger based on date/time that fires process events global.appRoot = __dirname + '/../../../'; global.logger = createWinstonLogger('DIVERA_STATUS ', global.appRoot + '/logs/api/DIVERA_STATUS-%DATE%.log'); global.logger.info('Started DIVERA_STATUS Sync', {label: 'APPJS '}); /** * connect to database */ var coreDb = new Database(global.logger); coreDb.openCoreDatabase((successDatabase) => { if (successDatabase) { global.coreDb = coreDb.db; global.logger.info('database started', {label: 'APPJS '}); } else { global.logger.error('Could not connect to database', {label: 'APPJS '}); } }); /** * authenticate Divera Monitor with Autologin Key * @returns boolean */ async function auth(){ let resp = await client.get(`${AUTH_ENDPOINT}${config.MONITOR_ID}.html?autologin=${config.AUTOLOGIN_KEY}`) if(resp.status === 200){ return true } return false } /** * Get Data from Divera pull Endpoint. With ts=0 all data is pulled. * If ?ts={timestamp}, data changed since this timestamp is pulled. * We just pull all data. * * The Divera Monitor App also connects to a websocket connection where changes are pushed. * Maybe this is a better idea to pull data in the future than pulling in a while loop * * @returns {dict|null} */ async function pull(){ let resp = await client.get(`${PULL_ENDPOINT}?ts=0`) if(resp.status === 200){ return resp.data } return null } /** * Function handling the state change of an User. * The feedback-status-id is identified by name and basedata(user)-(uu)id is identified by firstname and lastname * So Divera feedback-status/firstname & lastname must be the same as in ALARMiator * * Feedback-state changes are applyed to the lates active operation * * if STATUS_EB/STATUS_NED is set, all groups for this user are muted/unmuted if the name is matching * * @param {Number} consumer_id * @param {Number} status_id */ async function onStateChange(consumer_id, status_id){ var d_consumer = pulled_data['consumer'][consumer_id] var d_status = pulled_data['status'][status_id] global.logger.info(`${d_consumer.stdformat_name.trim()}: ${d_status.name.trim()}`) let a_consumer = await getMemberByName(d_consumer.firstname.trim(), d_consumer.lastname.trim()) if(a_consumer === null){ global.logger.info(`no matching basedata for \'${d_consumer.firstname.trim()}\' \'${d_consumer.lastname.trim()}\'`) return } let a_status = await getFeedbackStateIDbyName(d_status.name.trim()) if(a_status !== null){ // state is feedback to an operation let a_operation = await getActiveOperation() if(a_consumer === null){ global.logger.info(`no active operation running`) return } // set feedback go last operation setFeedback(a_operation, a_consumer, a_status) }else{ // Status auf einsatzbereit/nicht einsatzbereit prüfen if(config.STATUS_EB.trim() == d_status.name.trim()){ //Alle Gruppen alamieren setGroupsMutedStateForMember(a_consumer,false) } if(config.STATUS_NEB.trim() == d_status.name.trim()){ //Alle Gruppen alamieren deaktivieren setGroupsMutedStateForMember(a_consumer,true) } } } function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function startAPI() { while(true){ try{ let _auth = await auth() if(_auth){ global.logger.info('auth OK') var _pulled_data = await pull() while(_pulled_data !== null){ if(_pulled_data !== null){ if(_pulled_data.success){ var d = _pulled_data.data if('cluster' in d){ pulled_data['consumer'] = d['cluster']['consumer'] pulled_data['status'] = d['cluster']['status'] } if('monitor' in d){ var m = d['monitor'][config.MONITOR_ID] Object.entries(m).forEach(([key, value]) => { // wenn 'monitor' nicht in pulled_data ist das der erste pull, dann alle status in ALARMiator abgleichen (betrifft hautsächlich den EB/NEB status) if(!('monitor' in pulled_data) || ('monitor' in pulled_data && value.status !== pulled_data['monitor'][key]['status'])){ onStateChange(value.id,value.status ) } }); pulled_data['monitor'] = d['monitor'][config.MONITOR_ID] } } } _pulled_data = await pull() if(_pulled_data === null){ global.logger.debug('_pulled_data === null, reauth') _auth = await auth() _pulled_data = await pull() if(_pulled_data === null){ global.logger.debug('_pulled_data === null after reauth, EXIT!!') } } } } }catch(err){ console.error(err); } await sleep(10000); global.logger.info('auth mit API_KEY war nicht erfolgreich. Service ist gestoppt und startet nicht mehr automatisch??') } }