209 lines
5.0 KiB
TypeScript
209 lines
5.0 KiB
TypeScript
import { sendHeartbeat, sendDownNotification } from "./requestHandler";
|
|
|
|
/**
|
|
* Defines an uptime kuma monitor
|
|
*/
|
|
interface Monitor {
|
|
/**
|
|
* The url to push heartbeats to
|
|
*/
|
|
url: string;
|
|
/**
|
|
* The interval in which to push heartbeats in seconds
|
|
*/
|
|
heartbeatIntervall: number;
|
|
}
|
|
|
|
/**
|
|
* Defines a monitor store
|
|
*/
|
|
interface MonitorStore {
|
|
/**
|
|
* The monitor
|
|
*/
|
|
monitor: Monitor;
|
|
/**
|
|
* The last heartbeat
|
|
*/
|
|
lastHeartbeat: Date;
|
|
}
|
|
|
|
/**
|
|
* The handler managing all monitors
|
|
*/
|
|
export class PushMonitor {
|
|
/**
|
|
* The private constructor
|
|
* @private
|
|
*/
|
|
private constructor() {
|
|
this.initTimer();
|
|
}
|
|
|
|
/**
|
|
* The singleton instance of the PushMonitor
|
|
* @private
|
|
*/
|
|
private static _instance = new PushMonitor();
|
|
|
|
/**
|
|
* The monitors to manage
|
|
* @private
|
|
*/
|
|
private _monitors: MonitorStore[] = [];
|
|
|
|
/**
|
|
* The check interval
|
|
* @private
|
|
*/
|
|
private _checkInterval: NodeJS.Timer | undefined;
|
|
|
|
/**
|
|
* Whether to log debug information
|
|
* @private
|
|
*/
|
|
private _debug: boolean = false;
|
|
|
|
/**
|
|
* Performance measurment function
|
|
* @private
|
|
*/
|
|
private _performance: (() => (Promise<number> | number)) | undefined;
|
|
|
|
/**
|
|
* Returns the singleton instance of the PushMonitor
|
|
*/
|
|
public static get instance(): PushMonitor {
|
|
return PushMonitor._instance;
|
|
}
|
|
|
|
/**
|
|
* Starts the monitor
|
|
* @returns This instance
|
|
*/
|
|
public start(): this {
|
|
this.initTimer();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Stops the monitor
|
|
* @returns This instance
|
|
*/
|
|
public stop(): this {
|
|
if (this._checkInterval) {
|
|
clearInterval(this._checkInterval);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Registers a new monitor to be managed
|
|
* @param url {string} The url to push heartbeats to
|
|
* @param heartbeatIntervall {number} The interval in which to push heartbeats in seconds. Default is 58 seconds
|
|
* @returns This instance
|
|
*/
|
|
public register(url: string, heartbeatIntervall: number = 58): this {
|
|
this._monitors.push({
|
|
monitor: {
|
|
url,
|
|
heartbeatIntervall,
|
|
},
|
|
lastHeartbeat: new Date(new Date().getTime() + 10000 - heartbeatIntervall * 1000),
|
|
});
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets whether to log debug information
|
|
* @param debug Whether to log debug information
|
|
* @returns This instance
|
|
*/
|
|
public setDebug(debug: boolean): this {
|
|
this._debug = debug;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Enables the sending of shutdown down notifications
|
|
* !! This will overwrite the uncaughtException handler function !!
|
|
* @returns This instance
|
|
*/
|
|
public enableShutdownNotifications(): this {
|
|
this.initEventHandlers();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the performance handler
|
|
* @param handler The performance handler
|
|
* @returns This instance
|
|
*/
|
|
public setPerformanceHandler(handler?: () => (Promise<number> | number)): this {
|
|
this._performance = handler;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Initializes the timer
|
|
* @private
|
|
*/
|
|
private initTimer() {
|
|
if (this._checkInterval) {
|
|
clearInterval(this._checkInterval);
|
|
}
|
|
|
|
let isRunning = false;
|
|
|
|
this._checkInterval = setInterval(async () => {
|
|
if (isRunning) return;
|
|
isRunning = true;
|
|
|
|
try {
|
|
let performance: number | undefined = undefined;
|
|
|
|
if (this._performance) performance = await this._performance();
|
|
|
|
this._monitors.forEach((monitor) => {
|
|
if (new Date().getTime() - monitor.lastHeartbeat.getTime() > monitor.monitor.heartbeatIntervall * 1000) {
|
|
sendHeartbeat(monitor.monitor.url, performance, this._debug);
|
|
monitor.lastHeartbeat = new Date();
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error(`[eu.astrogd.uptime-kuma-push-monitor] (${new Date().toISOString()}) <internal.interval>: ${error}`);
|
|
}
|
|
|
|
|
|
isRunning = false;
|
|
}, 1000);
|
|
}
|
|
|
|
/**
|
|
* Initializes event handlers
|
|
* @private
|
|
*/
|
|
private initEventHandlers() {
|
|
process.on("uncaughtException", async (err, origin) => {
|
|
console.error(origin + "\n" + err.stack);
|
|
await this.sendShutdownNotification(`Uncaught Exception (${err.message})`);
|
|
process.exitCode = 1;
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Sends a shutdown notification to all monitors
|
|
* @param msg The message to send
|
|
*/
|
|
private async sendShutdownNotification(msg: string = "Shutdown") {
|
|
const promises: Promise<void>[] = [];
|
|
|
|
this._monitors.forEach((monitor) => {
|
|
promises.push(sendDownNotification(monitor.monitor.url, msg, this._debug));
|
|
});
|
|
|
|
return Promise.all(promises);
|
|
}
|
|
}
|