lint issues resolved

This commit is contained in:
maryamsaleem 2025-02-06 14:57:09 +05:00
parent 8704b12fae
commit 70d1d9a964
5 changed files with 202 additions and 146 deletions
server
model
notification-providers
util-server.js
src
modules/dayjs/plugin/timezone
pages

View file

@ -5,7 +5,7 @@ const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MI
SQL_DATETIME_FORMAT, evaluateJsonQuery
} = require("../../src/util");
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery,
redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal, sipRegisterRequest,sipOptionRequest
redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal, sipRegisterRequest, sipOptionRequest
} = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
@ -315,9 +315,9 @@ class Monitor extends BeanModel {
sipUrl: this.sipUrl,
sipPort: this.sipPort,
sipProtocol: this.sipProtocol,
sipMethod: this.sipMethod,
sipMaintainence: this.isSipMaintainence(),
sipAuthMethod: this.sipAuthMethod,
sipMethod: this.sipMethod,
sipMaintainence: this.isSipMaintainence(),
sipAuthMethod: this.sipAuthMethod,
};
if (includeSensitiveData) {
@ -483,6 +483,7 @@ class Monitor extends BeanModel {
getKafkaProducerAllowAutoTopicCreation() {
return Boolean(this.kafkaProducerAllowAutoTopicCreation);
}
/**
* Parse to boolean
* @returns {boolean} Sip Allow Maintainenece Option
@ -490,6 +491,7 @@ class Monitor extends BeanModel {
isSipMaintainence() {
return Boolean(this.sipMaintainence);
}
/**
* Start monitor
* @param {Server} io Socket server instance
@ -1052,12 +1054,11 @@ class Monitor extends BeanModel {
let sipMessage;
let startTime = dayjs().valueOf();
let totalResponseTime;
let requestCount;
if (this.sipMethod !== "OPTIONS") {
sipResponse = await sipRegisterRequest(this.sipUrl, this.sipPort, this.sipProtocol, this.sip_basic_auth_user, this.sip_basic_auth_pass, version);
let sipResponseTime = dayjs().valueOf() - startTime;
totalResponseTime += sipResponseTime;
console.log("sipResponse", sipResponse);
console.log("sipResponse", totalResponseTime);
console.log("this.sipMaintainence", this.sipMaintainence);
const matchingStatus = sipStatusCodes.find(code => code.status === sipResponse?.status);
if (matchingStatus) {
@ -1066,7 +1067,7 @@ class Monitor extends BeanModel {
bean.status = sipResponse?.status === 200 ? UP : DOWN;
console.log("sipResponse?.status", sipResponse?.status);
// Additional check for 503 status within matchingStatus
if (sipResponse?.status === 503 && this.sipMaintainence == 1) {
if (sipResponse?.status === 503 && this.sipMaintainence === 1) {
sipMessage = "Monitor under maintenance";
bean.status = MAINTENANCE;
}
@ -1074,12 +1075,9 @@ class Monitor extends BeanModel {
sipMessage = ` ${sipResponse?.status}-Not Ok`;
bean.status = DOWN;
}
} else if (this.sipMethod === "OPTIONS") {
sipResponse = await sipOptionRequest(this.sipUrl, this.sipPort, this.sipProtocol, this.sip_basic_auth_user, this.sip_basic_auth_pass, version);
let sipOptionsResponseTime = dayjs().valueOf() - startTime;
totalResponseTime = sipOptionsResponseTime;
requestCount++;
console.log("=====resposne status", sipResponse?.status);
console.log("this.sipMaintainence", this.sipMaintainence);
const matchingStatus = sipStatusCodes.find(code => code.status === sipResponse?.status);
@ -1089,7 +1087,7 @@ class Monitor extends BeanModel {
bean.status = sipResponse?.status === 200 ? UP : DOWN;
// Additional check for 503 status within matchingStatus
if (sipResponse?.status === 503 && this.sipMaintainence == 1) {
if (sipResponse?.status === 503 && this.sipMaintainence === 1) {
sipMessage = "Monitor under maintenance";
bean.status = MAINTENANCE;
}
@ -1105,8 +1103,7 @@ class Monitor extends BeanModel {
bean.msg = `Error: ${error.message}`;
bean.status = DOWN;
}
}
else {
} else {
throw new Error("Unknown Monitor Type");
}

View file

@ -2,14 +2,29 @@ const NotificationProvider = require("./notification-provider");
class SIP extends NotificationProvider {
name = "sip";
/**
* Sends a SIP notification message.
* @param {object} notification - SIP notification configuration.
* @param {string} msg - The message content.
* @param {object | null} monitorJSON - The monitor data (if available).
* @param {object | null} heartbeatJSON - The heartbeat data (if available).
* @returns {Promise<string>} - Confirmation message if successful.
* @throws {Error} - If sending the SIP message fails.
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let monitorName = monitorJSON ? monitorJSON["name"] : "Unknown Monitor";
let subject = this.updateSubject(msg, monitorName);
let body;
let body = "";
if (heartbeatJSON) {
body += `\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`;
}
try {
console.log("Sending SIP message:", { notification,
msg,
monitorName,
body });
return "SIP Message Sent Successfully.";
} catch (error) {
console.error("Error sending SIP message:", error);
@ -17,44 +32,58 @@ class SIP extends NotificationProvider {
}
}
/**
* Generates a subject line based on the message content.
* @param {string} message - The incoming status message.
* @param {string} monitorName - The name of the monitored service.
* @returns {string} - The formatted subject line.
*/
updateSubject(message, monitorName) {
if (!message) return "Default Subject"; // Handle null/undefined message
if (!message) {
return "Default Subject";
}
message = message.toLowerCase(); // Normalize input
if (/\bdown\b/i.test(message) || message.includes("offline")) {
return `🚨 ❌ Service Impacted...`;
return "🚨 ❌ Service Impacted...";
}
if (/\bup\b/i.test(message) || message.includes("online")) {
return `🚨 ✅ Service Restored...`;
return "🚨 ✅ Service Restored...";
}
if (message.includes("maintenance")) {
if (message.includes("begin")) {
return `🚧 🔧 ❌ Maintenance Start...`;
return "🚧 🔧 ❌ Maintenance Start...";
}
if (/\bend\b/i.test(message)) {
return `🚧 🔧 ✅ Maintenance Complete...`;
return "🚧 🔧 ✅ Maintenance Complete...";
}
if (message.includes("scheduled")) {
return `🚧 🪟 📆 Maintenance Window Scheduled...`;
return "🚧 🪟 📆 Maintenance Window Scheduled...";
}
if (message.includes("window begin")) {
return `🚧 🪟 🛑 Maintenance Window Start...`;
return "🚧 🪟 🛑 Maintenance Window Start...";
}
if (message.includes("window end")) {
return `🚧 🪟 ✅ Maintenance Window Complete...`;
return "🚧 🪟 ✅ Maintenance Window Complete...";
}
}
if (message.includes("started on node")) {
return `📈 🔬 ✅ Monitoring Start...`;
return "📈 🔬 ✅ Monitoring Start...";
}
if (message.includes("started")) {
return `📈 🔬 ✅ ${monitorName}`;
return `📈 🔬 ✅ ${monitorName}`;
}
return "Default Subject";
}
/**
* Sends a SIP message using the provided notification configuration.
* @param {object} notification - SIP notification settings.
* @param {string} sipMessage - The message content to send.
* @returns {void}
*/
async sendSIPMessage(notification, sipMessage) {
console.log("Sending SIP message with config:", notification);
console.log("Message:", sipMessage);

View file

@ -33,8 +33,6 @@ const { Kafka, SASLOptions } = require("kafkajs");
const crypto = require("crypto");
let sip = require("sip");
const uuid = require("uuid");
let sharedSipServer;
const SERVER_PORT = 25060;
const isWindows = process.platform === /^win/.test(process.platform);
/**
@ -266,23 +264,28 @@ exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, sa
/**
* Sends a SIP REGISTER request
* @param {string} sipServer The SIP server to register with
* @param {number} sipPort The port of the SIP server
* @param {string} transport The transport protocol to use (e.g., 'udp' or 'tcp')
* @returns {Promise<void>}
* @param {string} username The username for registration
* @param {string} password The password for registration
* @param {string} version The version of the SIP health monitor
* @returns {Promise<object>} The response from the SIP REGISTER request
*/
exports.sipRegisterRequest = function (sipServer, sipPort, transport, username, password, version) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
const registerRequest = {
method: 'REGISTER',
method: "REGISTER",
uri: `sip:${sipServer}:${sipPort}`,
headers: {
to: { uri: `sip:${sipServer}:${sipPort}` },
from: { uri: `sip:${username}` },
'call-id': uuid.v4(),
cseq: { method: 'REGISTER', seq: 1 },
'content-length': 0,
"call-id": uuid.v4(),
cseq: { method: "REGISTER",
seq: 1 },
"content-length": 0,
contact: { uri: `sip:${username}` },
"User-Agent": "SIP Health Monitor " + version,
"Expires": 60,
@ -321,9 +324,16 @@ exports.sipRegister = function (registerRequest) {
return new Promise((resolve, reject) => {
const timeout = 5000; // Timeout duration in milliseconds
let timeoutID;
// Cleanup function to clear the timeout and destroy the server
// Cleanup function to ensure proper resource management
/**
* Clears the timeout and destroys the SIP server instance.
* This function is called to prevent memory leaks and ensure that no lingering processes are left running.
* @returns {void} This function does not return any value.
*/
function cleanup() {
if (timeoutID) clearTimeout(timeoutID);
if (timeoutID) {
clearTimeout(timeoutID);
}
if (server && server.destroy) {
server.destroy();
console.log("SIP server destroyed.");
@ -378,8 +388,12 @@ exports.constructAuthorizedRequest = function (request, username, password, prox
/**
* Sends a SIP OPTIONS request
* @param {string} sipServer The SIP server to send OPTIONS to
* @param {number} sipPort The port of the SIP server
* @param {string} transport The transport protocol to use (e.g., 'udp' or 'tcp')
* @returns {Promise<void>}
* @param {string} username The username for authentication (optional)
* @param {string} password The password for authentication (optional)
* @param {string} version The version of the SIP Health Monitor
* @returns {Promise<object>} The response from the SIP OPTIONS request
*/
exports.sipOptionRequest = function (sipServer, sipPort, transport, username, password, version) {
const publicIP = process.env.PUBLIC_IP;
@ -387,28 +401,28 @@ exports.sipOptionRequest = function (sipServer, sipPort, transport, username, pa
return new Promise(async (resolve, reject) => {
try {
const optionsRequest = {
method: 'OPTIONS',
uri: `sip:${sipServer}:${sipPort}`,//hostname
method: "OPTIONS",
uri: `sip:${sipServer}:${sipPort}`, //hostname
headers: {
to: { uri: `sip:${sipServer}:${sipPort}` },//hostname
from: { uri: `sip:${publicIP}` },//live ip || primary url
'call-id': 1234,
cseq: { method: 'OPTIONS', seq: 1 },
'content-length': 0,
contact: [ { uri: `sip:${publicIP}` }],
to: { uri: `sip:${sipServer}:${sipPort}` }, //hostname
from: { uri: `sip:${publicIP}` }, //live ip || primary url
"call-id": 1234,
cseq: { method: "OPTIONS",
seq: 1 },
"content-length": 0,
contact: [{ uri: `sip:${publicIP}` }],
"User-Agent": "SIP Health Monitor" + version,
},
transport: transport,
};
let optionResponse
if(!username) {
console.log("will only send ok")
let optionResponse;
if (!username) {
console.log("will only send ok");
const optionResponse = await exports.sipOption(optionsRequest);
console.log("optionResponse", optionResponse);
resolve(optionResponse)
}
else {
resolve(optionResponse);
} else {
optionResponse = await exports.sipRegister(optionsRequest);
console.log("optionResponse", optionResponse);
if (optionResponse.status === 407 && optionResponse.headers["proxy-authenticate"]) {
@ -419,12 +433,12 @@ exports.sipOptionRequest = function (sipServer, sipPort, transport, username, pa
password,
proxyAuthenticateHeader
);
const secondResponse = await exports.sipOption(authorizedOptionRequest);
resolve(secondResponse);
}
}
}
} catch (error) {
console.error("Error:", error.message);
reject(error);
@ -439,18 +453,24 @@ exports.sipOption = function (optionsRequest) {
console.log("SIP server created:", server);
return new Promise((resolve, reject) => {
const timeout = 5000; // Timeout duration in milliseconds
let timeoutID;
// Cleanup function to clear the timeout and destroy the server
// Cleanup function to ensure proper resource management
/**
* Clears the timeout and destroys the SIP server instance.
* This function is called to prevent memory leaks and ensure that no lingering processes are left running.
* @returns {void} This function does not return any value.
*/
function cleanup() {
if (timeoutID) clearTimeout(timeoutID);
if (timeoutID) {
clearTimeout(timeoutID);
}
if (server) {
server.destroy();
console.log("SIP server destroyed.");
}
}
try {
// Send the SIP options request
server.send(optionsRequest, (response) => {

View file

@ -1,12 +1,12 @@
import { PluginFunc, ConfigType } from 'dayjs/esm'
import { PluginFunc, ConfigType } from "dayjs/esm";
declare const plugin: PluginFunc
declare const plugin: PluginFunc;
export = plugin
declare module 'dayjs/esm' {
declare module "dayjs/esm" {
interface Dayjs {
tz(timezone?: string, keepLocalTime?: boolean): Dayjs
offsetName(type?: 'short' | 'long'): string | undefined
offsetName(type?: "short" | "long"): string | undefined
}
interface DayjsTimezone {
@ -16,5 +16,5 @@ declare module 'dayjs/esm' {
setDefault(timezone?: string): void
}
const tz: DayjsTimezone
const tz: DayjsTimezone;
}

View file

@ -91,7 +91,7 @@
<option v-if="!$root.info.isContainer" value="tailscale-ping">
Tailscale Ping
</option>
<option value="sip">SIP</option>
<option value="sip">SIP</option>
</optgroup>
</select>
<i18n-t v-if="monitor.type === 'rabbitmq'" keypath="rabbitmqHelpText" tag="div" class="form-text">
@ -121,10 +121,10 @@
<!--SIP-->
<div v-if="monitor.type === 'sip'" class="my-3">
<label for="sipprotocol" class="form-label">{{ $t("SipProtocol") }}</label>
<select id="sipprotocol" class="form-select" required v-model="monitor.sipProtocol">
<option value="UDP">UDP</option>
<option value="TCP">TCP</option>
<option value="TLS">TLS</option>
<select id="sipprotocol" v-model="monitor.sipProtocol" class="form-select" required>
<option value="UDP">UDP</option>
<option value="TCP">TCP</option>
<option value="TLS">TLS</option>
</select>
</div>
<!-- gRPC URL -->
@ -175,8 +175,10 @@
</div>
<div v-if="monitor.type === 'sip'" class="my-3">
<label for="sipport" class="form-label mt-3">{{ $t("SipPort") }}</label>
<input v-if="monitor.sipProtocol !== 'SRV'" id="sipport" type="number" class="form-control"
v-model="monitor.sipPort" placeholder="Enter SIP Port">
<input
v-if="monitor.sipProtocol !== 'SRV'" id="sipport" v-model="monitor.sipPort" type="number"
class="form-control" placeholder="Enter SIP Port"
>
</div>
<!-- Remote Browser -->
<div v-if="monitor.type === 'real-browser'" class="my-3">
@ -637,7 +639,7 @@
<input id="expiry-notification" v-model="monitor.expiryNotification" class="form-check-input" type="checkbox" :disabled="monitor.ignoreTls">
<label class="form-check-label" for="expiry-notification">
{{ $t("Certificate Expiry Notification") }}
</label>
</label>
<div class="form-text">
</div>
</div>
@ -681,8 +683,8 @@
<label class="form-check-label" for="process-503-as-maintenance">
{{ $t("process503AsMaintenanceLabel") }}
</label>
</div>
</div>
<div v-if="monitor.type === 'gamedig'" class="my-3 form-check">
<input id="gamedig-guess-port" v-model="monitor.gamedigGivenPortOnly" :true-value="false" :false-value="true" class="form-check-input" type="checkbox">
<label class="form-check-label" for="gamedig-guess-port">
@ -858,83 +860,91 @@
</div>
</div>
</template>
<!-- SIP Options -->
<template v-if="monitor.type === 'sip'
">
<h2 class="mt-5 mb-2">{{ $t("SIP Options") }}</h2>
<!-- SIP Options -->
<!-- Method -->
<div class="my-3">
<label for="method" class="form-label">{{
$t("Method")
}}</label>
<select id="method" v-model="monitor.sipMethod" class="form-select">
<option value="REGISTER">REGISTER</option>
<option value="OPTIONS">OPTIONS</option>
</select>
</div>
<template
v-if="monitor.type === 'sip'
"
>
<h2 class="mt-5 mb-2">{{ $t("SIP Options") }}</h2>
<!-- Encoding -->
<div class="my-3">
<label for="httpBodyEncoding" class="form-label">{{
$t("Body Encoding")
}}</label>
<select id="httpBodyEncoding" v-model="monitor.httpBodyEncoding" class="form-select">
<option value="json">JSON</option>
<option value="xml">XML</option>
</select>
</div>
<!-- Method -->
<div class="my-3">
<label for="method" class="form-label">{{
$t("Method")
}}</label>
<select id="method" v-model="monitor.sipMethod" class="form-select">
<option value="REGISTER">REGISTER</option>
<option value="OPTIONS">OPTIONS</option>
</select>
</div>
<!-- Body -->
<div class="my-3">
<label for="body" class="form-label">{{ $t("Body") }}</label>
<textarea id="body" v-model="monitor.body" class="form-control"
:placeholder="bodyPlaceholder"></textarea>
</div>
<!-- Encoding -->
<div class="my-3">
<label for="httpBodyEncoding" class="form-label">{{
$t("Body Encoding")
}}</label>
<select id="httpBodyEncoding" v-model="monitor.httpBodyEncoding" class="form-select">
<option value="json">JSON</option>
<option value="xml">XML</option>
</select>
</div>
<!-- Headers -->
<div class="my-3">
<label for="headers" class="form-label">{{
$t("Headers")
}}</label>
<textarea id="headers" v-model="monitor.headers" class="form-control"
:placeholder="headersPlaceholder"></textarea>
</div>
<!-- Body -->
<div class="my-3">
<label for="body" class="form-label">{{ $t("Body") }}</label>
<textarea
id="body" v-model="monitor.body" class="form-control"
:placeholder="bodyPlaceholder"
></textarea>
</div>
<!-- HTTP Auth -->
<h4 class="mt-5 mb-2">{{ $t("Authentication") }}</h4>
<!-- Headers -->
<div class="my-3">
<label for="headers" class="form-label">{{
$t("Headers")
}}</label>
<textarea
id="headers" v-model="monitor.headers" class="form-control"
:placeholder="headersPlaceholder"
></textarea>
</div>
<!-- Method -->
<div class="my-3">
<label for="authmethod" class="form-label">{{
$t("Method")
}}</label>
<select id="authsipmethod" v-model="monitor.sipAuthMethod" class="form-select">
<option :value="null">
{{ $t("None") }}
</option>
<option value="basic">
{{ $t("SIP Basic Auth") }}
</option>
</select>
</div>
<template v-if="monitor.sipAuthMethod === 'basic'">
<div class="my-3">
<label for="basicauth-user" class="form-label">{{ $t("Username") }}</label>
<input id="basicauth-user" v-model="monitor.sip_basic_auth_user" type="text" class="form-control"
:placeholder="$t('Username')" />
</div>
<!-- HTTP Auth -->
<h4 class="mt-5 mb-2">{{ $t("Authentication") }}</h4>
<div class="my-3">
<label for="basicauth-pass" class="form-label">{{ $t("Password") }}</label>
<input id="basicauth-pass" v-model="monitor.sip_basic_auth_pass" type="password" autocomplete="new-password"
class="form-control" :placeholder="$t('Password')" />
</div>
</template>
</template>
<!-- Method -->
<div class="my-3">
<label for="authmethod" class="form-label">{{
$t("Method")
}}</label>
<select id="authsipmethod" v-model="monitor.sipAuthMethod" class="form-select">
<option :value="null">
{{ $t("None") }}
</option>
<option value="basic">
{{ $t("SIP Basic Auth") }}
</option>
</select>
</div>
<template v-if="monitor.sipAuthMethod === 'basic'">
<div class="my-3">
<label for="basicauth-user" class="form-label">{{ $t("Username") }}</label>
<input
id="basicauth-user" v-model="monitor.sip_basic_auth_user" type="text" class="form-control"
:placeholder="$t('Username')"
/>
</div>
<div class="my-3">
<label for="basicauth-pass" class="form-label">{{ $t("Password") }}</label>
<input
id="basicauth-pass" v-model="monitor.sip_basic_auth_pass" type="password" autocomplete="new-password"
class="form-control" :placeholder="$t('Password')"
/>
</div>
</template>
</template>
<!-- HTTP Options -->
<template v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' ">
<h2 class="mt-5 mb-2">{{ $t("HTTP Options") }}</h2>
@ -1223,10 +1233,10 @@ const monitorDefaults = {
conditions: [],
sipProtocol: "UDP",
sipPort: 5060,
sipUrl:null,
sipUrl: null,
sipMethod: "OPTIONS",
sipMaintainence:false,
sipAuthMethod: null,
sipMaintainence: false,
sipAuthMethod: null,
};
export default {