alexa-monit – Rev 1

Subversion Repositories:
Rev:
#!/usr/bin/env nodejs
 ///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2018 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////

const request = require('request');
const mqtt = require('mqtt')
const YAML = require('yamljs');
const winston = require('winston');
const urljoin = require('url-join');
const fs = require('fs');
const jsonDiff = require('json-diff')

// Load configuration file.
const config = YAML.load('config.yml');

// Set up logger.
const logger = winston.createLogger({
    level: 'info',
    format: winston.format.json(),
    transports: [
        new winston.transports.File({
            filename: config.log
        })
    ]
});

if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

// Create cookie jar.
const cookieJar = request.jar();

// Connect to MQTT
const mqttClient = mqtt.connect(config.mqtt.url);

function main() {
    return new Promise((resolve, reject) => {
        request({
                method: 'GET',
                url: urljoin(config.mmonit.url, '/index.csp'),
                jar: cookieJar
            },
            (error, response, body) => {
                if (error) {
                    reject(error);
                    return;
                }
                resolve(error);
            });
    });
}

function authenticate() {
    return new Promise((resolve, reject) => {
        request.post({
                url: urljoin(config.mmonit.url, '/z_security_check'),
                jar: cookieJar,
                form: {
                    'z_username': config.mmonit.username,
                    'z_password': config.mmonit.password,
                    'z_csrf_protection': 'off'
                }
            },
            (error, response, body) => {
                if (error) {
                    reject(error);
                    return;
                }
                resolve(error);
            });
    });
}

function getHostStatusList() {
    return new Promise((resolve, reject) => {
        request({
                method: 'GET',
                url: urljoin(config.mmonit.url, '/status/hosts/list'),
                jar: cookieJar
            },
            (error, response, body) => {
                if (error) {
                    reject(error);
                    return;
                }
                resolve(body);
            });
    });
}

function writeState(state, file) {
    // Store the state.
    var data = JSON.stringify(state);

    return new Promise(function (resolve, reject) {
        fs.writeFile(file, data, function (error) {
            if (error) {
                reject(error);
                return;
            }
            resolve();
        });
    });
}

function readState(file) {
    // Store the state.
    return new Promise(function (resolve, reject) {
        fs.readFile(file, 'utf8', function (error, data) {
            if (error) {
                reject(error);
                return;
            }
            resolve(JSON.parse(data));
        })
    });
}

function retrieveData() {
    main().then((error) => {
        if (error) {
            logger.error('Could not reach main page.');
            return;
        }

        logger.info('Got cookie.');

        authenticate().then((error) => {
            if (error) {
                logger.error('Could not authenticate.');
                return;
            }

            logger.info('Authentication successful.');

            getHostStatusList().then((data) => {
                if (error) {
                    logger.error('Could not get status list.');
                    return;
                }

                logger.info('Retrieved status list.');
                var stateNew = JSON.parse(data);

                fs.access(config.stateFile, fs.constants.F_OK, function (error) {
                    // State file does not exist, so write the data file and terminate.
                    if (error) {
                        logger.warn('State file not found, writing state.');
                        writeState(stateNew, config.stateFile).then(function () {
                            logger.info("Data stored.");
                        }, function (error) {
                            logger.error("Unable to store data: " + error);
                        });
                        return;
                    }

                    readState(config.stateFile).then(function (stateOld) {
                        logger.info("Comparing data.");

                        // stateOld, stateNew
                        stateOld.records.forEach(function (oldRecord) {
                            var hostname = oldRecord.hostname;
                            var id = oldRecord.id;

                            var newRecord = stateNew.records.find(function (record) {
                                return record.id === id;
                            });

                            var diff = jsonDiff.diff(oldRecord, newRecord);
                            if (typeof diff === undefined || diff == null) {
                                // No difference found so continue.
                                return;
                            }

                            // Filter out the "status" component.
                            if (typeof diff.status === undefined ||
                                diff.status == null) {
                                return;
                            }

                            // Build message out of hostname and new status change.
                            var message = hostname + " " + diff.status.__new;
                            logger.info(message);

                            mqttClient.publish(config.mqtt.topic, message, {}, function(error) {
                                if(error) {
                                    logger.error("Unable to publish MQTT message: " + error);
                                    return;
                                }

                                logger.info("Status change pushed to MQTT.");
                            });
                        });

                        // Save the retrieved data.
                        writeState(stateNew, config.stateFile).then(function () {
                            logger.info("Data stored.");
                        }, function (error) {
                            logger.error("Unable to store data: " + error);
                        });

                    }, function(error) {
                        logger.error("Unable to read state: " + error);
                    });
                });
            })
        })
    });
}

setInterval(retrieveData, config.interval);

Generated by GNU Enscript 1.6.5.90.