add telegram notification

This commit is contained in:
LouisLam
2021-07-09 14:14:03 +08:00
parent 04ec91d7a9
commit 3bdf174e90
11 changed files with 418 additions and 85 deletions

View File

@@ -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
View 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,
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);
}