Added JSDoc to ESLint (#3529)

* Added JSDoc to eslint rules

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>

* Fixed JSDoc eslint errors

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>

* Update the check-linters workflow to Node.js 20

---------

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
This commit is contained in:
Matthew Nickson
2023-08-11 09:46:41 +02:00
committed by GitHub
parent da4f4e3d76
commit 8a92054c2b
153 changed files with 1505 additions and 574 deletions

View File

@@ -9,9 +9,9 @@ const dayjs = require("dayjs");
/**
* Login to web app
* @param {string} username
* @param {string} password
* @returns {Promise<(Bean|null)>}
* @param {string} username Username to login with
* @param {string} password Password to login with
* @returns {Promise<(Bean|null)>} User or null if login failed
*/
exports.login = async function (username, password) {
if (typeof username !== "string" || typeof password !== "string") {
@@ -39,6 +39,7 @@ exports.login = async function (username, password) {
/**
* Validate a provided API key
* @param {string} key API key to verify
* @returns {boolean} API is ok?
*/
async function verifyAPIKey(key) {
if (typeof key !== "string") {
@@ -73,9 +74,10 @@ async function verifyAPIKey(key) {
/**
* Custom authorizer for express-basic-auth
* @param {string} username
* @param {string} password
* @param {authCallback} callback
* @param {string} username Username to login with
* @param {string} password Password to login with
* @param {authCallback} callback Callback to handle login result
* @returns {void}
*/
function apiAuthorizer(username, password, callback) {
// API Rate Limit
@@ -99,9 +101,10 @@ function apiAuthorizer(username, password, callback) {
/**
* Custom authorizer for express-basic-auth
* @param {string} username
* @param {string} password
* @param {authCallback} callback
* @param {string} username Username to login with
* @param {string} password Password to login with
* @param {authCallback} callback Callback to handle login result
* @returns {void}
*/
function userAuthorizer(username, password, callback) {
// Login Rate Limit
@@ -126,7 +129,8 @@ function userAuthorizer(username, password, callback) {
* Use basic auth if auth is not disabled
* @param {express.Request} req Express request object
* @param {express.Response} res Express response object
* @param {express.NextFunction} next
* @param {express.NextFunction} next Next handler in chain
* @returns {void}
*/
exports.basicAuth = async function (req, res, next) {
const middleware = basicAuth({
@@ -148,7 +152,8 @@ exports.basicAuth = async function (req, res, next) {
* Use use API Key if API keys enabled, else use basic auth
* @param {express.Request} req Express request object
* @param {express.Response} res Express response object
* @param {express.NextFunction} next
* @param {express.NextFunction} next Next handler in chain
* @returns {void}
*/
exports.apiAuth = async function (req, res, next) {
if (!await Settings.get("disableAuth")) {

View File

@@ -15,6 +15,7 @@ class CacheableDnsHttpAgent {
/**
* Register/Disable cacheable to global agents
* @returns {void}
*/
static async update() {
log.debug("CacheableDnsHttpAgent", "update");
@@ -40,14 +41,15 @@ class CacheableDnsHttpAgent {
/**
* Attach cacheable to HTTP agent
* @param {http.Agent} agent Agent to install
* @returns {void}
*/
static install(agent) {
this.cacheable.install(agent);
}
/**
* @var {https.AgentOptions} agentOptions
* @return {https.Agent}
* @param {https.AgentOptions} agentOptions Options to pass to HTTPS agent
* @returns {https.Agent} The new HTTPS agent
*/
static getHttpsAgent(agentOptions) {
if (!this.enable) {
@@ -63,8 +65,8 @@ class CacheableDnsHttpAgent {
}
/**
* @var {http.AgentOptions} agentOptions
* @return {https.Agents}
* @param {http.AgentOptions} agentOptions Options to pass to the HTTP agent
* @returns {https.Agents} The new HTTP agent
*/
static getHttpAgent(agentOptions) {
if (!this.enable) {

View File

@@ -12,7 +12,7 @@ const checkVersion = require("./check-version");
/**
* Send list of notification providers to client
* @param {Socket} socket Socket.io socket instance
* @returns {Promise<Bean[]>}
* @returns {Promise<Bean[]>} List of notifications
*/
async function sendNotificationList(socket) {
const timeLogger = new TimeLogger();
@@ -40,8 +40,8 @@ async function sendNotificationList(socket) {
* Send Heartbeat History list to socket
* @param {Socket} socket Socket.io instance
* @param {number} monitorID ID of monitor to send heartbeat history
* @param {boolean} [toUser=false] True = send to all browsers with the same user id, False = send to the current browser only
* @param {boolean} [overwrite=false] Overwrite client-side's heartbeat list
* @param {boolean} toUser True = send to all browsers with the same user id, False = send to the current browser only
* @param {boolean} overwrite Overwrite client-side's heartbeat list
* @returns {Promise<void>}
*/
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
@@ -71,8 +71,8 @@ async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite =
* Important Heart beat list (aka event list)
* @param {Socket} socket Socket.io instance
* @param {number} monitorID ID of monitor to send heartbeat history
* @param {boolean} [toUser=false] True = send to all browsers with the same user id, False = send to the current browser only
* @param {boolean} [overwrite=false] Overwrite client-side's heartbeat list
* @param {boolean} toUser True = send to all browsers with the same user id, False = send to the current browser only
* @param {boolean} overwrite Overwrite client-side's heartbeat list
* @returns {Promise<void>}
*/
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
@@ -100,7 +100,7 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove
/**
* Emit proxy list to client
* @param {Socket} socket Socket.io socket instance
* @return {Promise<Bean[]>}
* @returns {Promise<Bean[]>} List of proxies
*/
async function sendProxyList(socket) {
const timeLogger = new TimeLogger();
@@ -141,7 +141,7 @@ async function sendAPIKeyList(socket) {
/**
* Emits the version information to the client.
* @param {Socket} socket Socket.io socket instance
* @param {boolean} hideVersion
* @param {boolean} hideVersion Should we hide the version information in the response?
* @returns {Promise<void>}
*/
async function sendInfo(socket, hideVersion = false) {
@@ -165,7 +165,7 @@ async function sendInfo(socket, hideVersion = false) {
/**
* Send list of docker hosts to client
* @param {Socket} socket Socket.io socket instance
* @returns {Promise<Bean[]>}
* @returns {Promise<Bean[]>} List of docker hosts
*/
async function sendDockerHostList(socket) {
const timeLogger = new TimeLogger();

View File

@@ -101,7 +101,8 @@ class Database {
/**
* Initialize the data directory
* @param {Object} args Arguments to initialize DB with
* @param {object} args Arguments to initialize DB with
* @returns {void}
*/
static initDataDir(args) {
// Data Directory (must be end with "/")
@@ -154,11 +155,11 @@ class Database {
/**
* Connect to the database
* @param {boolean} [testMode=false] Should the connection be
* @param {boolean} testMode Should the connection be
* started in test mode?
* @param {boolean} [autoloadModels=true] Should models be
* @param {boolean} autoloadModels Should models be
* automatically loaded?
* @param {boolean} [noLog=false] Should logs not be output?
* @param {boolean} noLog Should logs not be output?
* @returns {Promise<void>}
*/
static async connect(testMode = false, autoloadModels = true, noLog = false) {
@@ -312,6 +313,10 @@ class Database {
}
}
/**
* Patch the database
* @returns {void}
*/
static async patch() {
// Still need to keep this for old versions of Uptime Kuma
if (Database.dbConfig.type === "sqlite") {
@@ -497,8 +502,8 @@ class Database {
* Patch database using new patching process
* Used it patch2() only
* @private
* @param sqlFilename
* @param databasePatchedFiles
* @param {string} sqlFilename Name of SQL file to load
* @param {object} databasePatchedFiles Patch status of database files
* @returns {Promise<void>}
*/
static async patch2Recursion(sqlFilename, databasePatchedFiles) {
@@ -533,7 +538,7 @@ class Database {
/**
* Load an SQL file and execute it
* @param filename Filename of SQL file to import
* @param {string} filename Filename of SQL file to import
* @returns {Promise<void>}
*/
static async importSQLFile(filename) {
@@ -567,7 +572,7 @@ class Database {
/**
* Aquire a direct connection to database
* @returns {any}
* @returns {any} Database connection
*/
static getBetterSQLite3Database() {
return R.knex.client.acquireConnection();
@@ -604,7 +609,10 @@ class Database {
process.removeListener("unhandledRejection", listener);
}
/** Get the size of the database */
/**
* Get the size of the database
* @returns {number} Size of database
*/
static getSize() {
log.debug("db", "Database.getSize()");
let stats = fs.statSync(Database.sqlitePath);

View File

@@ -14,10 +14,10 @@ class DockerHost {
/**
* Save a docker host
* @param {Object} dockerHost Docker host to save
* @param {object} dockerHost Docker host to save
* @param {?number} dockerHostID ID of the docker host to update
* @param {number} userID ID of the user who adds the docker host
* @returns {Promise<Bean>}
* @returns {Promise<Bean>} Updated docker host
*/
static async save(dockerHost, dockerHostID, userID) {
let bean;
@@ -64,7 +64,7 @@ class DockerHost {
/**
* Fetches the amount of containers on the Docker host
* @param {Object} dockerHost Docker host to check for
* @param {object} dockerHost Docker host to check for
* @returns {number} Total amount of containers on the host
*/
static async testDockerHost(dockerHost) {
@@ -108,6 +108,8 @@ class DockerHost {
/**
* Since axios 0.27.X, it does not accept `tcp://` protocol.
* Change it to `http://` on the fly in order to fix it. (https://github.com/louislam/uptime-kuma/issues/2165)
* @param {any} url URL to fix
* @returns {any} URL with tcp:// replaced by http://
*/
static patchDockerURL(url) {
if (typeof url === "string") {
@@ -129,11 +131,10 @@ class DockerHost {
* 'data/docker-tls/example.com/' would be searched for certificate files),
* then 'ca.pem', 'key.pem' and 'cert.pem' files are included in the agent options.
* File names can also be overridden via 'DOCKER_TLS_FILE_NAME_(CA|KEY|CERT)'.
*
* @param {String} dockerType i.e. "tcp" or "socket"
* @param {String} url The docker host URL rewritten to https://
* @return {Object}
* */
* @param {string} dockerType i.e. "tcp" or "socket"
* @param {string} url The docker host URL rewritten to https://
* @returns {object} HTTP agent options
*/
static getHttpsAgentOptions(dockerType, url) {
let baseOptions = {
maxCachedSessions: 0,

View File

@@ -3,8 +3,8 @@ const jsesc = require("jsesc");
/**
* Returns a string that represents the javascript that is required to insert the Google Analytics scripts
* into a webpage.
* @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
* @returns {string}
* @param {string} tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
* @returns {string} HTML script tags to inject into page
*/
function getGoogleAnalyticsScript(tagId) {
let escapedTagId = jsesc(tagId, { isScriptContext: true });

View File

@@ -10,7 +10,7 @@ let ImageDataURI = (() => {
/**
* Decode the data:image/ URI
* @param {string} dataURI data:image/ URI to decode
* @returns {?Object} An object with properties "imageType" and "dataBase64".
* @returns {?object} An object with properties "imageType" and "dataBase64".
* The former is the image type, e.g., "png", and the latter is a base64
* encoded string of the image's binary data. If it fails to parse, returns
* null instead of an object.
@@ -52,8 +52,8 @@ let ImageDataURI = (() => {
/**
* Write data URI to file
* @param {string} dataURI data:image/ URI
* @param {string} [filePath] Path to write file to
* @returns {Promise<string>}
* @param {string} filePath Path to write file to
* @returns {Promise<string|void>} Write file error
*/
function outputFile(dataURI, filePath) {
filePath = filePath || "./";

View File

@@ -39,7 +39,10 @@ const initBackgroundJobs = async function () {
};
/** Stop all background jobs if running */
/**
* Stop all background jobs if running
* @returns {void}
*/
const stopBackgroundJobs = function () {
for (const job of jobs) {
if (job.croner) {

View File

@@ -7,7 +7,7 @@ const DEFAULT_KEEP_PERIOD = 180;
/**
* Clears old data from the heartbeat table of the database.
* @return {Promise<void>} A promise that resolves when the data has been cleared.
* @returns {Promise<void>} A promise that resolves when the data has been cleared.
*/
const clearOldData = async () => {

View File

@@ -4,7 +4,7 @@ const Database = require("../database");
/**
* Run incremental_vacuum and checkpoint the WAL.
* @return {Promise<void>} A promise that resolves when the process is finished.
* @returns {Promise<void>} A promise that resolves when the process is finished.
*/
const incrementalVacuum = async () => {

View File

@@ -19,7 +19,7 @@ class APIKey extends BeanModel {
/**
* Returns an object that ready to parse to JSON
* @returns {Object}
* @returns {object} Object ready to parse
*/
toJSON() {
return {
@@ -37,7 +37,7 @@ class APIKey extends BeanModel {
/**
* Returns an object that ready to parse to JSON with sensitive fields
* removed
* @returns {Object}
* @returns {object} Object ready to parse
*/
toPublicJSON() {
return {
@@ -53,9 +53,9 @@ class APIKey extends BeanModel {
/**
* Create a new API Key and store it in the database
* @param {Object} key Object sent by client
* @param {object} key Object sent by client
* @param {int} userID ID of socket user
* @returns {Promise<bean>}
* @returns {Promise<bean>} API key
*/
static async save(key, userID) {
let bean;

View File

@@ -3,7 +3,7 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
class DockerHost extends BeanModel {
/**
* Returns an object that ready to parse to JSON
* @returns {Object}
* @returns {object} Object ready to parse
*/
toJSON() {
return {

View File

@@ -4,10 +4,12 @@ const { R } = require("redbean-node");
class Group extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @param {boolean} [showTags=false] Should the JSON include monitor tags
* @returns {Object}
* Return an object that ready to parse to JSON for public Only show
* necessary data to public
* @param {boolean} showTags Should the JSON include monitor tags
* @param {boolean} certExpiry Should JSON include info about
* certificate expiry?
* @returns {object} Object ready to parse
*/
async toPublicJSON(showTags = false, certExpiry = false) {
let monitorBeanList = await this.getMonitorList();
@@ -27,7 +29,7 @@ class Group extends BeanModel {
/**
* Get all monitors
* @returns {Bean[]}
* @returns {Bean[]} List of monitors
*/
async getMonitorList() {
return R.convertToBeans("monitor", await R.getAll(`

View File

@@ -12,7 +12,7 @@ class Heartbeat extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {Object}
* @returns {object} Object ready to parse
*/
toPublicJSON() {
return {
@@ -25,7 +25,7 @@ class Heartbeat extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @returns {Object}
* @returns {object} Object ready to parse
*/
toJSON() {
return {

View File

@@ -5,7 +5,7 @@ class Incident extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {Object}
* @returns {object} Object ready to parse
*/
toPublicJSON() {
return {

View File

@@ -11,7 +11,7 @@ class Maintenance extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {Object}
* @returns {object} Object ready to parse
*/
async toPublicJSON() {
@@ -98,7 +98,7 @@ class Maintenance extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @param {string} timezone If not specified, the timeRange will be in UTC
* @returns {Object}
* @returns {object} Object ready to parse
*/
async toJSON(timezone = null) {
return this.toPublicJSON(timezone);
@@ -142,7 +142,7 @@ class Maintenance extends BeanModel {
/**
* Convert data from socket to bean
* @param {Bean} bean Bean to fill in
* @param {Object} obj Data to fill bean with
* @param {object} obj Data to fill bean with
* @returns {Bean} Filled bean
*/
static async jsonToBean(bean, obj) {
@@ -188,7 +188,7 @@ class Maintenance extends BeanModel {
/**
* Throw error if cron is invalid
* @param cron
* @param {string|Date} cron Pattern or date
* @returns {Promise<void>}
*/
static async validateCron(cron) {
@@ -198,6 +198,8 @@ class Maintenance extends BeanModel {
/**
* Run the cron
* @param {boolean} throwError Should an error be thrown on failure
* @returns {Promise<void>}
*/
async run(throwError = false) {
if (this.beanMeta.job) {
@@ -290,6 +292,10 @@ class Maintenance extends BeanModel {
}
}
/**
* Get timeslots where maintenance is running
* @returns {object|null} Maintenance time slot
*/
getRunningTimeslot() {
let start = dayjs(this.beanMeta.job.nextRun(dayjs().add(-this.duration, "second").toDate()));
let end = start.add(this.duration, "second");
@@ -305,6 +311,10 @@ class Maintenance extends BeanModel {
}
}
/**
* Stop the maintenance
* @returns {void}
*/
stop() {
if (this.beanMeta.job) {
this.beanMeta.job.stop();
@@ -312,10 +322,18 @@ class Maintenance extends BeanModel {
}
}
/**
* Is this maintenance currently active
* @returns {boolean} The maintenance is active?
*/
async isUnderMaintenance() {
return (await this.getStatus()) === "under-maintenance";
}
/**
* Get the timezone of the maintenance
* @returns {string} timezone
*/
async getTimezone() {
if (!this.timezone || this.timezone === "SAME_AS_SERVER") {
return await UptimeKumaServer.getInstance().getTimezone();
@@ -323,10 +341,18 @@ class Maintenance extends BeanModel {
return this.timezone;
}
/**
* Get offset for timezone
* @returns {string} offset
*/
async getTimezoneOffset() {
return dayjs.tz(dayjs(), await this.getTimezone()).format("Z");
}
/**
* Get the current status of the maintenance
* @returns {string} Current status
*/
async getStatus() {
if (!this.active) {
return "inactive";

View File

@@ -34,9 +34,12 @@ const Database = require("../database");
class Monitor extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {Object}
* Return an object that ready to parse to JSON for public Only show
* necessary data to public
* @param {boolean} showTags Include tags in JSON
* @param {boolean} certExpiry Include certificate expiry info in
* JSON
* @returns {object} Object ready to parse
*/
async toPublicJSON(showTags = false, certExpiry = false) {
let obj = {
@@ -65,7 +68,9 @@ class Monitor extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @returns {Object}
* @param {boolean} includeSensitiveData Include sensitive data in
* JSON
* @returns {object} Object ready to parse
*/
async toJSON(includeSensitiveData = true) {
@@ -183,9 +188,9 @@ class Monitor extends BeanModel {
}
/**
* Checks if the monitor is active based on itself and its parents
* @returns {Promise<Boolean>}
*/
* Checks if the monitor is active based on itself and its parents
* @returns {Promise<boolean>} Is the monitor active?
*/
async isActive() {
const parentActive = await Monitor.isParentActive(this.id);
@@ -194,7 +199,8 @@ class Monitor extends BeanModel {
/**
* Get all tags applied to this monitor
* @returns {Promise<LooseObject<any>[]>}
* @returns {Promise<LooseObject<any>[]>} List of tags on the
* monitor
*/
async getTags() {
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ? ORDER BY tag.name", [ this.id ]);
@@ -203,7 +209,8 @@ class Monitor extends BeanModel {
/**
* Gets certificate expiry for this monitor
* @param {number} monitorID ID of monitor to send
* @returns {Promise<LooseObject<any>>}
* @returns {Promise<LooseObject<any>>} Certificate expiry info for
* monitor
*/
async getCertExpiry(monitorID) {
let tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
@@ -228,7 +235,9 @@ class Monitor extends BeanModel {
/**
* Encode user and password to Base64 encoding
* for HTTP "basic" auth, as per RFC-7617
* @returns {string}
* @param {string} user Username to encode
* @param {string} pass Password to encode
* @returns {string} Encoded username:password
*/
encodeBase64(user, pass) {
return Buffer.from(user + ":" + pass).toString("base64");
@@ -236,7 +245,7 @@ class Monitor extends BeanModel {
/**
* Is the TLS expiry notification enabled?
* @returns {boolean}
* @returns {boolean} Enabled?
*/
isEnabledExpiryNotification() {
return Boolean(this.expiryNotification);
@@ -244,7 +253,7 @@ class Monitor extends BeanModel {
/**
* Parse to boolean
* @returns {boolean}
* @returns {boolean} Should TLS errors be ignored?
*/
getIgnoreTls() {
return Boolean(this.ignoreTls);
@@ -252,7 +261,7 @@ class Monitor extends BeanModel {
/**
* Parse to boolean
* @returns {boolean}
* @returns {boolean} Is the monitor in upside down mode?
*/
isUpsideDown() {
return Boolean(this.upsideDown);
@@ -260,7 +269,7 @@ class Monitor extends BeanModel {
/**
* Parse to boolean
* @returns {boolean}
* @returns {boolean} Invert keyword match?
*/
isInvertKeyword() {
return Boolean(this.invertKeyword);
@@ -268,7 +277,7 @@ class Monitor extends BeanModel {
/**
* Parse to boolean
* @returns {boolean}
* @returns {boolean} Enable TLS for gRPC?
*/
getGrpcEnableTls() {
return Boolean(this.grpcEnableTls);
@@ -276,7 +285,7 @@ class Monitor extends BeanModel {
/**
* Get accepted status codes
* @returns {Object}
* @returns {object} Accepted status codes
*/
getAcceptedStatuscodes() {
return JSON.parse(this.accepted_statuscodes_json);
@@ -289,6 +298,7 @@ class Monitor extends BeanModel {
/**
* Start monitor
* @param {Server} io Socket server instance
* @returns {void}
*/
start(io) {
let previousBeat = null;
@@ -980,7 +990,10 @@ class Monitor extends BeanModel {
};
/** Get a heartbeat and handle errors */
/**
* Get a heartbeat and handle errors7
* @returns {void}
*/
const safeBeat = async () => {
try {
await beat();
@@ -1008,10 +1021,10 @@ class Monitor extends BeanModel {
/**
* Make a request using axios
* @param {Object} options Options for Axios
* @param {object} options Options for Axios
* @param {boolean} finalCall Should this be the final call i.e
* don't retry on faliure
* @returns {Object} Axios response
* don't retry on failure
* @returns {object} Axios response
*/
async makeAxiosRequest(options, finalCall = false) {
try {
@@ -1046,7 +1059,10 @@ class Monitor extends BeanModel {
}
}
/** Stop monitor */
/**
* Stop monitor
* @returns {void}
*/
stop() {
clearTimeout(this.heartbeatInterval);
this.isStop = true;
@@ -1056,7 +1072,7 @@ class Monitor extends BeanModel {
/**
* Get prometheus instance
* @returns {Prometheus|undefined}
* @returns {Prometheus|undefined} Current prometheus instance
*/
getPrometheus() {
return this.prometheus;
@@ -1066,7 +1082,7 @@ class Monitor extends BeanModel {
* Helper Method:
* returns URL object for further usage
* returns null if url is invalid
* @returns {(null|URL)}
* @returns {(null|URL)} Monitor URL
*/
getUrl() {
try {
@@ -1078,8 +1094,8 @@ class Monitor extends BeanModel {
/**
* Store TLS info to database
* @param checkCertificateResult
* @returns {Promise<Object>}
* @param {object} checkCertificateResult Certificate to update
* @returns {Promise<object>} Updated certificate
*/
async updateTlsInfo(checkCertificateResult) {
let tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
@@ -1126,6 +1142,7 @@ class Monitor extends BeanModel {
* @param {Server} io Socket server instance
* @param {number} monitorID ID of monitor to send
* @param {number} userID ID of user to send to
* @returns {void}
*/
static async sendStats(io, monitorID, userID) {
const hasClients = getTotalClientInRoom(io, userID) > 0;
@@ -1143,6 +1160,10 @@ class Monitor extends BeanModel {
/**
* Send the average ping to user
* @param {number} duration Hours
* @param {Server} io Socket instance to send data to
* @param {number} monitorID ID of monitor to read
* @param {number} userID ID of user to send data to
* @returns {void}
*/
static async sendAvgPing(duration, io, monitorID, userID) {
const timeLogger = new TimeLogger();
@@ -1168,6 +1189,7 @@ class Monitor extends BeanModel {
* @param {Server} io Socket server instance
* @param {number} monitorID ID of monitor to send
* @param {number} userID ID of user to send to
* @returns {void}
*/
static async sendCertInfo(io, monitorID, userID) {
let tlsInfo = await R.findOne("monitor_tls_info", "monitor_id = ?", [
@@ -1184,6 +1206,8 @@ class Monitor extends BeanModel {
* https://www.uptrends.com/support/kb/reporting/calculation-of-uptime-and-downtime
* @param {number} duration Hours
* @param {number} monitorID ID of monitor to calculate
* @param {boolean} forceNoCache Should the uptime be recalculated?
* @returns {number} Uptime of monitor
*/
static async calcUptime(duration, monitorID, forceNoCache = false) {
@@ -1264,6 +1288,7 @@ class Monitor extends BeanModel {
* @param {Server} io Socket server instance
* @param {number} monitorID ID of monitor to send
* @param {number} userID ID of user to send to
* @returns {void}
*/
static async sendUptime(duration, io, monitorID, userID) {
const uptime = await this.calcUptime(duration, monitorID);
@@ -1338,6 +1363,7 @@ class Monitor extends BeanModel {
* @param {boolean} isFirstBeat Is this beat the first of this monitor?
* @param {Monitor} monitor The monitor to send a notificaton about
* @param {Bean} bean Status information about monitor
* @returns {void}
*/
static async sendNotification(isFirstBeat, monitor, bean) {
if (!isFirstBeat || bean.status === DOWN) {
@@ -1378,7 +1404,7 @@ class Monitor extends BeanModel {
/**
* Get list of notification providers for a given monitor
* @param {Monitor} monitor Monitor to get notification providers for
* @returns {Promise<LooseObject<any>[]>}
* @returns {Promise<LooseObject<any>[]>} List of notifications
*/
static async getNotificationList(monitor) {
let notificationList = await R.getAll("SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id ", [
@@ -1389,7 +1415,8 @@ class Monitor extends BeanModel {
/**
* checks certificate chain for expiring certificates
* @param {Object} tlsInfoObject Information about certificate
* @param {object} tlsInfoObject Information about certificate
* @returns {void}
*/
async checkCertExpiryNotifications(tlsInfoObject) {
if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) {
@@ -1476,7 +1503,7 @@ class Monitor extends BeanModel {
/**
* Get the status of the previous heartbeat
* @param {number} monitorID ID of monitor to check
* @returns {Promise<LooseObject<any>>}
* @returns {Promise<LooseObject<any>>} Previous heartbeat
*/
static async getPreviousHeartbeat(monitorID) {
return await R.getRow(`
@@ -1490,7 +1517,7 @@ class Monitor extends BeanModel {
/**
* Check if monitor is under maintenance
* @param {number} monitorID ID of monitor to check
* @returns {Promise<boolean>}
* @returns {Promise<boolean>} Is the monitor under maintenance
*/
static async isUnderMaintenance(monitorID) {
const maintenanceIDList = await R.getCol(`
@@ -1513,7 +1540,11 @@ class Monitor extends BeanModel {
return false;
}
/** Make sure monitor interval is between bounds */
/**
* Make sure monitor interval is between bounds
* @returns {void}
* @throws Interval is outside of range
*/
validate() {
if (this.interval > MAX_INTERVAL_SECOND) {
throw new Error(`Interval cannot be more than ${MAX_INTERVAL_SECOND} seconds`);
@@ -1526,7 +1557,7 @@ class Monitor extends BeanModel {
/**
* Gets Parent of the monitor
* @param {number} monitorID ID of monitor to get
* @returns {Promise<LooseObject<any>>}
* @returns {Promise<LooseObject<any>>} Parent
*/
static async getParent(monitorID) {
return await R.getRow(`
@@ -1542,7 +1573,7 @@ class Monitor extends BeanModel {
/**
* Gets all Children of the monitor
* @param {number} monitorID ID of monitor to get
* @returns {Promise<LooseObject<any>>}
* @returns {Promise<LooseObject<any>>} Children
*/
static async getChildren(monitorID) {
return await R.getAll(`
@@ -1555,7 +1586,7 @@ class Monitor extends BeanModel {
/**
* Gets Full Path-Name (Groups and Name)
* @returns {Promise<String>}
* @returns {Promise<string>} Full path name of this monitor
*/
async getPathName() {
let path = this.name;
@@ -1575,8 +1606,8 @@ class Monitor extends BeanModel {
/**
* Gets recursive all child ids
* @param {number} monitorID ID of the monitor to get
* @returns {Promise<Array>}
* @param {number} monitorID ID of the monitor to get
* @returns {Promise<Array>} IDs of all children
*/
static async getAllChildrenIDs(monitorID) {
const childs = await Monitor.getChildren(monitorID);
@@ -1607,10 +1638,10 @@ class Monitor extends BeanModel {
}
/**
* Checks recursive if parent (ancestors) are active
* @param {number} monitorID ID of the monitor to get
* @returns {Promise<Boolean>}
*/
* Checks recursive if parent (ancestors) are active
* @param {number} monitorID ID of the monitor to get
* @returns {Promise<boolean>} Is the parent monitor active?
*/
static async isParentActive(monitorID) {
const parent = await Monitor.getParent(monitorID);

View File

@@ -3,7 +3,7 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
class Proxy extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @returns {Object}
* @returns {object} Object ready to parse
*/
toJSON() {
return {

View File

@@ -14,10 +14,11 @@ class StatusPage extends BeanModel {
static domainMappingList = { };
/**
*
* @param {Response} response
* @param {string} indexHTML
* @param {string} slug
* Handle responses to status page
* @param {Response} response Response object
* @param {string} indexHTML HTML to render
* @param {string} slug Status page slug
* @returns {void}
*/
static async handleStatusPageResponse(response, indexHTML, slug) {
let statusPage = await R.findOne("status_page", " slug = ? ", [
@@ -33,8 +34,9 @@ class StatusPage extends BeanModel {
/**
* SSR for status pages
* @param {string} indexHTML
* @param {StatusPage} statusPage
* @param {string} indexHTML HTML page to render
* @param {StatusPage} statusPage Status page populate HTML with
* @returns {void}
*/
static async renderHTML(indexHTML, statusPage) {
const $ = cheerio.load(indexHTML);
@@ -87,7 +89,8 @@ class StatusPage extends BeanModel {
/**
* Get all status page data in one call
* @param {StatusPage} statusPage
* @param {StatusPage} statusPage Status page to get data for
* @returns {object} Status page data
*/
static async getStatusPageData(statusPage) {
const config = await statusPage.toPublicJSON();
@@ -142,7 +145,7 @@ class StatusPage extends BeanModel {
* Send status page list to client
* @param {Server} io io Socket server instance
* @param {Socket} socket Socket.io instance
* @returns {Promise<Bean[]>}
* @returns {Promise<Bean[]>} Status page list
*/
static async sendStatusPageList(io, socket) {
let result = {};
@@ -159,7 +162,7 @@ class StatusPage extends BeanModel {
/**
* Update list of domain names
* @param {string[]} domainNameList
* @param {string[]} domainNameList List of status page domains
* @returns {Promise<void>}
*/
async updateDomainNameList(domainNameList) {
@@ -203,7 +206,7 @@ class StatusPage extends BeanModel {
/**
* Get list of domain names
* @returns {Object[]}
* @returns {object[]} List of status page domains
*/
getDomainNameList() {
let domainList = [];
@@ -219,7 +222,7 @@ class StatusPage extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @returns {Object}
* @returns {object} Object ready to parse
*/
async toJSON() {
return {
@@ -243,7 +246,7 @@ class StatusPage extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {Object}
* @returns {object} Object ready to parse
*/
async toPublicJSON() {
return {
@@ -264,7 +267,8 @@ class StatusPage extends BeanModel {
/**
* Convert slug to status page ID
* @param {string} slug
* @param {string} slug Status page slug
* @returns {Promise<number>} ID of status page
*/
static async slugToID(slug) {
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [
@@ -274,7 +278,7 @@ class StatusPage extends BeanModel {
/**
* Get path to the icon for the page
* @returns {string}
* @returns {string} Path
*/
getIcon() {
if (!this.icon) {
@@ -287,7 +291,7 @@ class StatusPage extends BeanModel {
/**
* Get list of maintenances
* @param {number} statusPageId ID of status page to get maintenance for
* @returns {Object} Object representing maintenances sanitized for public
* @returns {object} Object representing maintenances sanitized for public
*/
static async getMaintenanceList(statusPageId) {
try {

View File

@@ -4,7 +4,7 @@ class Tag extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @returns {Object}
* @returns {object} Object ready to parse
*/
toJSON() {
return {

View File

@@ -7,7 +7,7 @@ class User extends BeanModel {
* Reset user password
* Fix #1510, as in the context reset-password.js, there is no auto model mapping. Call this static function instead.
* @param {number} userID ID of user to update
* @param {string} newPassword
* @param {string} newPassword Users new password
* @returns {Promise<void>}
*/
static async resetPassword(userID, newPassword) {
@@ -19,7 +19,7 @@ class User extends BeanModel {
/**
* Reset this users password
* @param {string} newPassword
* @param {string} newPassword Users new password
* @returns {Promise<void>}
*/
async resetPassword(newPassword) {

View File

@@ -3,10 +3,10 @@ class MonitorType {
name = undefined;
/**
*
* @param {Monitor} monitor
* @param {Heartbeat} heartbeat
* @param {UptimeKumaServer} server
* Run the monitoring check on the given monitor
* @param {Monitor} monitor Monitor to check
* @param {Heartbeat} heartbeat Monitor heartbeat to update
* @param {UptimeKumaServer} server Uptime Kuma server
* @returns {Promise<void>}
*/
async check(monitor, heartbeat, server) {

View File

@@ -51,6 +51,11 @@ if (process.platform === "win32") {
log.debug("chrome", allowedList);
/**
* Is the executable path allowed?
* @param {string} executablePath Path to executable
* @returns {Promise<boolean>} The executable is allowed?
*/
async function isAllowedChromeExecutable(executablePath) {
console.log(config.args);
if (config.args["allow-all-chrome-exec"] || process.env.UPTIME_KUMA_ALLOW_ALL_CHROME_EXEC === "1") {
@@ -61,6 +66,11 @@ async function isAllowedChromeExecutable(executablePath) {
return allowedList.includes(executablePath);
}
/**
* Get the current instance of the browser. If there isn't one, create
* it.
* @returns {Promise<Browser>} The browser
*/
async function getBrowser() {
if (!browser) {
let executablePath = await Settings.get("chromeExecutable");
@@ -75,6 +85,11 @@ async function getBrowser() {
return browser;
}
/**
* Prepare the chrome executable path
* @param {string} executablePath Path to chrome executable
* @returns {Promise<string>} Executable path
*/
async function prepareChromeExecutable(executablePath) {
// Special code for using the playwright_chromium
if (typeof executablePath === "string" && executablePath.toLocaleLowerCase() === "#playwright_chromium") {
@@ -121,6 +136,12 @@ async function prepareChromeExecutable(executablePath) {
return executablePath;
}
/**
* Find the chrome executable
* @param {any[]} executables Executables to search through
* @returns {any} Executable
* @throws Could not find executable
*/
function findChrome(executables) {
// Use the last working executable, so we don't have to search for it again
if (lastAutoDetectChromeExecutable) {
@@ -138,6 +159,10 @@ function findChrome(executables) {
throw new Error("Chromium not found, please specify Chromium executable path in the settings page.");
}
/**
* Reset chrome
* @returns {Promise<void>}
*/
async function resetChrome() {
if (browser) {
await browser.close();
@@ -147,8 +172,8 @@ async function resetChrome() {
/**
* Test if the chrome executable is valid and return the version
* @param executablePath
* @returns {Promise<string>}
* @param {string} executablePath Path to executable
* @returns {Promise<string>} Chrome version
*/
async function testChrome(executablePath) {
try {
@@ -175,6 +200,9 @@ class RealBrowserMonitorType extends MonitorType {
name = "real-browser";
/**
* @inheritdoc
*/
async check(monitor, heartbeat, server) {
const browser = await getBrowser();
const context = await browser.newContext();

View File

@@ -13,9 +13,9 @@ class TailscalePing extends MonitorType {
/**
* Checks the ping status of the URL associated with the monitor.
* It then parses the Tailscale ping command output to update the heatrbeat.
*
* @param {Object} monitor - The monitor object associated with the check.
* @param {Object} heartbeat - The heartbeat object to update.
* @param {object} monitor The monitor object associated with the check.
* @param {object} heartbeat The heartbeat object to update.
* @returns {Promise<void>}
* @throws Will throw an error if checking Tailscale ping encounters any error
*/
async check(monitor, heartbeat) {
@@ -31,9 +31,9 @@ class TailscalePing extends MonitorType {
/**
* Runs the Tailscale ping command to the given URL.
*
* @param {string} hostname - The hostname to ping.
* @returns {Promise<string>} - A Promise that resolves to the output of the Tailscale ping command
* @param {string} hostname The hostname to ping.
* @param {number} interval Interval to send ping
* @returns {Promise<string>} A Promise that resolves to the output of the Tailscale ping command
* @throws Will throw an error if the command execution encounters any error.
*/
async runTailscalePing(hostname, interval) {
@@ -61,9 +61,9 @@ class TailscalePing extends MonitorType {
/**
* Parses the output of the Tailscale ping command to update the heartbeat.
*
* @param {string} tailscaleOutput - The output of the Tailscale ping command.
* @param {Object} heartbeat - The heartbeat object to update.
* @param {string} tailscaleOutput The output of the Tailscale ping command.
* @param {object} heartbeat The heartbeat object to update.
* @returns {void}
* @throws Will throw an eror if the output contains any unexpected string.
*/
parseTailscaleOutput(tailscaleOutput, heartbeat) {

View File

@@ -6,6 +6,9 @@ class Alerta extends NotificationProvider {
name = "alerta";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -7,6 +7,9 @@ class AlertNow extends NotificationProvider {
name = "AlertNow";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -7,6 +7,9 @@ const qs = require("qs");
class AliyunSMS extends NotificationProvider {
name = "AliyunSMS";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
@@ -78,9 +81,9 @@ class AliyunSMS extends NotificationProvider {
/**
* Aliyun request sign
* @param {Object} param Parameters object to sign
* @param {object} param Parameters object to sign
* @param {string} AccessKeySecret Secret key to sign parameters with
* @returns {string}
* @returns {string} Base64 encoded request
*/
sign(param, AccessKeySecret) {
let param2 = {};
@@ -122,7 +125,7 @@ class AliyunSMS extends NotificationProvider {
/**
* Convert status constant to string
* @param {const} status The status constant
* @returns {string}
* @returns {string} Status
*/
statusToString(status) {
switch (status) {

View File

@@ -5,6 +5,9 @@ class Apprise extends NotificationProvider {
name = "apprise";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const args = [ "-vv", "-b", msg, notification.appriseURL ];
if (notification.title) {

View File

@@ -18,6 +18,9 @@ const successMessage = "Successes!";
class Bark extends NotificationProvider {
name = "Bark";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let barkEndpoint = notification.barkEndpoint;
@@ -45,8 +48,9 @@ class Bark extends NotificationProvider {
/**
* Add additional parameter for better on device styles (iOS 15
* optimized)
* @param {BeanModel} notification Notification to send
* @param {string} postUrl URL to append parameters to
* @returns {string}
* @returns {string} Additional URL parameters
*/
appendAdditionalParameters(notification, postUrl) {
// set icon to uptime kuma icon, 11kb should be fine
@@ -70,7 +74,8 @@ class Bark extends NotificationProvider {
/**
* Check if result is successful
* @param {Object} result Axios response object
* @param {object} result Axios response object
* @returns {void}
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
@@ -84,10 +89,11 @@ class Bark extends NotificationProvider {
/**
* Send the message
* @param {BeanModel} notification Notification to send
* @param {string} title Message title
* @param {string} subtitle Message
* @param {string} endpoint Endpoint to send request to
* @returns {string}
* @returns {string} Success message
*/
async postNotification(notification, title, subtitle, endpoint) {
// url encode title and subtitle

View File

@@ -5,6 +5,9 @@ class ClickSendSMS extends NotificationProvider {
name = "clicksendsms";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -6,6 +6,9 @@ const Crypto = require("crypto");
class DingDing extends NotificationProvider {
name = "DingDing";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
@@ -39,8 +42,8 @@ class DingDing extends NotificationProvider {
/**
* Send message to DingDing
* @param {BeanModel} notification
* @param {Object} params Parameters of message
* @param {BeanModel} notification Notification to send
* @param {object} params Parameters of message
* @returns {boolean} True if successful else false
*/
async sendToDingDing(notification, params) {
@@ -66,7 +69,7 @@ class DingDing extends NotificationProvider {
* DingDing sign
* @param {Date} timestamp Timestamp of message
* @param {string} secretKey Secret key to sign data with
* @returns {string}
* @returns {string} Base64 encoded signature
*/
sign(timestamp, secretKey) {
return Crypto
@@ -78,7 +81,7 @@ class DingDing extends NotificationProvider {
/**
* Convert status constant to string
* @param {const} status The status constant
* @returns {string}
* @returns {string} Status
*/
statusToString(status) {
// TODO: Move to notification-provider.js to avoid repetition in classes

View File

@@ -6,6 +6,9 @@ class Discord extends NotificationProvider {
name = "discord";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ const { DOWN, UP } = require("../../src/util");
class Feishu extends NotificationProvider {
name = "Feishu";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let feishuWebHookUrl = notification.feishuWebHookUrl;

View File

@@ -7,6 +7,9 @@ const successMessage = "Sent Successfully.";
class FlashDuty extends NotificationProvider {
name = "FlashDuty";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
if (heartbeatJSON == null) {
@@ -33,12 +36,12 @@ class FlashDuty extends NotificationProvider {
this.throwGeneralAxiosError(error);
}
}
/**
* Generate a monitor url from the monitors infomation
* @param {Object} monitorInfo Monitor details
* @returns {string|undefined}
* @param {object} monitorInfo Monitor details
* @returns {string|undefined} Monitor URL
*/
genMonitorUrl(monitorInfo) {
if (monitorInfo.type === "port" && monitorInfo.port) {
return monitorInfo.hostname + ":" + monitorInfo.port;
@@ -54,9 +57,9 @@ class FlashDuty extends NotificationProvider {
* @param {BeanModel} notification Message title
* @param {string} title Message
* @param {string} body Message
* @param {Object} monitorInfo Monitor details
* @param {object} monitorInfo Monitor details
* @param {string} eventStatus Monitor status (Info, Warning, Critical, Ok)
* @returns {string}
* @returns {string} Success message
*/
async postNotification(notification, title, body, monitorInfo, eventStatus) {
const options = {

View File

@@ -5,6 +5,9 @@ class FreeMobile extends NotificationProvider {
name = "FreeMobile";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -6,6 +6,9 @@ class GoAlert extends NotificationProvider {
name = "GoAlert";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -8,6 +8,9 @@ class GoogleChat extends NotificationProvider {
name = "GoogleChat";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -5,6 +5,9 @@ class Gorush extends NotificationProvider {
name = "gorush";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class Gotify extends NotificationProvider {
name = "gotify";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -6,6 +6,9 @@ const defaultNotificationService = "notify";
class HomeAssistant extends NotificationProvider {
name = "HomeAssistant";
/**
* @inheritdoc
*/
async send(notification, message, monitor = null, heartbeat = null) {
const notificationService = notification?.notificationService || defaultNotificationService;

View File

@@ -5,6 +5,9 @@ class Kook extends NotificationProvider {
name = "Kook";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let url = "https://www.kookapp.cn/api/v3/message/create";

View File

@@ -6,6 +6,9 @@ class Line extends NotificationProvider {
name = "line";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -7,6 +7,9 @@ class LineNotify extends NotificationProvider {
name = "LineNotify";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -6,6 +6,9 @@ class LunaSea extends NotificationProvider {
name = "lunasea";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let lunaseaurl = "";

View File

@@ -6,6 +6,9 @@ const { log } = require("../../src/util");
class Matrix extends NotificationProvider {
name = "matrix";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -6,6 +6,9 @@ class Mattermost extends NotificationProvider {
name = "mattermost";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -33,6 +33,9 @@ if (semver.lt(nodeVersion, "16.0.0")) {
class Nostr extends NotificationProvider {
name = "nostr";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
// All DMs should have same timestamp
const createdAt = Math.floor(Date.now() / 1000);
@@ -86,6 +89,11 @@ class Nostr extends NotificationProvider {
return `${successfulRelays}/${relays.length} relays connected.`;
}
/**
* Get the private key for the sender
* @param {string} sender Sender to retrieve key for
* @returns {nip19.DecodeResult} Private key
*/
async getPrivateKey(sender) {
try {
const senderDecodeResult = await nip19.decode(sender);
@@ -96,6 +104,11 @@ class Nostr extends NotificationProvider {
}
}
/**
* Get public keys for recipients
* @param {string} recipients Newline delimited list of recipients
* @returns {nip19.DecodeResult[]} Public keys
*/
async getPublicKeys(recipients) {
const recipientsList = recipients.split("\n");
const publicKeys = [];

View File

@@ -2,16 +2,16 @@ class NotificationProvider {
/**
* Notification Provider Name
* @type string
* @type {string}
*/
name = undefined;
/**
* Send a notification
* @param {BeanModel} notification
* @param {BeanModel} notification Notification to send
* @param {string} msg General Message
* @param {?Object} monitorJSON Monitor details (For Up/Down only)
* @param {?Object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {?object} monitorJSON Monitor details (For Up/Down only)
* @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
* @returns {Promise<string>} Return Successful Message
* @throws Error with fail msg
*/
@@ -22,6 +22,7 @@ class NotificationProvider {
/**
* Throws an error
* @param {any} error The error to throw
* @returns {void}
* @throws {any} The error specified
*/
throwGeneralAxiosError(error) {

View File

@@ -6,6 +6,9 @@ class Ntfy extends NotificationProvider {
name = "ntfy";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -5,6 +5,9 @@ class Octopush extends NotificationProvider {
name = "octopush";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class OneBot extends NotificationProvider {
name = "OneBot";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -68,11 +68,11 @@ class Opsgenie extends NotificationProvider {
}
/**
*
* @param {BeanModel} notification
* Make POST request to Opsgenie
* @param {BeanModel} notification Notification to send
* @param {string} url Request url
* @param {Object} data Request body
* @returns {Promise<string>}
* @param {object} data Request body
* @returns {Promise<string>} Success message
*/
async post(notification, url, data) {
let config = {

View File

@@ -39,7 +39,8 @@ class PagerDuty extends NotificationProvider {
/**
* Check if result is successful, result code should be in range 2xx
* @param {Object} result Axios response object
* @param {object} result Axios response object
* @returns {void}
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
@@ -56,9 +57,9 @@ class PagerDuty extends NotificationProvider {
* @param {BeanModel} notification Message title
* @param {string} title Message title
* @param {string} body Message
* @param {Object} monitorInfo Monitor details (For Up/Down only)
* @param {object} monitorInfo Monitor details (For Up/Down only)
* @param {?string} eventAction Action event for PagerDuty (trigger, acknowledge, resolve)
* @returns {string}
* @returns {Promise<string>} Success message
*/
async postNotification(notification, title, body, monitorInfo, eventAction = "trigger") {

View File

@@ -32,7 +32,8 @@ class PagerTree extends NotificationProvider {
/**
* Check if result is successful, result code should be in range 2xx
* @param {Object} result Axios response object
* @param {object} result Axios response object
* @returns {void}
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
@@ -48,9 +49,10 @@ class PagerTree extends NotificationProvider {
* Send the message
* @param {BeanModel} notification Message title
* @param {string} title Message title
* @param {Object} monitorJSON Monitor details (For Up/Down only)
* @param {object} monitorJSON Monitor details (For Up/Down only)
* @param {object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {?string} eventAction Action event for PagerTree (create, resolve)
* @returns {string}
* @returns {Promise<string>} Success state
*/
async postNotification(notification, title, monitorJSON, heartbeatJSON, eventAction = "create") {

View File

@@ -5,6 +5,9 @@ class PromoSMS extends NotificationProvider {
name = "promosms";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -7,6 +7,9 @@ class Pushbullet extends NotificationProvider {
name = "pushbullet";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -6,6 +6,9 @@ class PushDeer extends NotificationProvider {
name = "PushDeer";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let endpoint = "/message/push";

View File

@@ -5,6 +5,9 @@ class Pushover extends NotificationProvider {
name = "pushover";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let pushoverlink = "https://api.pushover.net/1/messages.json";

View File

@@ -5,6 +5,9 @@ class Pushy extends NotificationProvider {
name = "pushy";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -8,6 +8,9 @@ class RocketChat extends NotificationProvider {
name = "rocket.chat";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -6,6 +6,9 @@ class ServerChan extends NotificationProvider {
name = "ServerChan";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
@@ -23,8 +26,8 @@ class ServerChan extends NotificationProvider {
/**
* Get the formatted title for message
* @param {?Object} monitorJSON Monitor details (For Up/Down only)
* @param {?Object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {?object} monitorJSON Monitor details (For Up/Down only)
* @returns {string} Formatted title
*/
checkStatus(heartbeatJSON, monitorJSON) {

View File

@@ -5,6 +5,9 @@ class SerwerSMS extends NotificationProvider {
name = "serwersms";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class Signal extends NotificationProvider {
name = "signal";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -10,7 +10,9 @@ class Slack extends NotificationProvider {
/**
* Deprecated property notification.slackbutton
* Set it as primary base url if this is not yet set.
* @deprecated
* @param {string} url The primary base URL to use
* @returns {Promise<void>}
*/
static async deprecateURL(url) {
let currentPrimaryBaseURL = await setting("primaryBaseURL");
@@ -25,6 +27,9 @@ class Slack extends NotificationProvider {
}
}
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -4,6 +4,9 @@ const axios = require("axios");
class SMSC extends NotificationProvider {
name = "smsc";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -5,6 +5,9 @@ class SMSEagle extends NotificationProvider {
name = "SMSEagle";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class SMSManager extends NotificationProvider {
name = "SMSManager";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
let data = {

View File

@@ -6,6 +6,9 @@ class SMTP extends NotificationProvider {
name = "smtp";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const config = {

View File

@@ -37,7 +37,8 @@ class Splunk extends NotificationProvider {
/**
* Check if result is successful, result code should be in range 2xx
* @param {Object} result Axios response object
* @param {object} result Axios response object
* @returns {void}
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
@@ -54,9 +55,9 @@ class Splunk extends NotificationProvider {
* @param {BeanModel} notification Message title
* @param {string} title Message title
* @param {string} body Message
* @param {Object} monitorInfo Monitor details (For Up/Down only)
* @param {object} monitorInfo Monitor details (For Up/Down only)
* @param {?string} eventAction Action event for PagerDuty (trigger, acknowledge, resolve)
* @returns {string}
* @returns {Promise<string>} Success state
*/
async postNotification(notification, title, body, monitorInfo, eventAction = "trigger") {

View File

@@ -6,6 +6,9 @@ class Squadcast extends NotificationProvider {
name = "squadcast";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -7,6 +7,9 @@ class Stackfield extends NotificationProvider {
name = "stackfield";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null) {
let okMsg = "Sent Successfully.";
try {

View File

@@ -9,7 +9,7 @@ class Teams extends NotificationProvider {
* Generate the message to send
* @param {const} status The status constant
* @param {string} monitorName Name of monitor
* @returns {string}
* @returns {string} Status message
*/
_statusMessageFactory = (status, monitorName) => {
if (status === DOWN) {
@@ -37,11 +37,12 @@ class Teams extends NotificationProvider {
/**
* Generate payload for notification
* @param {const} status The status of the monitor
* @param {string} monitorMessage Message to send
* @param {string} monitorName Name of monitor affected
* @param {string} monitorUrl URL of monitor affected
* @returns {Object}
* @param {object} args Method arguments
* @param {const} args.status The status of the monitor
* @param {string} args.monitorMessage Message to send
* @param {string} args.monitorName Name of monitor affected
* @param {string} args.monitorUrl URL of monitor affected
* @returns {object} Notification payload
*/
_notificationPayloadFactory = ({
status,
@@ -96,7 +97,8 @@ class Teams extends NotificationProvider {
/**
* Send the notification
* @param {string} webhookUrl URL to send the request to
* @param {Object} payload Payload generated by _notificationPayloadFactory
* @param {object} payload Payload generated by _notificationPayloadFactory
* @returns {Promise<void>}
*/
_sendNotification = async (webhookUrl, payload) => {
await axios.post(webhookUrl, payload);
@@ -116,6 +118,9 @@ class Teams extends NotificationProvider {
return this._sendNotification(webhookUrl, payload);
};
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class TechulusPush extends NotificationProvider {
name = "PushByTechulus";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class Telegram extends NotificationProvider {
name = "telegram";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -5,6 +5,9 @@ class Twilio extends NotificationProvider {
name = "twilio";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -7,6 +7,9 @@ class Webhook extends NotificationProvider {
name = "webhook";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -6,6 +6,9 @@ class WeCom extends NotificationProvider {
name = "WeCom";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
@@ -26,9 +29,9 @@ class WeCom extends NotificationProvider {
/**
* Generate the message to send
* @param {Object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {string} msg General message
* @returns {Object}
* @returns {object} Message
*/
composeMessage(heartbeatJSON, msg) {
let title;

View File

@@ -10,7 +10,7 @@ class ZohoCliq extends NotificationProvider {
* Generate the message to send
* @param {const} status The status constant
* @param {string} monitorName Name of monitor
* @returns {string}
* @returns {string} Status message
*/
_statusMessageFactory = (status, monitorName) => {
if (status === DOWN) {
@@ -25,6 +25,7 @@ class ZohoCliq extends NotificationProvider {
* Send the notification
* @param {string} webhookUrl URL to send the request to
* @param {Array} payload Payload generated by _notificationPayloadFactory
* @returns {Promise<void>}
*/
_sendNotification = async (webhookUrl, payload) => {
await axios.post(webhookUrl, { text: payload.join("\n") });
@@ -32,11 +33,12 @@ class ZohoCliq extends NotificationProvider {
/**
* Generate payload for notification
* @param {const} status The status of the monitor
* @param {string} monitorMessage Message to send
* @param {string} monitorName Name of monitor affected
* @param {string} monitorUrl URL of monitor affected
* @returns {Array}
* @param {object} args Method arguments
* @param {const} args.status The status of the monitor
* @param {string} args.monitorMessage Message to send
* @param {string} args.monitorName Name of monitor affected
* @param {string} args.monitorUrl URL of monitor affected
* @returns {Array} Notification payload
*/
_notificationPayloadFactory = ({
status,
@@ -74,6 +76,9 @@ class ZohoCliq extends NotificationProvider {
return this._sendNotification(webhookUrl, payload);
};
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";

View File

@@ -58,7 +58,12 @@ class Notification {
providerList = {};
/** Initialize the notification providers */
/**
* Initialize the notification providers
* @returns {void}
* @throws Notification provider does not have a name
* @throws Duplicate notification providers in list
*/
static init() {
log.info("notification", "Prepare Notification Providers");
@@ -133,10 +138,10 @@ class Notification {
/**
* Send a notification
* @param {BeanModel} notification
* @param {BeanModel} notification Notification to send
* @param {string} msg General Message
* @param {Object} monitorJSON Monitor details (For Up/Down only)
* @param {Object} heartbeatJSON Heartbeat details (For Up/Down only)
* @param {object} monitorJSON Monitor details (For Up/Down only)
* @param {object} heartbeatJSON Heartbeat details (For Up/Down only)
* @returns {Promise<string>} Successful msg
* @throws Error with fail msg
*/
@@ -150,10 +155,10 @@ class Notification {
/**
* Save a notification
* @param {Object} notification Notification to save
* @param {object} notification Notification to save
* @param {?number} notificationID ID of notification to update
* @param {number} userID ID of user who adds notification
* @returns {Promise<Bean>}
* @returns {Promise<Bean>} Notification that was saved
*/
static async save(notification, notificationID, userID) {
let bean;

View File

@@ -4,8 +4,8 @@ const saltRounds = 10;
/**
* Hash a password
* @param {string} password
* @returns {string}
* @param {string} password Password to hash
* @returns {string} Hash
*/
exports.generate = function (password) {
return bcrypt.hashSync(password, saltRounds);
@@ -13,8 +13,8 @@ exports.generate = function (password) {
/**
* Verify a password against a hash
* @param {string} password
* @param {string} hash
* @param {string} password Password to verify
* @param {string} hash Hash to verify against
* @returns {boolean} Does the password match the hash?
*/
exports.verify = function (password, hash) {
@@ -27,8 +27,8 @@ exports.verify = function (password, hash) {
/**
* Is the hash a SHA1 hash
* @param {string} hash
* @returns {boolean}
* @param {string} hash Hash to check
* @returns {boolean} Is SHA1 hash?
*/
function isSHA1(hash) {
return (typeof hash === "string" && hash.startsWith("sha1"));
@@ -36,7 +36,8 @@ function isSHA1(hash) {
/**
* Does the hash need to be rehashed?
* @returns {boolean}
* @param {string} hash Hash to check
* @returns {boolean} Needs to be rehashed?
*/
exports.needRehash = function (hash) {
return isSHA1(hash);

View File

@@ -36,7 +36,7 @@ class Prometheus {
monitorLabelValues = {};
/**
* @param {Object} monitor Monitor object to monitor
* @param {object} monitor Monitor object to monitor
*/
constructor(monitor) {
this.monitorLabelValues = {
@@ -50,8 +50,9 @@ class Prometheus {
/**
* Update the metrics page
* @param {Object} heartbeat Heartbeat details
* @param {Object} tlsInfo TLS details
* @param {object} heartbeat Heartbeat details
* @param {object} tlsInfo TLS details
* @returns {void}
*/
update(heartbeat, tlsInfo) {
@@ -99,7 +100,10 @@ class Prometheus {
}
}
/** Remove monitor from prometheus */
/**
* Remove monitor from prometheus
* @returns {void}
*/
remove() {
try {
monitorCertDaysRemaining.remove(this.monitorLabelValues);

View File

@@ -11,11 +11,10 @@ class Proxy {
/**
* Saves and updates given proxy entity
*
* @param proxy
* @param proxyID
* @param userID
* @return {Promise<Bean>}
* @param {object} proxy Proxy to store
* @param {number} proxyID ID of proxy to update
* @param {number} userID ID of user the proxy belongs to
* @returns {Promise<Bean>} Updated proxy
*/
static async save(proxy, proxyID, userID) {
let bean;
@@ -65,10 +64,9 @@ class Proxy {
/**
* Deletes proxy with given id and removes it from monitors
*
* @param proxyID
* @param userID
* @return {Promise<void>}
* @param {number} proxyID ID of proxy to delete
* @param {number} userID ID of proxy owner
* @returns {Promise<void>}
*/
static async delete(proxyID, userID) {
const bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]);
@@ -86,10 +84,10 @@ class Proxy {
/**
* Create HTTP and HTTPS agents related with given proxy bean object
*
* @param proxy proxy bean object
* @param options http and https agent options
* @return {{httpAgent: Agent, httpsAgent: Agent}}
* @param {object} proxy proxy bean object
* @param {object} options http and https agent options
* @returns {{httpAgent: Agent, httpsAgent: Agent}} New HTTP and HTTPS agents
* @throws Proxy protocol is unsupported
*/
static createAgents(proxy, options) {
const { httpAgentOptions, httpsAgentOptions } = options || {};
@@ -171,10 +169,9 @@ class Proxy {
/**
* Applies given proxy id to monitors
*
* @param proxyID
* @param userID
* @return {Promise<void>}
* @param {number} proxyID ID of proxy to apply
* @param {number} userID ID of proxy owner
* @returns {Promise<void>}
*/
async function applyProxyEveryMonitor(proxyID, userID) {
// Find all monitors with id and proxy id

View File

@@ -3,7 +3,7 @@ const { log } = require("../src/util");
class KumaRateLimiter {
/**
* @param {Object} config Rate limiter configuration object
* @param {object} config Rate limiter configuration object
*/
constructor(config) {
this.errorMessage = config.errorMessage;
@@ -13,14 +13,14 @@ class KumaRateLimiter {
/**
* Callback for pass
* @callback passCB
* @param {Object} err Too many requests
* @param {object} err Too many requests
*/
/**
* Should the request be passed through
* @param {passCB} callback
* @param {number} [num=1] Number of tokens to remove
* @returns {Promise<boolean>}
* @param {passCB} callback Callback function to call with decision
* @param {number} num Number of tokens to remove
* @returns {Promise<boolean>} Should the request be allowed?
*/
async pass(callback, num = 1) {
const remainingRequests = await this.removeTokens(num);
@@ -39,8 +39,8 @@ class KumaRateLimiter {
/**
* Remove a given number of tokens
* @param {number} [num=1] Number of tokens to remove
* @returns {Promise<number>}
* @param {number} num Number of tokens to remove
* @returns {Promise<number>} Number of remaining tokens
*/
async removeTokens(num = 1) {
return await this.rateLimiter.removeTokens(num);

View File

@@ -1699,8 +1699,8 @@ async function updateMonitorNotification(monitorID, notificationIDList) {
/**
* Check if a given user owns a specific monitor
* @param {number} userID
* @param {number} monitorID
* @param {number} userID ID of user to check
* @param {number} monitorID ID of monitor to check
* @returns {Promise<void>}
* @throws {Error} The specified user does not own the monitor
*/
@@ -1719,7 +1719,7 @@ async function checkOwner(userID, monitorID) {
* Function called after user login
* This function is used to send the heartbeat list of a monitor.
* @param {Socket} socket Socket.io instance
* @param {Object} user User object
* @param {object} user User object
* @returns {Promise<void>}
*/
async function afterLogin(socket, user) {
@@ -1760,7 +1760,7 @@ async function afterLogin(socket, user) {
/**
* Initialize the database
* @param {boolean} [testMode=false] Should the connection be
* @param {boolean} testMode Should the connection be
* started in test mode?
* @returns {Promise<void>}
*/
@@ -1852,7 +1852,10 @@ async function pauseMonitor(userID, monitorID) {
}
}
/** Resume active monitors */
/**
* Resume active monitors
* @returns {Promise<void>}
*/
async function startMonitors() {
let list = await R.find("monitor", " active = 1 ");
@@ -1896,7 +1899,10 @@ async function shutdownFunction(signal) {
Settings.stopCacheCleaner();
}
/** Final function called before application exits */
/**
* Final function called before application exits
* @returns {void}
*/
function finalFunction() {
log.info("server", "Graceful shutdown successful!");
}

View File

@@ -96,7 +96,7 @@ class Settings {
/**
* Get settings based on type
* @param {string} type The type of setting
* @returns {Promise<Bean>}
* @returns {Promise<Bean>} Settings
*/
static async getSettings(type) {
let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
@@ -119,7 +119,7 @@ class Settings {
/**
* Set settings based on type
* @param {string} type Type of settings to set
* @param {Object} data Values of settings
* @param {object} data Values of settings
* @returns {Promise<void>}
*/
static async setSettings(type, data) {
@@ -150,8 +150,9 @@ class Settings {
}
/**
*
* @param {string[]} keyList
* Delete selected keys from settings cache
* @param {string[]} keyList Keys to remove
* @returns {void}
*/
static deleteCache(keyList) {
for (let key of keyList) {
@@ -159,6 +160,10 @@ class Settings {
}
}
/**
* Stop the cache cleaner if running
* @returns {void}
*/
static stopCacheCleaner() {
if (Settings.cacheCleaner) {
clearInterval(Settings.cacheCleaner);

View File

@@ -9,8 +9,9 @@ const { Settings } = require("../settings");
const { sendAPIKeyList } = require("../client");
/**
* Handlers for Maintenance
* Handlers for API keys
* @param {Socket} socket Socket.io instance
* @returns {void}
*/
module.exports.apiKeySocketHandler = (socket) => {
// Add a new api key

View File

@@ -11,6 +11,7 @@ const cloudflared = new CloudflaredTunnel();
* Change running state
* @param {string} running Is it running?
* @param {string} message Message to pass
* @returns {void}
*/
cloudflared.change = (running, message) => {
io.to("cloudflared").emit(prefix + "running", running);
@@ -19,7 +20,8 @@ cloudflared.change = (running, message) => {
/**
* Emit an error message
* @param {string} errorMessage
* @param {string} errorMessage Error message to send
* @returns {void}
*/
cloudflared.error = (errorMessage) => {
io.to("cloudflared").emit(prefix + "errorMessage", errorMessage);
@@ -28,6 +30,7 @@ cloudflared.error = (errorMessage) => {
/**
* Handler for cloudflared
* @param {Socket} socket Socket.io instance
* @returns {void}
*/
module.exports.cloudflaredSocketHandler = (socket) => {
@@ -89,6 +92,7 @@ module.exports.cloudflaredSocketHandler = (socket) => {
/**
* Automatically start cloudflared
* @param {string} token Cloudflared tunnel token
* @returns {Promise<void>}
*/
module.exports.autoStart = async (token) => {
if (!token) {
@@ -106,7 +110,10 @@ module.exports.autoStart = async (token) => {
}
};
/** Stop cloudflared */
/**
* Stop cloudflared
* @returns {Promise<void>}
*/
module.exports.stop = async () => {
log.info("cloudflared", "Stop cloudflared");
if (cloudflared) {

View File

@@ -4,6 +4,7 @@ const Database = require("../database");
/**
* Handlers for database
* @param {Socket} socket Socket.io instance
* @returns {void}
*/
module.exports = (socket) => {

View File

@@ -6,6 +6,7 @@ const { log } = require("../../src/util");
/**
* Handlers for docker hosts
* @param {Socket} socket Socket.io instance
* @returns {void}
*/
module.exports.dockerSocketHandler = (socket) => {
socket.on("addDockerHost", async (dockerHost, dockerHostID, callback) => {

View File

@@ -10,7 +10,7 @@ let gameList = null;
/**
* Get a game list via GameDig
* @returns {Object[]} list of games supported by GameDig
* @returns {object[]} list of games supported by GameDig
*/
function getGameList() {
if (gameList == null) {

View File

@@ -9,6 +9,7 @@ const server = UptimeKumaServer.getInstance();
/**
* Handlers for Maintenance
* @param {Socket} socket Socket.io instance
* @returns {void}
*/
module.exports.maintenanceSocketHandler = (socket) => {
// Add a new maintenance

View File

@@ -7,6 +7,7 @@ const server = UptimeKumaServer.getInstance();
/**
* Handlers for proxy
* @param {Socket} socket Socket.io instance
* @returns {void}
*/
module.exports.proxySocketHandler = (socket) => {
socket.on("addProxy", async (proxy, proxyID, callback) => {

View File

@@ -11,6 +11,7 @@ const { UptimeKumaServer } = require("../uptime-kuma-server");
/**
* Socket handlers for status page
* @param {Socket} socket Socket.io instance to add listeners on
* @returns {void}
*/
module.exports.statusPageSocketHandler = (socket) => {
@@ -350,6 +351,8 @@ module.exports.statusPageSocketHandler = (socket) => {
* Check slug a-z, 0-9, - only
* Regex from: https://stackoverflow.com/questions/22454258/js-regex-string-validation-for-slug
* @param {string} slug Slug to test
* @returns {void}
* @throws Slug is not valid
*/
function checkSlug(slug) {
if (typeof slug !== "string") {

View File

@@ -7,9 +7,9 @@ class UptimeCacheList {
/**
* Get the uptime for a specific period
* @param {number} monitorID
* @param {number} duration
* @return {number}
* @param {number} monitorID ID of monitor to query
* @param {number} duration Duration to query
* @returns {(number|null)} Uptime for provided duration, if it exists
*/
static getUptime(monitorID, duration) {
if (UptimeCacheList.list[monitorID] && UptimeCacheList.list[monitorID][duration]) {
@@ -22,9 +22,10 @@ class UptimeCacheList {
/**
* Add uptime for specified monitor
* @param {number} monitorID
* @param {number} duration
* @param {number} monitorID ID of monitor to insert for
* @param {number} duration Duration to insert for
* @param {number} uptime Uptime to add
* @returns {void}
*/
static addUptime(monitorID, duration, uptime) {
log.debug("UptimeCacheList", "addUptime: " + monitorID + " " + duration);
@@ -36,7 +37,8 @@ class UptimeCacheList {
/**
* Clear cache for specified monitor
* @param {number} monitorID
* @param {number} monitorID ID of monitor to clear
* @returns {void}
*/
static clearCache(monitorID) {
log.debug("UptimeCacheList", "clearCache: " + monitorID);

View File

@@ -20,7 +20,7 @@ const path = require("path");
*/
class UptimeKumaServer {
/**
*
* Current server instance
* @type {UptimeKumaServer}
*/
static instance = null;
@@ -49,7 +49,6 @@ class UptimeKumaServer {
indexHTML = "";
/**
*
* @type {{}}
*/
static monitorTypeList = {
@@ -62,6 +61,12 @@ class UptimeKumaServer {
*/
jwtSecret = null;
/**
* Get the current instance of the server if it exists, otherwise
* create a new instance.
* @param {object} args Arguments to pass to instance constructor
* @returns {UptimeKumaServer} Server instance
*/
static getInstance(args) {
if (UptimeKumaServer.instance == null) {
UptimeKumaServer.instance = new UptimeKumaServer(args);
@@ -69,6 +74,9 @@ class UptimeKumaServer {
return UptimeKumaServer.instance;
}
/**
* @param {object} args Arguments to initialise server with
*/
constructor(args) {
// SSL
const sslKey = args["ssl-key"] || process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined;
@@ -106,7 +114,10 @@ class UptimeKumaServer {
this.io = new Server(this.httpServer);
}
/** Initialise app after the database has been set up */
/**
* Initialise app after the database has been set up
* @returns {Promise<void>}
*/
async initAfterDatabaseReady() {
// Static
this.app.use("/screenshots", express.static(Database.screenshotDir));
@@ -123,8 +134,8 @@ class UptimeKumaServer {
/**
* Send list of monitors to client
* @param {Socket} socket
* @returns {Object} List of monitors
* @param {Socket} socket Socket to send list on
* @returns {object} List of monitors
*/
async sendMonitorList(socket) {
let list = await this.getMonitorJSONList(socket.userID);
@@ -135,7 +146,7 @@ class UptimeKumaServer {
/**
* Get a list of monitors for the given user.
* @param {string} userID - The ID of the user to get monitors for.
* @returns {Promise<Object>} A promise that resolves to an object with monitor IDs as keys and monitor objects as values.
* @returns {Promise<object>} A promise that resolves to an object with monitor IDs as keys and monitor objects as values.
*
* Generated by Trelent
*/
@@ -156,7 +167,7 @@ class UptimeKumaServer {
/**
* Send maintenance list to client
* @param {Socket} socket Socket.io instance to send to
* @returns {Object}
* @returns {object} Maintenance list
*/
async sendMaintenanceList(socket) {
return await this.sendMaintenanceListByUserID(socket.userID);
@@ -164,8 +175,8 @@ class UptimeKumaServer {
/**
* Send list of maintenances to user
* @param {number} userID
* @returns {Object}
* @param {number} userID User to send list to
* @returns {object} Maintenance list
*/
async sendMaintenanceListByUserID(userID) {
let list = await this.getMaintenanceJSONList(userID);
@@ -176,7 +187,7 @@ class UptimeKumaServer {
/**
* Get a list of maintenances for the given user.
* @param {string} userID - The ID of the user to get maintenances for.
* @returns {Promise<Object>} A promise that resolves to an object with maintenance IDs as keys and maintenances objects as values.
* @returns {Promise<object>} A promise that resolves to an object with maintenance IDs as keys and maintenances objects as values.
*/
async getMaintenanceJSONList(userID) {
let result = {};
@@ -188,7 +199,7 @@ class UptimeKumaServer {
/**
* Load maintenance list and run
* @param userID
* @param {any} userID Unused
* @returns {Promise<void>}
*/
async loadMaintenanceList(userID) {
@@ -202,6 +213,11 @@ class UptimeKumaServer {
}
}
/**
* Retrieve a specific maintenance
* @param {number} maintenanceID ID of maintenance to retrieve
* @returns {(object|null)} Maintenance if it exists
*/
getMaintenance(maintenanceID) {
if (this.maintenanceList[maintenanceID]) {
return this.maintenanceList[maintenanceID];
@@ -213,6 +229,7 @@ class UptimeKumaServer {
* Write error to log file
* @param {any} error The error to write
* @param {boolean} outputToConsole Should the error also be output to console?
* @returns {void}
*/
static errorLog(error, outputToConsole = true) {
const errorLogStream = fs.createWriteStream(path.join(Database.dataDir, "/error.log"), {
@@ -237,8 +254,8 @@ class UptimeKumaServer {
/**
* Get the IP of the client connected to the socket
* @param {Socket} socket
* @returns {string}
* @param {Socket} socket Socket to query
* @returns {string} IP of client
*/
async getClientIP(socket) {
let clientIP = socket.client.conn.remoteAddress;
@@ -262,7 +279,7 @@ class UptimeKumaServer {
* Attempt to get the current server timezone
* If this fails, fall back to environment variables and then make a
* guess.
* @returns {Promise<string>}
* @returns {Promise<string>} Current timezone
*/
async getTimezone() {
// From process.env.TZ
@@ -307,7 +324,7 @@ class UptimeKumaServer {
/**
* Get the current offset
* @returns {string}
* @returns {string} Time offset
*/
getTimezoneOffset() {
return dayjs().format("Z");
@@ -315,7 +332,9 @@ class UptimeKumaServer {
/**
* Throw an error if the timezone is invalid
* @param timezone
* @param {string} timezone Timezone to test
* @returns {void}
* @throws The timezone is invalid
*/
checkTimezone(timezone) {
try {
@@ -327,7 +346,8 @@ class UptimeKumaServer {
/**
* Set the current server timezone and environment variables
* @param {string} timezone
* @param {string} timezone Timezone to set
* @returns {Promise<void>}
*/
async setTimezone(timezone) {
this.checkTimezone(timezone);
@@ -355,6 +375,7 @@ class UptimeKumaServer {
/**
* Start all system services (e.g. nscd)
* For now, only used in Docker
* @returns {void}
*/
startServices() {
if (process.env.UPTIME_KUMA_IS_CONTAINER) {
@@ -369,6 +390,7 @@ class UptimeKumaServer {
/**
* Stop all system services
* @returns {void}
*/
stopServices() {
if (process.env.UPTIME_KUMA_IS_CONTAINER) {

View File

@@ -40,7 +40,7 @@ const { Kafka, SASLOptions } = require("kafkajs");
const isWindows = process.platform === /^win/.test(process.platform);
/**
* Init or reset JWT secret
* @returns {Promise<Bean>}
* @returns {Promise<Bean>} JWT secret
*/
exports.initJWTSecret = async () => {
let jwtSecretBean = await R.findOne("setting", " `key` = ? ", [
@@ -60,7 +60,7 @@ exports.initJWTSecret = async () => {
/**
* Decodes a jwt and returns the payload portion without verifying the jqt.
* @param {string} jwt The input jwt as a string
* @returns {Object} Decoded jwt payload object
* @returns {object} Decoded jwt payload object
*/
exports.decodeJwt = (jwt) => {
return JSON.parse(Buffer.from(jwt.split(".")[1], "base64").toString());
@@ -124,7 +124,7 @@ exports.tcping = function (hostname, port) {
/**
* Ping the specified machine
* @param {string} hostname Hostname / address of machine
* @param {number} [size=56] Size of packet to send
* @param {number} size Size of packet to send
* @returns {Promise<number>} Time for ping in ms rounded to nearest integer
*/
exports.ping = async (hostname, size = 56) => {
@@ -147,7 +147,7 @@ exports.ping = async (hostname, size = 56) => {
* Ping the specified machine
* @param {string} hostname Hostname / address of machine to ping
* @param {boolean} ipv6 Should IPv6 be used?
* @param {number} [size = 56] Size of ping packet to send
* @param {number} size Size of ping packet to send
* @returns {Promise<number>} Time for ping in ms rounded to nearest integer
*/
exports.pingAsync = function (hostname, ipv6 = false, size = 56) {
@@ -179,9 +179,9 @@ exports.pingAsync = function (hostname, ipv6 = false, size = 56) {
* @param {string} hostname Hostname / address of machine to test
* @param {string} topic MQTT topic
* @param {string} okMessage Expected result
* @param {Object} [options={}] MQTT options. Contains port, username,
* @param {object} options MQTT options. Contains port, username,
* password and interval (interval defaults to 20)
* @returns {Promise<string>}
* @returns {Promise<string>} Received MQTT message
*/
exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
return new Promise((resolve, reject) => {
@@ -243,16 +243,17 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
/**
* Monitor Kafka using Producer
* @param {string[]} brokers List of kafka brokers to connect, host and
* port joined by ':'
* @param {string} topic Topic name to produce into
* @param {string} message Message to produce
* @param {Object} [options={interval = 20, allowAutoTopicCreation = false, ssl = false, clientId = "Uptime-Kuma"}]
* Kafka client options. Contains ssl, clientId, allowAutoTopicCreation and
* interval (interval defaults to 20, allowAutoTopicCreation defaults to false, clientId defaults to "Uptime-Kuma"
* and ssl defaults to false)
* @param {string[]} brokers List of kafka brokers to connect, host and port joined by ':'
* @param {SASLOptions} [saslOptions={}] Options for kafka client Authentication (SASL) (defaults to
* {})
* @returns {Promise<string>}
* @param {object} options Kafka client options. Contains ssl, clientId,
* allowAutoTopicCreation and interval (interval defaults to 20,
* allowAutoTopicCreation defaults to false, clientId defaults to
* "Uptime-Kuma" and ssl defaults to false)
* @param {SASLOptions} saslOptions Options for kafka client
* Authentication (SASL) (defaults to {})
* @returns {Promise<string>} Status message
*/
exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, saslOptions = {}) {
return new Promise((resolve, reject) => {
@@ -331,9 +332,9 @@ exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, sa
/**
* Use NTLM Auth for a http request.
* @param {Object} options The http request options
* @param {Object} ntlmOptions The auth options
* @returns {Promise<(string[]|Object[]|Object)>}
* @param {object} options The http request options
* @param {object} ntlmOptions The auth options
* @returns {Promise<(string[] | object[] | object)>} NTLM response
*/
exports.httpNtlm = function (options, ntlmOptions) {
return new Promise((resolve, reject) => {
@@ -355,7 +356,7 @@ exports.httpNtlm = function (options, ntlmOptions) {
* @param {string} resolverServer The DNS server to use
* @param {string} resolverPort Port the DNS server is listening on
* @param {string} rrtype The type of record to request
* @returns {Promise<(string[]|Object[]|Object)>}
* @returns {Promise<(string[] | object[] | object)>} DNS response
*/
exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) {
const resolver = new Resolver();
@@ -388,7 +389,8 @@ exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) {
* Run a query on SQL Server
* @param {string} connectionString The database connection string
* @param {string} query The query to validate the database with
* @returns {Promise<(string[]|Object[]|Object)>}
* @returns {Promise<(string[] | object[] | object)>} Response from
* server
*/
exports.mssqlQuery = async function (connectionString, query) {
let pool;
@@ -409,7 +411,8 @@ exports.mssqlQuery = async function (connectionString, query) {
* Run a query on Postgres
* @param {string} connectionString The database connection string
* @param {string} query The query to validate the database with
* @returns {Promise<(string[]|Object[]|Object)>}
* @returns {Promise<(string[] | object[] | object)>} Response from
* server
*/
exports.postgresQuery = function (connectionString, query) {
return new Promise((resolve, reject) => {
@@ -455,7 +458,7 @@ exports.postgresQuery = function (connectionString, query) {
* Run a query on MySQL/MariaDB
* @param {string} connectionString The database connection string
* @param {string} query The query to validate the database with
* @returns {Promise<(string)>}
* @returns {Promise<(string)>} Response from server
*/
exports.mysqlQuery = function (connectionString, query) {
return new Promise((resolve, reject) => {
@@ -486,9 +489,10 @@ exports.mysqlQuery = function (connectionString, query) {
};
/**
* Connect to and Ping a MongoDB database
* Connect to and ping a MongoDB database
* @param {string} connectionString The database connection string
* @returns {Promise<(string[]|Object[]|Object)>}
* @returns {Promise<(string[] | object[] | object)>} Response from
* server
*/
exports.mongodbPing = async function (connectionString) {
let client = await MongoClient.connect(connectionString);
@@ -510,9 +514,9 @@ exports.mongodbPing = async function (connectionString) {
* @param {string} calledStationId ID of called station
* @param {string} callingStationId ID of calling station
* @param {string} secret Secret to use
* @param {number} [port=1812] Port to contact radius server on
* @param {number} [timeout=2500] Timeout for connection to use
* @returns {Promise<any>}
* @param {number} port Port to contact radius server on
* @param {number} timeout Timeout for connection to use
* @returns {Promise<any>} Response from server
*/
exports.radius = function (
hostname,
@@ -552,6 +556,7 @@ exports.radius = function (
/**
* Redis server ping
* @param {string} dsn The redis connection string
* @returns {Promise<any>} Response from redis server
*/
exports.redisPingAsync = function (dsn) {
return new Promise((resolve, reject) => {
@@ -593,7 +598,7 @@ exports.setting = async function (key) {
};
/**
* Sets the specified setting to specifed value
* Sets the specified setting to specified value
* @param {string} key Key of setting to set
* @param {any} value Value to set to
* @param {?string} type Type of setting
@@ -606,7 +611,7 @@ exports.setSetting = async function (key, value, type = null) {
/**
* Get settings based on type
* @param {string} type The type of setting
* @returns {Promise<Bean>}
* @returns {Promise<Bean>} Settings of requested type
*/
exports.getSettings = async function (type) {
return await Settings.getSettings(type);
@@ -615,7 +620,7 @@ exports.getSettings = async function (type) {
/**
* Set settings based on type
* @param {string} type Type of settings to set
* @param {Object} data Values of settings
* @param {object} data Values of settings
* @returns {Promise<void>}
*/
exports.setSettings = async function (type, data) {
@@ -629,7 +634,7 @@ exports.setSettings = async function (type, data) {
* Get number of days between two dates
* @param {Date} validFrom Start date
* @param {Date} validTo End date
* @returns {number}
* @returns {number} Number of days
*/
const getDaysBetween = (validFrom, validTo) =>
Math.round(Math.abs(+validFrom - +validTo) / 8.64e7);
@@ -638,7 +643,7 @@ const getDaysBetween = (validFrom, validTo) =>
* Get days remaining from a time range
* @param {Date} validFrom Start date
* @param {Date} validTo End date
* @returns {number}
* @returns {number} Number of days remaining
*/
const getDaysRemaining = (validFrom, validTo) => {
const daysRemaining = getDaysBetween(validFrom, validTo);
@@ -650,8 +655,9 @@ const getDaysRemaining = (validFrom, validTo) => {
/**
* Fix certificate info for display
* @param {Object} info The chain obtained from getPeerCertificate()
* @returns {Object} An object representing certificate information
* @param {object} info The chain obtained from getPeerCertificate()
* @returns {object} An object representing certificate information
* @throws The certificate chain length exceeded 500.
*/
const parseCertificateInfo = function (info) {
let link = info;
@@ -698,8 +704,9 @@ const parseCertificateInfo = function (info) {
/**
* Check if certificate is valid
* @param {Object} res Response object from axios
* @returns {Object} Object containing certificate information
* @param {object} res Response object from axios
* @returns {object} Object containing certificate information
* @throws No socket was found to check certificate for
*/
exports.checkCertificate = function (res) {
if (!res.request.res.socket) {
@@ -757,7 +764,7 @@ exports.checkStatusCode = function (status, acceptedCodes) {
* Get total number of clients in room
* @param {Server} io Socket server instance
* @param {string} roomName Name of room to check
* @returns {number}
* @returns {number} Total clients in room
*/
exports.getTotalClientInRoom = (io, roomName) => {
@@ -784,7 +791,8 @@ exports.getTotalClientInRoom = (io, roomName) => {
/**
* Allow CORS all origins if development
* @param {Object} res Response object from axios
* @param {object} res Response object from axios
* @returns {void}
*/
exports.allowDevAllOrigin = (res) => {
if (process.env.NODE_ENV === "development") {
@@ -794,7 +802,8 @@ exports.allowDevAllOrigin = (res) => {
/**
* Allow CORS all origins
* @param {Object} res Response object from axios
* @param {object} res Response object from axios
* @returns {void}
*/
exports.allowAllOrigin = (res) => {
res.header("Access-Control-Allow-Origin", "*");
@@ -805,6 +814,8 @@ exports.allowAllOrigin = (res) => {
/**
* Check if a user is logged in
* @param {Socket} socket Socket instance
* @returns {void}
* @throws The user is not logged in
*/
exports.checkLogin = (socket) => {
if (!socket.userID) {
@@ -815,8 +826,10 @@ exports.checkLogin = (socket) => {
/**
* For logged-in users, double-check the password
* @param {Socket} socket Socket.io instance
* @param {string} currentPassword
* @returns {Promise<Bean>}
* @param {string} currentPassword Password to validate
* @returns {Promise<Bean>} User
* @throws The current password is not a string
* @throws The provided password is not correct
*/
exports.doubleCheckPassword = async (socket, currentPassword) => {
if (typeof currentPassword !== "string") {
@@ -834,7 +847,10 @@ exports.doubleCheckPassword = async (socket, currentPassword) => {
return user;
};
/** Start Unit tests */
/**
* Start Unit tests
* @returns {void}
*/
exports.startUnitTest = async () => {
console.log("Starting unit test...");
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
@@ -854,7 +870,10 @@ exports.startUnitTest = async () => {
});
};
/** Start end-to-end tests */
/**
* Start end-to-end tests
* @returns {void}
*/
exports.startE2eTests = async () => {
console.log("Starting unit test...");
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
@@ -877,7 +896,7 @@ exports.startE2eTests = async () => {
/**
* Convert unknown string to UTF8
* @param {Uint8Array} body Buffer
* @returns {string}
* @returns {string} UTF8 string
*/
exports.convertToUTF8 = (body) => {
const guessEncoding = chardet.detect(body);
@@ -889,11 +908,10 @@ exports.convertToUTF8 = (body) => {
* Returns a color code in hex format based on a given percentage:
* 0% => hue = 10 => red
* 100% => hue = 90 => green
*
* @param {number} percentage float, 0 to 1
* @param {number} maxHue
* @param {number} minHue, int
* @returns {string}, hex value
* @param {number} maxHue Maximum hue - int
* @param {number} minHue Minimum hue - int
* @returns {string} Color in hex
*/
exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => {
const hue = percentage * (maxHue - minHue) + minHue;
@@ -906,10 +924,9 @@ exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => {
/**
* Joins and array of string to one string after filtering out empty values
*
* @param {string[]} parts
* @param {string} connector
* @returns {string}
* @param {string[]} parts Strings to join
* @param {string} connector Separator for joined strings
* @returns {string} Joined strings
*/
exports.filterAndJoin = (parts, connector = "") => {
return parts.filter((part) => !!part && part !== "").join(connector);
@@ -917,8 +934,9 @@ exports.filterAndJoin = (parts, connector = "") => {
/**
* Send an Error response
* @param {Object} res Express response object
* @param {string} [msg=""] Message to send
* @param {object} res Express response object
* @param {string} msg Message to send
* @returns {void}
*/
module.exports.sendHttpError = (res, msg = "") => {
if (msg.includes("SQLITE_BUSY") || msg.includes("SQLITE_LOCKED")) {
@@ -939,6 +957,13 @@ module.exports.sendHttpError = (res, msg = "") => {
}
};
/**
* Convert timezone of time object
* @param {object} obj Time object to update
* @param {string} timezone New timezone to set
* @param {boolean} timeObjectToUTC Convert time object to UTC
* @returns {object} Time object with updated timezone
*/
function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) {
let offsetString;
@@ -981,20 +1006,20 @@ function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) {
}
/**
*
* @param {object} obj
* @param {string} timezone
* @returns {object}
* Convert time object to UTC
* @param {object} obj Object to convert
* @param {string} timezone Timezone of time object
* @returns {object} Updated time object
*/
module.exports.timeObjectToUTC = (obj, timezone = undefined) => {
return timeObjectConvertTimezone(obj, timezone, true);
};
/**
*
* @param {object} obj
* @param {string} timezone
* @returns {object}
* Convert time object to local time
* @param {object} obj Object to convert
* @param {string} timezone Timezone to convert to
* @returns {object} Updated object
*/
module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
return timeObjectConvertTimezone(obj, timezone, false);
@@ -1002,7 +1027,8 @@ module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
/**
* Create gRPC client stib
* @param {Object} options from gRPC client
* @param {object} options from gRPC client
* @returns {Promise<object>} Result of gRPC query
*/
module.exports.grpcQuery = async (options) => {
const { grpcUrl, grpcProtobufData, grpcServiceName, grpcEnableTls, grpcMethod, grpcBody } = options;