divera_status/service.js

291 lines
10 KiB
JavaScript

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??')
}
}