mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-08-08 16:07:20 +08:00
add telegram notification
This commit is contained in:
@@ -141,71 +141,52 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Uptime with calculation
|
||||
* Calculation based on:
|
||||
* https://www.uptrends.com/support/kb/reporting/calculation-of-uptime-and-downtime
|
||||
* @param duration : int Hours
|
||||
*/
|
||||
static async sendUptime(duration, io, monitorID, userID) {
|
||||
let sec = duration * 3600;
|
||||
|
||||
let downtimeList = await R.getAll(`
|
||||
SELECT duration, time
|
||||
SELECT duration, time, status
|
||||
FROM heartbeat
|
||||
WHERE time > DATE('now', ? || ' hours')
|
||||
AND status = 0
|
||||
AND monitor_id = ? `, [
|
||||
-duration,
|
||||
monitorID
|
||||
]);
|
||||
|
||||
let downtime = 0;
|
||||
let uptime = 0;
|
||||
let total = 0;
|
||||
let uptime;
|
||||
|
||||
if (downtimeList.length === 0) {
|
||||
for (let row of downtimeList) {
|
||||
let value = parseInt(row.duration)
|
||||
let time = row.time
|
||||
for (let row of downtimeList) {
|
||||
let value = parseInt(row.duration)
|
||||
let time = row.time
|
||||
|
||||
// Handle if heartbeat duration longer than the target duration
|
||||
// e.g. Heartbeat duration = 28hrs, but target duration = 24hrs
|
||||
if (value <= sec) {
|
||||
downtime += value;
|
||||
} else {
|
||||
let trim = dayjs.utc().diff(dayjs(time), 'second');
|
||||
// Handle if heartbeat duration longer than the target duration
|
||||
// e.g. Heartbeat duration = 28hrs, but target duration = 24hrs
|
||||
if (value > sec) {
|
||||
let trim = dayjs.utc().diff(dayjs(time), 'second');
|
||||
value = sec - trim;
|
||||
|
||||
value = sec - trim;
|
||||
|
||||
if (value < 0) {
|
||||
value = 0;
|
||||
}
|
||||
downtime += value;
|
||||
if (value < 0) {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uptime = (sec - downtime) / sec;
|
||||
|
||||
if (uptime < 0) {
|
||||
uptime = 0;
|
||||
total += value;
|
||||
if (row.status === 0) {
|
||||
downtime += value;
|
||||
}
|
||||
} else {
|
||||
// This case for someone who are not running UptimeKuma 24x7.
|
||||
// If there is no heartbeat in this time range, use last heartbeat as reference
|
||||
// If is down, uptime = 0
|
||||
// If is up, uptime = 1
|
||||
}
|
||||
|
||||
let lastHeartbeat = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [
|
||||
monitorID
|
||||
]);
|
||||
uptime = (total - downtime) / total;
|
||||
|
||||
if (lastHeartbeat) {
|
||||
if (lastHeartbeat.status === 1) {
|
||||
uptime = 1;
|
||||
} else {
|
||||
uptime = 0;
|
||||
}
|
||||
} else {
|
||||
// No heartbeat is found, assume 100%
|
||||
uptime = 1;
|
||||
}
|
||||
if (uptime < 0) {
|
||||
uptime = 0;
|
||||
}
|
||||
|
||||
io.to(userID).emit("uptime", monitorID, duration, uptime);
|
||||
|
58
server/notification.js
Normal file
58
server/notification.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const axios = require("axios");
|
||||
const {R} = require("redbean-node");
|
||||
|
||||
class Notification {
|
||||
static async send(notification, msg) {
|
||||
if (notification.type === "telegram") {
|
||||
let res = await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
||||
params: {
|
||||
chat_id: notification.telegramChatID,
|
||||
text: msg,
|
||||
}
|
||||
})
|
||||
return true;
|
||||
} else {
|
||||
throw new Error("Notification type is not supported")
|
||||
}
|
||||
}
|
||||
|
||||
static async save(notification, notificationID, userID) {
|
||||
let bean
|
||||
|
||||
if (notificationID) {
|
||||
bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
|
||||
notificationID,
|
||||
userID,
|
||||
])
|
||||
|
||||
if (! bean) {
|
||||
throw new Error("notification not found")
|
||||
}
|
||||
|
||||
} else {
|
||||
bean = R.dispense("notification")
|
||||
}
|
||||
|
||||
bean.name = notification.name;
|
||||
bean.user_id = userID;
|
||||
bean.config = JSON.stringify(notification)
|
||||
await R.store(bean)
|
||||
}
|
||||
|
||||
static async delete(notificationID, userID) {
|
||||
let bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
|
||||
notificationID,
|
||||
userID,
|
||||
])
|
||||
|
||||
if (! bean) {
|
||||
throw new Error("notification not found")
|
||||
}
|
||||
|
||||
await R.trash(bean)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Notification,
|
||||
}
|
@@ -10,6 +10,7 @@ const passwordHash = require('password-hash');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const Monitor = require("./model/monitor");
|
||||
const {getSettings} = require("./util-server");
|
||||
const {Notification} = require("./notification")
|
||||
|
||||
let totalClient = 0;
|
||||
let jwtSecret = null;
|
||||
@@ -26,6 +27,10 @@ let monitorList = {};
|
||||
|
||||
app.use('/', express.static("dist"));
|
||||
|
||||
app.get('*', function(request, response, next) {
|
||||
response.sendFile(process.cwd() + '/dist/index.html');
|
||||
});
|
||||
|
||||
io.on('connection', async (socket) => {
|
||||
console.log('a user connected');
|
||||
totalClient++;
|
||||
@@ -318,6 +323,65 @@ let monitorList = {};
|
||||
}
|
||||
});
|
||||
|
||||
// Add or Edit
|
||||
socket.on("addNotification", async (notification, notificationID, callback) => {
|
||||
try {
|
||||
checkLogin(socket)
|
||||
|
||||
await Notification.save(notification, notificationID, socket.userID)
|
||||
await sendNotificationList(socket)
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Saved",
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("deleteNotification", async (notificationID, callback) => {
|
||||
try {
|
||||
checkLogin(socket)
|
||||
|
||||
await Notification.delete(notificationID, socket.userID)
|
||||
await sendNotificationList(socket)
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Deleted",
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("testNotification", async (notification, callback) => {
|
||||
try {
|
||||
checkLogin(socket)
|
||||
|
||||
await Notification.send(notification, notification.name + " Testing")
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Sent Successfully"
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(3001, () => {
|
||||
@@ -344,6 +408,20 @@ async function sendMonitorList(socket) {
|
||||
return list;
|
||||
}
|
||||
|
||||
async function sendNotificationList(socket) {
|
||||
let result = [];
|
||||
let list = await R.find("notification", " user_id = ? ", [
|
||||
socket.userID
|
||||
]);
|
||||
|
||||
for (let bean of list) {
|
||||
result.push(bean.export())
|
||||
}
|
||||
|
||||
io.to(socket.userID).emit("notificationList", result)
|
||||
return list;
|
||||
}
|
||||
|
||||
async function afterLogin(socket, user) {
|
||||
socket.userID = user.id;
|
||||
socket.join(user.id)
|
||||
@@ -355,6 +433,8 @@ async function afterLogin(socket, user) {
|
||||
await sendImportantHeartbeatList(socket, monitorID);
|
||||
await Monitor.sendStats(io, monitorID, user.id)
|
||||
}
|
||||
|
||||
await sendNotificationList(socket)
|
||||
}
|
||||
|
||||
async function getMonitorJSONList(userID) {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
const tcpp = require('tcp-ping');
|
||||
const Ping = require("./ping-lite");
|
||||
const {R} = require("redbean-node");
|
||||
|
||||
exports.tcping = function (hostname, port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -37,3 +38,25 @@ exports.ping = function (hostname) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exports.setting = async function (key) {
|
||||
return await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
|
||||
key
|
||||
])
|
||||
}
|
||||
|
||||
exports.getSettings = async function (type) {
|
||||
let list = await R.getAll("SELECT * FROM setting WHERE `type` = ? ", [
|
||||
type
|
||||
])
|
||||
|
||||
let result = {};
|
||||
|
||||
for (let row of list) {
|
||||
result[row.key] = row.value;
|
||||
}
|
||||
|
||||
console.log(result)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -10,6 +10,10 @@ export function sleep(ms) {
|
||||
}
|
||||
|
||||
export function ucfirst(str) {
|
||||
if (! str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
const firstLetter = str.substr(0, 1);
|
||||
return firstLetter.toUpperCase() + str.substr(1);
|
||||
}
|
||||
|
Reference in New Issue
Block a user