/*
* site-monitor/models/monitor.js Copyright 2021 cPanel, L.L.C.
* All rights reserved.
* copyright@cpanel.net http://cpanel.net
* This code is subject to the cPanel license. Unauthorized copying is prohibited
*/
/* global define, PAGE */
/** @namespace cpanel.siteMoniter.models.monitor */
define([
"app/models/monitor-status.enum",
"app/models/monitor-type.enum",
"app/models/uptime-window.enum",
"app/models/monitor-state.enum",
],
function(MonitorStatus, MonitorType, UptimeWindow, MonitorState) {
"use strict";
var DEFAULT_CHECK_INTERVAL = 1800; // 30 min
/**
* @typedef Monitor
* @property {string} id - The unique id for the monitor provided by the backend.
* @property {string} name - The user given name for the monitor.
* @property {MonitorType} protocol - The protocal to access the site with.
* @property {string} domain - The domain to monitor.
* @property {number} port - Port the site is hosted on if any.
* @property {string} path - Path under the domain if any.
* @property {string} search - The querystring associated with the site url.
* @property {boolean} enabled - Weather the monitor is enabled or not, NOTE: not supported yet by nixstats
* @property {ISiteCheck2[]} data - average response time by hour for last 24 hours.
* @property {Contact} contact - The contact information for the monitor.
* @property {Date} firstUpdate - The date/time of the first check.
* @property {Date} lastUpdate - The date/time of the most recent check.
* @property {string} fromLocation - The location monitors check from.
* @property {number} interval - The interval that the site is check in seconds. NOTE: We don't know how to retrive this right now.
* @property {Date} sslExpiration - When HTTPS, the expiration date for the SSL certificate. Only present when retrieving the list of monitors.
* @property {MonitorState} [state] - optional, default to MonitorState.Ready.
*/
/**
*
* @param {Monitor} monitor
*/
function Monitor(monitor) {
if (monitor) {
this.id = monitor.id;
this.name = monitor.name;
this.protocol = monitor.protocol || MonitorType.HTTPS;
this.domain = monitor.domain;
this.port = monitor.port || _getDefaultPort(this.protocol);
this.path = monitor.path || '';
this.search = monitor.search || '';
this.enabled = monitor.enabled || true;
this.data = monitor.data || [];
this.contact = monitor.contact;
this.firstUpdate = monitor.firstUpdate;
this.lastUpdate = monitor.lastUpdate;
this.fromLocation = monitor.fromLocation;
this.interval = monitor.interval || DEFAULT_CHECK_INTERVAL;
this.sslExpiration = monitor.sslExpiration;
this.state = monitor.state || MonitorState.Ready;
}
}
/**
* Getter for the full URL for the monitor.
*/
Monitor.prototype.url = function() {
return (/^http/.test(this.protocol) ? this.protocol + "://" : "") +
this.domain +
(this.port !== _getDefaultPort(this.protocol) ? ":" + this.port : "") +
"/" + this.path +
(this.search !== '' ? "?" + this.search : "");
}
/**
* Clone the monitor.
*
* @returns {Monitor}
*/
Monitor.prototype.clone = function() {
return new Monitor(_.cloneDeep(this));
}
/**
* Calculate the default port number to be used with the given protocol.
*
* @param {MonitorType} protocol
* @returns {Number} the default port number.
*/
function _getDefaultPort(protocol) {
switch(protocol) {
case MonitorType.ICMP:
return; // ICMP does not use ports as it is neither TCP or UDP, it is a lower level IP protocol.
case MonitorType.TCP:
return 23; // Described as telnet, so uses the default telnet port.
case MonitorType.HTTP:
return 80;
case MonitorType.HTTPS:
default:
return 443;
}
}
/**
* @typedef {number} Timestamp
*/
/**
* @typedef ISiteCheck
* @property {number} t - Total time
* @property {numbrer} c - Time to connect to the server
* @property {string} status - The status message returned by the site check
* @property {Timestamp} time - The time the last site check was processed.
* @property {number} code - Status code returned by the site check
* @property {number} dns - Time for dns resolution
* @property {number} ttfb - Time to first byte
*/
/**
* @typedef ICheckFrom
* @property {string} name - The location the site was checked from.
* @property {string} ip_address_v6 - optional the locations ipv6 address.
* @property {string} ip_address - the locations ipv4 address.
*/
/**
* @typedef IMonitorItem
* @property {number} downtime_seconds - number of seconds the site was down.
* @property {Timestamp} first_update - the first time the monitore was updated.
* @property {string} id - unique idenfier for the monitor
* @property {string|null} ip_address - ???
* @property {ISiteCheck} last_check - statistics from the last site check.
* @property {Timestamp} last_update - the last time the monitor was updated.
* @property {ICheckFrom} monitor - the location the site was checked from.
* @property {string} name - the human readable name for the monitor.
* @property {Timestamp} ssl_expiration_timestamp - expiration date for the certificate. Only pressent on https requests.
* @property {MonitorStatus} status - the last status for the site.
* @property {string} status_message - the status message from the last check.
* @property {MonitorType} type - the monitor type.
* @property {number} uptime_percentage - the percentage of uptime
* @property {string} url - the full url without the protocol.
*/
/**
* Parse the raw monitor data from the apis into a Monitor object.
*
* @param {IMonitorItem} item
* @returns {Monitor}
*/
Monitor.parseListItem = function parseListItem(item) {
var fullUrl = "https://" + item.url;
var url = new URL(fullUrl);
return new Monitor({
id: item.id,
name: item.name,
protocol: item.type,
domain: url.hostname,
port: Number(url.port),
path: url.pathname.replace(/^\//, ""),
search: url.search.replace(/^\?/, ""),
type: item.type,
// UNIX timestamps are in sec, javascript timestamps are in ms
firstUpdate: new Date(item.first_update * 1000),
lastUpdate: new Date(item.last_update * 1000),
sslExpiration: new Date(item.ssl_expiration_timestamp * 1000), // UNIX timestamps are in sec, javascript timestamps are in ms
fromLocation: item.monitor.name,
// TODO: parse more data
});
}
/**
* @typedef {object} Contact
* @property {object} email - the contact is an email address
* @property {number} delay - number of seconds to delay before sending the alert.
*/
/**
* @typedef ISiteCheck2
* @property {number} time_total - Total time
* @property {number} time_connect - Time to connect to the server
* @property {string} status - The status message returned by the site check
* @property {number} time_dns - Time for dns resolution
* @property {number} time_to_first_byte - Time to first byte
*/
/**
* @typedef IUptimeWindow
* @property {UptimeWindow} date - the kind of uptime window.
* @property {number} events - number of events seen during the window.
* @property {number} downtime_seconds - number of seconds the site was down.
* @property {number} uptime_percentage - the percentage of time the site was down.
* @property {Timestamp} start - the start date/time for the window
* @property {Timestamp} end - the start date/time for the window
*/
/**
* @typedef {object} IMonitorDetails
* @property {Object.<string, Contact>} contacts - list of contact to alert when the site is down
* @property {number} code
* @property {Timestamp} first_update - the date/time of the first update
* @property {string} id - uniquie id for the monitor.
* @property {string|null} ip_address - ???
* @property {boolean} password - ???
* @property {Timestamp} last_update - the date/time of the last update
* @property {ISiteCheck2} last_check - the times for the most recent check.
* @property {ICheckFrom} monitor - the location the monitor was checked from.
* @property {string} name - the user friendly name of the monitor
* @property {MonitorType} type - the protocol for the monitor.
* @property {MonitorStatus} status - the current status for the monitor.
* @property {string} url - the full url including the protocol.
* @property {IUptimeWindow[]} uptimes - summaries of various uptime windows.
* @property {boolean} username - ???
*/
/**
* Parser for data returned by get_domain_monitor
*
* @param {IMonitorDetails} item
* @returns {Monitor}
*/
Monitor.parseItem = function parseItem(item) {
var url = new URL(item.url);
return new Monitor({
id: angular.isDefined(item.id) ? item.id: null,
name: angular.isDefined(item.name) ? item.name: null,
protocol: item.type,
domain: url.hostname,
port: url.port,
path: url.pathname.replace(/^\//, ""),
search: url.search.replace(/^\?/, ""),
firstUpdate: angular.isDefined(item.first_update) ? new Date(item.first_update * 1000) : null,
lastUpdate: angular.isDefined(item.last_update) ? new Date(item.last_update * 1000) : null,
fromLocation: angular.isDefined(item.monitor) ? item.monitor.name : null,
interval: angular.isDefined(item.interval) ? item.interval: null,
state: angular.isDefined(item.state) ? item.state: null,
// TODO: parse more data
});
}
/**
* The default interval that monitors check the site/page being monitored in ms.
*
* @type Number
*/
Monitor.DEFAULT_CHECK_INTERVAL = DEFAULT_CHECK_INTERVAL;
return Monitor;
}
);