diff --git a/server/client.js b/server/client.js index fcfddeb5..d75f2900 100644 --- a/server/client.js +++ b/server/client.js @@ -33,13 +33,14 @@ async function sendNotificationList(socket) { async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) { const timeLogger = new TimeLogger(); - let list = await R.find("heartbeat", ` - monitor_id = ? - ORDER BY time DESC - LIMIT 100 - `, [ - monitorID, - ]) + let monitor = userMonitorList.getMonitor(socket.userID, monitorID); + + if (! monitor) { + console.error("No this monitor??"); + return; + } + + let list = monitor.getCachedHeartbeatList().array; let result = []; diff --git a/server/limit-array.js b/server/limit-array.js new file mode 100644 index 00000000..e89b116b --- /dev/null +++ b/server/limit-array.js @@ -0,0 +1,13 @@ +class LimitArray { + limit = 100; + array = []; + + add(item) { + this.array.push(item); + if (this.array.length > this.limit) { + this.array.shift(); + } + } +} + +module.exports = LimitArray; diff --git a/server/model/monitor.js b/server/model/monitor.js index 57815cdd..3b3959ff 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -6,14 +6,20 @@ dayjs.extend(utc) dayjs.extend(timezone) const axios = require("axios"); const { Prometheus } = require("../prometheus"); -const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); +const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger, getRandomInt } = require("../../src/util"); const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification") const { userMonitorList } = require("../user-monitor-list"); +const LimitArray = require("../limit-array"); const version = require("../../package.json").version; +/** + * Master List + */ +const cachedHeartbeatList = {}; + /** * status: * 0 = DOWN @@ -21,6 +27,29 @@ const version = require("../../package.json").version; * 2 = PENDING */ class Monitor extends BeanModel { + + /** + * Cache Last 100 Heartbeat list + * @returns {LimitArray} + */ + getCachedHeartbeatList() { + return cachedHeartbeatList[this.id]; + } + + async onOpen() { + this.beanMeta.extraData = {}; + + cachedHeartbeatList[this.id] = new LimitArray(); + + cachedHeartbeatList[this.id].array = await R.find("heartbeat", ` + monitor_id = ? + ORDER BY time DESC + LIMIT 100 + `, [ + this.id, + ]); + } + async toJSON() { let notificationIDList = {}; @@ -83,7 +112,6 @@ class Monitor extends BeanModel { let prometheus = new Prometheus(this); const beat = async () => { - // Expose here for prometheus update // undefined if not https let tlsInfo = undefined; @@ -302,22 +330,37 @@ class Monitor extends BeanModel { console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Type: ${this.type}`) } + if (! this.beanMeta.extraData.uniqueNumber) { + this.beanMeta.extraData.uniqueNumber = getRandomInt(0, 9999999999); + } + + debug(this.beanMeta.extraData.uniqueNumber); + io.to(this.user_id).emit("heartbeat", bean.toJSON()); Monitor.sendStats(io, this.id, this.user_id) await R.store(bean); + + // Also add to cache + this.getCachedHeartbeatList().add(bean); + prometheus.update(bean, tlsInfo); previousBeat = bean; - this.heartbeatInterval = setTimeout(beat, this.interval * 1000); + if (this.beanMeta.extraData.stop !== true) { + this.heartbeatInterval = setTimeout(beat, this.interval * 1000); + } } beat(); } stop() { + console.log(`[Monitor: ${this.id}] Stop`); + debug("Stop " + this.beanMeta.extraData.uniqueNumber) clearTimeout(this.heartbeatInterval); + this.beanMeta.extraData.stop = true; } /** diff --git a/server/server.js b/server/server.js index 126aa18d..8d61c7cd 100644 --- a/server/server.js +++ b/server/server.js @@ -283,8 +283,7 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); bean.import(monitor) bean.user_id = socket.userID - await R.store(bean) - + await R.store(bean); await updateMonitorNotification(bean.id, notificationIDList) await startMonitor(socket.userID, bean.id); @@ -427,7 +426,6 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); let monitor = userMonitorList.getMonitor(socket.userID, monitorID); if (monitor) { - monitor.stop(); userMonitorList.delete(socket.userID, monitorID); } @@ -678,7 +676,7 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); }); console.log("Starting All Monitors"); - await startMonitors(); + await initMonitors(); console.log("Init the server"); @@ -818,24 +816,18 @@ async function startMonitor(userID, monitorID) { let monitor = await R.findOne("monitor", " id = ? ", [ monitorID, - ]) - - let oldMonitor = userMonitorList.getMonitor(userID, monitorID); - - if (oldMonitor) { - oldMonitor.stop(); - } + ]); userMonitorList.add(userID, monitor); monitor.start(io) } async function restartMonitor(userID, monitorID) { - return await startMonitor(userID, monitorID) + return await startMonitor(userID, monitorID); } async function pauseMonitor(userID, monitorID) { - await checkOwner(userID, monitorID) + await checkOwner(userID, monitorID); console.log(`Pause Monitor: ${monitorID} User ID: ${userID}`) @@ -847,6 +839,7 @@ async function pauseMonitor(userID, monitorID) { let monitor = userMonitorList.getMonitor(userID, monitorID); if (monitor) { + monitor.active = 0; monitor.stop(); } } @@ -854,14 +847,21 @@ async function pauseMonitor(userID, monitorID) { /** * Resume active monitors */ -async function startMonitors() { - let list = await R.find("monitor", " active = 1 "); +async function initMonitors() { + // Init all monitors + let list = await R.find("monitor"); + let activeList = []; for (let monitor of list) { userMonitorList.add(monitor.user_id, monitor); + + if (monitor.active) { + activeList.push(monitor); + } } - delayStartMonitors(list); + // Start active monitors only + delayStartMonitors(activeList); } /** diff --git a/server/user-monitor-list.js b/server/user-monitor-list.js index 053060bd..0ce64fb4 100644 --- a/server/user-monitor-list.js +++ b/server/user-monitor-list.js @@ -4,14 +4,36 @@ class UserMonitorList { list = {}; + /** + * Add or update + * @param userID + * @param monitor + */ add(userID, monitor) { if (! this.list[userID]) { this.list[userID] = {}; } + + // Stopped the old monitor if same id + this.stop(userID, monitor.id); + this.list[userID][monitor.id] = monitor; } + stop(userID, monitorID) { + if (this.list[userID][monitorID]) { + let oldMonitor = this.list[userID][monitorID]; + + if (oldMonitor) { + oldMonitor.stop(); + } else { + console.log("No old monitor: " + monitorID); + } + } + } + delete(userID, monitorID) { + this.stop(userID, monitorID); let monitorList = this.getMonitorList(userID); delete monitorList[monitorID]; }