mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-08-09 03:28:45 +08:00
Merge branch 'master' into snmp-monitor
This commit is contained in:
@@ -209,9 +209,9 @@ class Database {
|
||||
let config = {};
|
||||
|
||||
let mariadbPoolConfig = {
|
||||
afterCreate: function (conn, done) {
|
||||
|
||||
}
|
||||
min: 0,
|
||||
max: 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
};
|
||||
|
||||
log.info("db", `Database Type: ${dbConfig.type}`);
|
||||
@@ -223,11 +223,8 @@ class Database {
|
||||
fs.copyFileSync(Database.templatePath, Database.sqlitePath);
|
||||
}
|
||||
|
||||
const Dialect = require("knex/lib/dialects/sqlite3/index.js");
|
||||
Dialect.prototype._driver = () => require("@louislam/sqlite3");
|
||||
|
||||
config = {
|
||||
client: Dialect,
|
||||
client: "sqlite3",
|
||||
connection: {
|
||||
filename: Database.sqlitePath,
|
||||
acquireConnectionTimeout: acquireConnectionTimeout,
|
||||
|
@@ -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, mongodbPing, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
|
||||
redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
|
||||
} = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||
@@ -811,15 +811,6 @@ class Monitor extends BeanModel {
|
||||
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1", mysqlPassword);
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
} else if (this.type === "mongodb") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
await mongodbPing(this.databaseConnectionString);
|
||||
|
||||
bean.msg = "";
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
|
||||
} else if (this.type === "radius") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
@@ -850,7 +841,7 @@ class Monitor extends BeanModel {
|
||||
} else if (this.type === "redis") {
|
||||
let startTime = dayjs().valueOf();
|
||||
|
||||
bean.msg = await redisPingAsync(this.databaseConnectionString);
|
||||
bean.msg = await redisPingAsync(this.databaseConnectionString, !this.ignoreTls);
|
||||
bean.status = UP;
|
||||
bean.ping = dayjs().valueOf() - startTime;
|
||||
|
||||
@@ -895,7 +886,6 @@ class Monitor extends BeanModel {
|
||||
retries = 0;
|
||||
|
||||
} catch (error) {
|
||||
|
||||
if (error?.name === "CanceledError") {
|
||||
bean.msg = `timeout by AbortSignal (${this.timeout}s)`;
|
||||
} else {
|
||||
@@ -968,6 +958,7 @@ class Monitor extends BeanModel {
|
||||
} else if (bean.status === MAINTENANCE) {
|
||||
log.warn("monitor", `Monitor #${this.id} '${this.name}': Under Maintenance | Type: ${this.type}`);
|
||||
} else {
|
||||
beatInterval = this.retryInterval;
|
||||
log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type} | Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`);
|
||||
}
|
||||
|
||||
|
@@ -238,6 +238,7 @@ class StatusPage extends BeanModel {
|
||||
description: this.description,
|
||||
icon: this.getIcon(),
|
||||
theme: this.theme,
|
||||
autoRefreshInterval: this.autoRefreshInterval,
|
||||
published: !!this.published,
|
||||
showTags: !!this.show_tags,
|
||||
domainNameList: this.getDomainNameList(),
|
||||
@@ -260,6 +261,7 @@ class StatusPage extends BeanModel {
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
icon: this.getIcon(),
|
||||
autoRefreshInterval: this.autoRefreshInterval,
|
||||
theme: this.theme,
|
||||
published: !!this.published,
|
||||
showTags: !!this.show_tags,
|
||||
|
@@ -5,7 +5,6 @@ const { dnsResolve } = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
|
||||
class DnsMonitorType extends MonitorType {
|
||||
|
||||
name = "dns";
|
||||
|
||||
/**
|
||||
|
63
server/monitor-types/mongodb.js
Normal file
63
server/monitor-types/mongodb.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const { MonitorType } = require("./monitor-type");
|
||||
const { UP } = require("../../src/util");
|
||||
const { MongoClient } = require("mongodb");
|
||||
const jsonata = require("jsonata");
|
||||
|
||||
class MongodbMonitorType extends MonitorType {
|
||||
name = "mongodb";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async check(monitor, heartbeat, _server) {
|
||||
let command = { "ping": 1 };
|
||||
if (monitor.databaseQuery) {
|
||||
command = JSON.parse(monitor.databaseQuery);
|
||||
}
|
||||
|
||||
let result = await this.runMongodbCommand(monitor.databaseConnectionString, command);
|
||||
|
||||
if (result["ok"] !== 1) {
|
||||
throw new Error("MongoDB command failed");
|
||||
} else {
|
||||
heartbeat.msg = "Command executed successfully";
|
||||
}
|
||||
|
||||
if (monitor.jsonPath) {
|
||||
let expression = jsonata(monitor.jsonPath);
|
||||
result = await expression.evaluate(result);
|
||||
if (result) {
|
||||
heartbeat.msg = "Command executed successfully and the jsonata expression produces a result.";
|
||||
} else {
|
||||
throw new Error("Queried value not found.");
|
||||
}
|
||||
}
|
||||
|
||||
if (monitor.expectedValue) {
|
||||
if (result.toString() === monitor.expectedValue) {
|
||||
heartbeat.msg = "Command executed successfully and expected value was found";
|
||||
} else {
|
||||
throw new Error("Query executed, but value is not equal to expected value, value was: [" + JSON.stringify(result) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
heartbeat.status = UP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to and run MongoDB command on a MongoDB database
|
||||
* @param {string} connectionString The database connection string
|
||||
* @param {object} command MongoDB command to run on the database
|
||||
* @returns {Promise<(string[] | object[] | object)>} Response from server
|
||||
*/
|
||||
async runMongodbCommand(connectionString, command) {
|
||||
let client = await MongoClient.connect(connectionString);
|
||||
let result = await client.db().command(command);
|
||||
await client.close();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MongodbMonitorType,
|
||||
};
|
@@ -11,7 +11,6 @@ class MonitorType {
|
||||
async check(monitor, heartbeat, server) {
|
||||
throw new Error("You need to override check()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@@ -4,15 +4,10 @@ const mqtt = require("mqtt");
|
||||
const jsonata = require("jsonata");
|
||||
|
||||
class MqttMonitorType extends MonitorType {
|
||||
|
||||
name = "mqtt";
|
||||
|
||||
/**
|
||||
* Run the monitoring check on the MQTT monitor
|
||||
* @param {Monitor} monitor Monitor to check
|
||||
* @param {Heartbeat} heartbeat Monitor heartbeat to update
|
||||
* @param {UptimeKumaServer} server Uptime Kuma server
|
||||
* @returns {Promise<void>}
|
||||
* @inheritdoc
|
||||
*/
|
||||
async check(monitor, heartbeat, server) {
|
||||
const receivedMessage = await this.mqttAsync(monitor.hostname, monitor.mqttTopic, {
|
||||
|
@@ -2,23 +2,13 @@ const { MonitorType } = require("./monitor-type");
|
||||
const { UP } = require("../../src/util");
|
||||
const childProcessAsync = require("promisify-child-process");
|
||||
|
||||
/**
|
||||
* A TailscalePing class extends the MonitorType.
|
||||
* It runs Tailscale ping to monitor the status of a specific node.
|
||||
*/
|
||||
class TailscalePing extends MonitorType {
|
||||
|
||||
name = "tailscale-ping";
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @returns {Promise<void>}
|
||||
* @throws Error if checking Tailscale ping encounters any error
|
||||
* @inheritdoc
|
||||
*/
|
||||
async check(monitor, heartbeat) {
|
||||
async check(monitor, heartbeat, _server) {
|
||||
try {
|
||||
let tailscaleOutput = await this.runTailscalePing(monitor.hostname, monitor.interval);
|
||||
this.parseTailscaleOutput(tailscaleOutput, heartbeat);
|
||||
|
31
server/notification-providers/bitrix24.js
Normal file
31
server/notification-providers/bitrix24.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP } = require("../../src/util");
|
||||
|
||||
class Bitrix24 extends NotificationProvider {
|
||||
name = "Bitrix24";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
const okMsg = "Sent Successfully.";
|
||||
|
||||
try {
|
||||
const params = {
|
||||
user_id: notification.bitrix24UserID,
|
||||
message: "[B]Uptime Kuma[/B]",
|
||||
"ATTACH[COLOR]": (heartbeatJSON ?? {})["status"] === UP ? "#b73419" : "#67b518",
|
||||
"ATTACH[BLOCKS][0][MESSAGE]": msg
|
||||
};
|
||||
|
||||
await axios.get(`${notification.bitrix24WebhookURL}/im.notify.system.add.json`, { params });
|
||||
return okMsg;
|
||||
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Bitrix24;
|
@@ -13,6 +13,10 @@ class Discord extends NotificationProvider {
|
||||
|
||||
try {
|
||||
const discordDisplayName = notification.discordUsername || "Uptime Kuma";
|
||||
const webhookUrl = new URL(notification.discordWebhookUrl);
|
||||
if (notification.discordChannelType === "postToThread") {
|
||||
webhookUrl.searchParams.append("thread_id", notification.threadId);
|
||||
}
|
||||
|
||||
// If heartbeatJSON is null, assume we're testing.
|
||||
if (heartbeatJSON == null) {
|
||||
@@ -20,7 +24,12 @@ class Discord extends NotificationProvider {
|
||||
username: discordDisplayName,
|
||||
content: msg,
|
||||
};
|
||||
await axios.post(notification.discordWebhookUrl, discordtestdata);
|
||||
|
||||
if (notification.discordChannelType === "createNewForumPost") {
|
||||
discordtestdata.thread_name = notification.postName;
|
||||
}
|
||||
|
||||
await axios.post(webhookUrl.toString(), discordtestdata);
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
@@ -72,12 +81,14 @@ class Discord extends NotificationProvider {
|
||||
],
|
||||
}],
|
||||
};
|
||||
|
||||
if (notification.discordChannelType === "createNewForumPost") {
|
||||
discorddowndata.thread_name = notification.postName;
|
||||
}
|
||||
if (notification.discordPrefixMessage) {
|
||||
discorddowndata.content = notification.discordPrefixMessage;
|
||||
}
|
||||
|
||||
await axios.post(notification.discordWebhookUrl, discorddowndata);
|
||||
await axios.post(webhookUrl.toString(), discorddowndata);
|
||||
return okMsg;
|
||||
|
||||
} else if (heartbeatJSON["status"] === UP) {
|
||||
@@ -108,11 +119,15 @@ class Discord extends NotificationProvider {
|
||||
}],
|
||||
};
|
||||
|
||||
if (notification.discordChannelType === "createNewForumPost") {
|
||||
discordupdata.thread_name = notification.postName;
|
||||
}
|
||||
|
||||
if (notification.discordPrefixMessage) {
|
||||
discordupdata.content = notification.discordPrefixMessage;
|
||||
}
|
||||
|
||||
await axios.post(notification.discordWebhookUrl, discordupdata);
|
||||
await axios.post(webhookUrl.toString(), discordupdata);
|
||||
return okMsg;
|
||||
}
|
||||
} catch (error) {
|
||||
|
@@ -25,25 +25,29 @@ class Feishu extends NotificationProvider {
|
||||
|
||||
if (heartbeatJSON["status"] === DOWN) {
|
||||
let downdata = {
|
||||
msg_type: "post",
|
||||
content: {
|
||||
post: {
|
||||
zh_cn: {
|
||||
title: "UptimeKuma Alert: [Down] " + monitorJSON["name"],
|
||||
content: [
|
||||
[
|
||||
{
|
||||
tag: "text",
|
||||
text:
|
||||
"[Down] " +
|
||||
heartbeatJSON["msg"] +
|
||||
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
msg_type: "interactive",
|
||||
card: {
|
||||
config: {
|
||||
update_multi: false,
|
||||
wide_screen_mode: true,
|
||||
},
|
||||
},
|
||||
header: {
|
||||
title: {
|
||||
tag: "plain_text",
|
||||
content: "UptimeKuma Alert: [Down] " + monitorJSON["name"],
|
||||
},
|
||||
template: "red",
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
tag: "div",
|
||||
text: {
|
||||
tag: "lark_md",
|
||||
content: getContent(heartbeatJSON),
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
await axios.post(notification.feishuWebHookUrl, downdata);
|
||||
return okMsg;
|
||||
@@ -51,25 +55,29 @@ class Feishu extends NotificationProvider {
|
||||
|
||||
if (heartbeatJSON["status"] === UP) {
|
||||
let updata = {
|
||||
msg_type: "post",
|
||||
content: {
|
||||
post: {
|
||||
zh_cn: {
|
||||
title: "UptimeKuma Alert: [Up] " + monitorJSON["name"],
|
||||
content: [
|
||||
[
|
||||
{
|
||||
tag: "text",
|
||||
text:
|
||||
"[Up] " +
|
||||
heartbeatJSON["msg"] +
|
||||
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
msg_type: "interactive",
|
||||
card: {
|
||||
config: {
|
||||
update_multi: false,
|
||||
wide_screen_mode: true,
|
||||
},
|
||||
},
|
||||
header: {
|
||||
title: {
|
||||
tag: "plain_text",
|
||||
content: "UptimeKuma Alert: [UP] " + monitorJSON["name"],
|
||||
},
|
||||
template: "green",
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
tag: "div",
|
||||
text: {
|
||||
tag: "lark_md",
|
||||
content: getContent(heartbeatJSON),
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
};
|
||||
await axios.post(notification.feishuWebHookUrl, updata);
|
||||
return okMsg;
|
||||
@@ -80,4 +88,17 @@ class Feishu extends NotificationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content
|
||||
* @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
|
||||
* @returns {string} Return Successful Message
|
||||
*/
|
||||
function getContent(heartbeatJSON) {
|
||||
return [
|
||||
"**Message**: " + heartbeatJSON["msg"],
|
||||
"**Ping**: " + (heartbeatJSON["ping"] == null ? "N/A" : heartbeatJSON["ping"] + " ms"),
|
||||
`**Time (${heartbeatJSON["timezone"]})**: ${heartbeatJSON["localDateTime"]}`
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
module.exports = Feishu;
|
||||
|
@@ -62,6 +62,15 @@ class FlashDuty extends NotificationProvider {
|
||||
* @returns {string} Success message
|
||||
*/
|
||||
async postNotification(notification, title, body, monitorInfo, eventStatus) {
|
||||
let labels = {
|
||||
resource: this.genMonitorUrl(monitorInfo),
|
||||
check: monitorInfo.name,
|
||||
};
|
||||
if (monitorInfo.tags && monitorInfo.tags.length > 0) {
|
||||
for (let tag of monitorInfo.tags) {
|
||||
labels[tag.name] = tag.value;
|
||||
}
|
||||
}
|
||||
const options = {
|
||||
method: "POST",
|
||||
url: "https://api.flashcat.cloud/event/push/alert/standard?integration_key=" + notification.flashdutyIntegrationKey,
|
||||
@@ -71,9 +80,7 @@ class FlashDuty extends NotificationProvider {
|
||||
title,
|
||||
event_status: eventStatus || "Info",
|
||||
alert_key: String(monitorInfo.id) || Math.random().toString(36).substring(7),
|
||||
labels: monitorInfo?.tags?.reduce((acc, item) => ({ ...acc,
|
||||
[item.name]: item.value
|
||||
}), { resource: this.genMonitorUrl(monitorInfo) }),
|
||||
labels,
|
||||
}
|
||||
};
|
||||
|
||||
|
46
server/notification-providers/smspartner.js
Normal file
46
server/notification-providers/smspartner.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
|
||||
class SMSPartner extends NotificationProvider {
|
||||
name = "SMSPartner";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
const okMsg = "Sent Successfully.";
|
||||
const url = "https://api.smspartner.fr/v1/send";
|
||||
|
||||
try {
|
||||
// smspartner does not support non ascii characters and only a maximum 639 characters
|
||||
let cleanMsg = msg.replace(/[^\x00-\x7F]/g, "").substring(0, 639);
|
||||
|
||||
let data = {
|
||||
"apiKey": notification.smspartnerApikey,
|
||||
"sender": notification.smspartnerSenderName.substring(0, 11),
|
||||
"phoneNumbers": notification.smspartnerPhoneNumber,
|
||||
"message": cleanMsg,
|
||||
};
|
||||
|
||||
let config = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"cache-control": "no-cache",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
};
|
||||
|
||||
let resp = await axios.post(url, data, config);
|
||||
|
||||
if (resp.data.success !== true) {
|
||||
throw Error(`Api returned ${resp.data.response.status}.`);
|
||||
}
|
||||
|
||||
return okMsg;
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SMSPartner;
|
@@ -5,6 +5,7 @@ const AlertNow = require("./notification-providers/alertnow");
|
||||
const AliyunSms = require("./notification-providers/aliyun-sms");
|
||||
const Apprise = require("./notification-providers/apprise");
|
||||
const Bark = require("./notification-providers/bark");
|
||||
const Bitrix24 = require("./notification-providers/bitrix24");
|
||||
const ClickSendSMS = require("./notification-providers/clicksendsms");
|
||||
const CallMeBot = require("./notification-providers/call-me-bot");
|
||||
const SMSC = require("./notification-providers/smsc");
|
||||
@@ -42,6 +43,7 @@ const RocketChat = require("./notification-providers/rocket-chat");
|
||||
const SerwerSMS = require("./notification-providers/serwersms");
|
||||
const Signal = require("./notification-providers/signal");
|
||||
const Slack = require("./notification-providers/slack");
|
||||
const SMSPartner = require("./notification-providers/smspartner");
|
||||
const SMSEagle = require("./notification-providers/smseagle");
|
||||
const SMTP = require("./notification-providers/smtp");
|
||||
const Squadcast = require("./notification-providers/squadcast");
|
||||
@@ -83,6 +85,7 @@ class Notification {
|
||||
new AliyunSms(),
|
||||
new Apprise(),
|
||||
new Bark(),
|
||||
new Bitrix24(),
|
||||
new ClickSendSMS(),
|
||||
new CallMeBot(),
|
||||
new SMSC(),
|
||||
@@ -121,6 +124,7 @@ class Notification {
|
||||
new SerwerSMS(),
|
||||
new Signal(),
|
||||
new SMSManager(),
|
||||
new SMSPartner(),
|
||||
new Slack(),
|
||||
new SMSEagle(),
|
||||
new SMTP(),
|
||||
|
@@ -44,9 +44,8 @@ router.get("/api/entry-page", async (request, response) => {
|
||||
response.json(result);
|
||||
});
|
||||
|
||||
router.get("/api/push/:pushToken", async (request, response) => {
|
||||
router.all("/api/push/:pushToken", async (request, response) => {
|
||||
try {
|
||||
|
||||
let pushToken = request.params.pushToken;
|
||||
let msg = request.query.msg || "OK";
|
||||
let ping = parseFloat(request.query.ping) || null;
|
||||
|
@@ -149,6 +149,7 @@ const apicache = require("./modules/apicache");
|
||||
const { resetChrome } = require("./monitor-types/real-browser-monitor-type");
|
||||
const { EmbeddedMariaDB } = require("./embedded-mariadb");
|
||||
const { SetupDatabase } = require("./setup-database");
|
||||
const { chartSocketHandler } = require("./socket-handlers/chart-socket-handler");
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
@@ -1532,6 +1533,7 @@ let needSetup = false;
|
||||
apiKeySocketHandler(socket);
|
||||
remoteBrowserSocketHandler(socket);
|
||||
generalSocketHandler(socket, server);
|
||||
chartSocketHandler(socket);
|
||||
|
||||
log.debug("server", "added all socket handlers");
|
||||
|
||||
|
38
server/socket-handlers/chart-socket-handler.js
Normal file
38
server/socket-handlers/chart-socket-handler.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const { checkLogin } = require("../util-server");
|
||||
const { UptimeCalculator } = require("../uptime-calculator");
|
||||
const { log } = require("../../src/util");
|
||||
|
||||
module.exports.chartSocketHandler = (socket) => {
|
||||
socket.on("getMonitorChartData", async (monitorID, period, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
log.debug("monitor", `Get Monitor Chart Data: ${monitorID} User ID: ${socket.userID}`);
|
||||
|
||||
if (period == null) {
|
||||
throw new Error("Invalid period.");
|
||||
}
|
||||
|
||||
let uptimeCalculator = await UptimeCalculator.getUptimeCalculator(monitorID);
|
||||
|
||||
let data;
|
||||
if (period <= 24) {
|
||||
data = uptimeCalculator.getDataArray(period * 60, "minute");
|
||||
} else if (period <= 720) {
|
||||
data = uptimeCalculator.getDataArray(period, "hour");
|
||||
} else {
|
||||
data = uptimeCalculator.getDataArray(period / 24, "day");
|
||||
}
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
data,
|
||||
});
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
@@ -148,13 +148,14 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||
config.logo = `/upload/${filename}?t=` + Date.now();
|
||||
|
||||
} else {
|
||||
config.icon = imgDataUrl;
|
||||
config.logo = imgDataUrl;
|
||||
}
|
||||
|
||||
statusPage.slug = config.slug;
|
||||
statusPage.title = config.title;
|
||||
statusPage.description = config.description;
|
||||
statusPage.icon = config.logo;
|
||||
statusPage.autoRefreshInterval = config.autoRefreshInterval,
|
||||
statusPage.theme = config.theme;
|
||||
//statusPage.published = ;
|
||||
//statusPage.search_engine_index = ;
|
||||
@@ -280,6 +281,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||
statusPage.title = title;
|
||||
statusPage.theme = "auto";
|
||||
statusPage.icon = "";
|
||||
statusPage.autoRefreshInterval = 300;
|
||||
await R.store(statusPage);
|
||||
|
||||
callback({
|
||||
|
@@ -290,7 +290,7 @@ class UptimeCalculator {
|
||||
dailyStatBean.pingMax = dailyData.maxPing;
|
||||
{
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { up, down, avgPing, minPing, maxPing, ...extras } = dailyData;
|
||||
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = dailyData;
|
||||
if (Object.keys(extras).length > 0) {
|
||||
dailyStatBean.extras = JSON.stringify(extras);
|
||||
}
|
||||
@@ -305,7 +305,7 @@ class UptimeCalculator {
|
||||
hourlyStatBean.pingMax = hourlyData.maxPing;
|
||||
{
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { up, down, avgPing, minPing, maxPing, ...extras } = hourlyData;
|
||||
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = hourlyData;
|
||||
if (Object.keys(extras).length > 0) {
|
||||
hourlyStatBean.extras = JSON.stringify(extras);
|
||||
}
|
||||
@@ -320,7 +320,7 @@ class UptimeCalculator {
|
||||
minutelyStatBean.pingMax = minutelyData.maxPing;
|
||||
{
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { up, down, avgPing, minPing, maxPing, ...extras } = minutelyData;
|
||||
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = minutelyData;
|
||||
if (Object.keys(extras).length > 0) {
|
||||
minutelyStatBean.extras = JSON.stringify(extras);
|
||||
}
|
||||
|
@@ -114,6 +114,7 @@ class UptimeKumaServer {
|
||||
UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType();
|
||||
|
||||
// Allow all CORS origins (polling) in development
|
||||
let cors = undefined;
|
||||
@@ -518,3 +519,4 @@ const { TailscalePing } = require("./monitor-types/tailscale-ping");
|
||||
const { DnsMonitorType } = require("./monitor-types/dns");
|
||||
const { MqttMonitorType } = require("./monitor-types/mqtt");
|
||||
const { SNMPMonitorType } = require("./monitor-types/snmp");
|
||||
const { MongodbMonitorType } = require("./monitor-types/mongodb");
|
||||
|
@@ -11,7 +11,6 @@ const mssql = require("mssql");
|
||||
const { Client } = require("pg");
|
||||
const postgresConParse = require("pg-connection-string").parse;
|
||||
const mysql = require("mysql2");
|
||||
const { MongoClient } = require("mongodb");
|
||||
const { NtlmClient } = require("axios-ntlm");
|
||||
const { Settings } = require("./settings");
|
||||
const grpc = require("@grpc/grpc-js");
|
||||
@@ -437,24 +436,6 @@ exports.mysqlQuery = function (connectionString, query, password = undefined) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect to and ping a MongoDB database
|
||||
* @param {string} connectionString The database connection string
|
||||
* @returns {Promise<(string[] | object[] | object)>} Response from
|
||||
* server
|
||||
*/
|
||||
exports.mongodbPing = async function (connectionString) {
|
||||
let client = await MongoClient.connect(connectionString);
|
||||
let dbPing = await client.db().command({ ping: 1 });
|
||||
await client.close();
|
||||
|
||||
if (dbPing["ok"] === 1) {
|
||||
return "UP";
|
||||
} else {
|
||||
throw Error("failed");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Query radius server
|
||||
* @param {string} hostname Hostname of radius server
|
||||
@@ -505,12 +486,16 @@ exports.radius = function (
|
||||
/**
|
||||
* Redis server ping
|
||||
* @param {string} dsn The redis connection string
|
||||
* @returns {Promise<any>} Response from redis server
|
||||
* @param {boolean} rejectUnauthorized If false, allows unverified server certificates.
|
||||
* @returns {Promise<any>} Response from server
|
||||
*/
|
||||
exports.redisPingAsync = function (dsn) {
|
||||
exports.redisPingAsync = function (dsn, rejectUnauthorized) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = redis.createClient({
|
||||
url: dsn
|
||||
url: dsn,
|
||||
socket: {
|
||||
rejectUnauthorized
|
||||
}
|
||||
});
|
||||
client.on("error", (err) => {
|
||||
if (client.isOpen) {
|
||||
|
Reference in New Issue
Block a user