Source: component/watchdog.js

/*! meta-admin/modules/watchdog */
/*jslint
    browser, long
*/
/*global
    Blob, BroadcastChannel
*/
import Logger from "js-logger";
import ko from "knockout";
import objects from "meta-client/modules/objects";
import model from "meta-core/modules/model";
import protocol from "meta-core/modules/protocol";
import _ from "underscore";
import dates from "util-web/modules/dates";
import ext from "util-web/modules/ext";
import i18next from "util-web/modules/i18next";
import nav from "util-web/modules/nav";
import ui from "util-web/modules/ui";
import template from "./watchdog.html";

const LOG = Logger.get("meta-admin/watchdog");

/**
 * watchdog component.
 *
 * @module meta-admin/modules/component/watchdog
 */
export default Object.freeze({
    template,
    viewModel: {
        createViewModel: function ({viewmodel}) {
            const getInfoJson = function (info) {
                if (_.isEmpty(info) === false) {
                    if (0 === info.indexOf("{")) {
                        return JSON.parse(info);
                    }
                    return info;
                }
            };
            const getVersion = function (info) {
                if (_.isEmpty(info) === false) {
                    if (0 === info.indexOf("{")) { // New JSON info
                        return JSON.parse(info).rt.version;
                    }
                    if (info.includes(",")) { // Old string info
                        return info.substring(0, info.indexOf(","));
                    }
                }
            };
            const notificationChannel = new BroadcastChannel("meta-admin");
            const vm = {};

            vm.viewmodel = viewmodel;

            vm.activeServerUpdate = ko.observable();
            vm.serverInfo = ko.observable();
            vm.errorReply = ko.observable();
            vm.isUpdating = ko.observable(false);
            vm.updateFileKey = ko.observable();
            vm.updateSchedule = ko.observable();
            const updateScheduleSub = dates.insertDateTimes({fromDateObservable: vm.updateSchedule});

            vm.activateServerInfo = function (status) {
                vm.serverInfo(JSON.stringify(getInfoJson(status.info()), undefined, 4));
            };

            vm.activateUpdate = function (status) {
                vm.activeServerUpdate(status);
            };

            vm.processUpdate = function (form) {
                const status = vm.activeServerUpdate();
                if (ui.validateForm(form) === false) {
                    return;
                }
                LOG.debug(`processUpdate, engineId=${status.engineId()}`);
                vm.isUpdating(true);
                return vm.viewmodel.client.writeObjectUpdate(protocol.writeObjectUpdateRequest({
                    channel: protocol.WATCHDOG_STATUS_CHANNEL,
                    meta: model.metaObject({
                        id: status.id,
                        typeId: vm.statusObjects.typeId,
                        value: {
                            update: model.watchdogStatusUpdate({
                                fileKey: vm.updateFileKey(),
                                schedule: vm.updateSchedule()
                            }),
                            updateStatus: null
                        }
                    })
                })).then(function () {
                    vm.errorReply(undefined);
                    vm.activeServerUpdate(undefined);
                    vm.updateFileKey(undefined);
                    vm.updateSchedule(undefined);
                    ui.resetForm(form);
                }, function (exc) {
                    vm.errorReply(JSON.stringify(exc, undefined, 4));
                }).then(function () {
                    vm.isUpdating(false);
                });
            };

            vm.clearUpdateStatus = function (status) {
                return vm.viewmodel.client.writeObjectUpdate(protocol.writeObjectUpdateRequest({
                    channel: protocol.WATCHDOG_STATUS_CHANNEL,
                    meta: model.metaObject({
                        id: status.id,
                        typeId: vm.statusObjects.typeId,
                        value: {
                            updateStatus: null
                        }
                    })
                })).then(function () {
                    vm.errorReply(undefined);
                    status.updateStatus(undefined);
                }, function (exc) {
                    vm.errorReply(JSON.stringify(exc, undefined, 4));
                });
            };

            vm.statusObjects = objects({
                loadById: objects.loadByMetaId.bind(undefined, vm.viewmodel.client),
                sort: ext.simpleSort.bind(undefined, "engineId"),
                toVm: vm.viewmodel.toWatchdogStatusVm,
                typeId: model.WATCHDOG_STATUS_TYPE_ID
            });
            const eventHandle = vm.viewmodel.client.registerOnEvent(vm.statusObjects);

            vm.unhealthyServers = ko.pureComputed(function () {
                return vm.statusObjects.objects().filter(function (statusVm) {
                    return statusVm.healthy() === false;
                });
            });
            vm.alertServers = ko.pureComputed(function () {
                return vm.statusObjects.objects().filter(function (statusVm) {
                    return statusVm.healthy() && (statusVm.hasAlerts() || statusVm.updateStatus());
                });
            });
            vm.healthyServers = ko.pureComputed(function () {
                return vm.statusObjects.objects().filter(function (statusVm) {
                    return statusVm.healthy() && statusVm.hasAlerts() === false && Boolean(statusVm.updateStatus()) === false;
                });
            });

            vm.serverAlertNotification = ko.computed(function () {
                const noOfUnhealthy = vm.unhealthyServers().length;
                if (0 < noOfUnhealthy) {
                    ext.displayNotification({
                        options: {
                            body: i18next.t("watchdog_alarm_body", {count: noOfUnhealthy}),
                            tag: "watchdog"
                        },
                        title: i18next.t("watchdog_alarm")
                    });
                }
            });

            notificationChannel.onmessage = function (message) {
                const data = message.data;
                switch (data.type) {
                    case "onclick":
                        LOG.debug(`notification clicked, tag=${data.tag}`);
                        break;
                    case "onclose":
                        LOG.debug(`notification closed, tag=${data.tag}`);
                        break;
                }
            };

            vm.loadStatus = function () {
                LOG.debug("loadStatus");
                vm.statusObjects.clear();
                return vm.statusObjects.processSearch(
                    vm.viewmodel.client.search(protocol.searchRequest({
                        cursor: vm.statusObjects.searchCursor(),
                        limit: 200,
                        query: vm.statusObjects.newSearchQuery()
                    }))
                ).then(function () {
                    const mapApi = vm.viewmodel.mapApiProvider();
                    if (mapApi) {
                        mapApi.objectMarkers(vm.statusObjects.objects());
                    }
                }, function (exc) {
                    LOG.warn("loadStatus failed", exc);
                });
            };

            vm.isExportActive = ko.observable(false);
            vm.exportVersionByServer = ko.pureComputed(function () {
                const vms = vm.statusObjects.objects();
                const servers = {};
                vms.forEach(function (statusVm) {
                    const version = getVersion(statusVm.info());
                    if (version) {
                        servers[statusVm.engineId()] = version;
                    }
                });
                return JSON.stringify(servers, undefined, 4);
            });
            vm.exportServersByVersion = ko.pureComputed(function () {
                const vms = vm.statusObjects.objects();
                const versions = {};
                vms.forEach(function (statusVm) {
                    const version = getVersion(statusVm.info());
                    if (version) {
                        if (Boolean(versions[version]) === false) {
                            versions[version] = [statusVm.engineId()];
                        } else {
                            versions[version].push(statusVm.engineId());
                        }
                    }
                });
                return JSON.stringify(versions, undefined, 4);
            });
            vm.exportServerInfos = ko.pureComputed(function () {
                const vms = vm.statusObjects.objects();
                const infos = {};
                vms.forEach(function (statusVm) {
                    infos[statusVm.engineId()] = getInfoJson(statusVm.info());
                });
                return JSON.stringify(infos, undefined, 4);
            });

            vm.activateExport = function () {
                vm.isExportActive(true);
            };

            nav.register({
                id: vm.viewmodel.COMPONENTS.WATCHDOG,
                onUpdate: vm.loadStatus
            });

            vm.dispose = function () {
                LOG.debug("dispose");
                vm.viewmodel.client.unregisterOnEvent(eventHandle);
                updateScheduleSub.dispose();
            };

            return Object.freeze(vm);
        }
    }
});