From 7bcef8edf995fa11c5f6e55eacf7921fc7a3a39e Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Mon, 9 Jan 2023 00:35:52 +0800 Subject: [PATCH] WIP --- server/database.js | 8 +++++ server/model/monitor.js | 9 +++++ server/monitor-types/monitor-type.js | 16 ++++++++- server/plugin.js | 13 +++++++ server/plugins-manager.js | 52 +++++++++++++++------------ server/server.js | 2 +- server/uptime-kuma-server.js | 36 +++++++++++++++++-- src/pages/EditMonitor.vue | 8 ++--- src/util.js | Bin 12207 -> 12207 bytes 9 files changed, 114 insertions(+), 30 deletions(-) create mode 100644 server/plugin.js diff --git a/server/database.js b/server/database.js index 2544f197..bc6c5cfc 100644 --- a/server/database.js +++ b/server/database.js @@ -4,6 +4,7 @@ const { setSetting, setting } = require("./util-server"); const { log, sleep } = require("../src/util"); const dayjs = require("dayjs"); const knex = require("knex"); +const { PluginsManager } = require("./plugins-manager"); /** * Database & App Data Folder @@ -83,6 +84,13 @@ class Database { static init(args) { // Data Directory (must be end with "/") Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/"; + + // Plugin feature is working only if the dataDir = "./data"; + if (Database.dataDir !== "./data/") { + log.warn("PLUGIN", "Warning: In order to enable plugin feature, you need to use the default data directory: ./data/"); + PluginsManager.disable = true; + } + Database.path = Database.dataDir + "kuma.db"; if (! fs.existsSync(Database.dataDir)) { fs.mkdirSync(Database.dataDir, { recursive: true }); diff --git a/server/model/monitor.js b/server/model/monitor.js index 9f8c8300..fbe44b76 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -617,6 +617,15 @@ class Monitor extends BeanModel { } } bean.ping = dayjs().valueOf() - startTime; + + } else if (this.type in UptimeKumaServer.monitorTypeList) { + let startTime = dayjs().valueOf(); + const monitorType = UptimeKumaServer.monitorTypeList[this.type]; + await monitorType.check(this, bean); + if (!bean.ping) { + bean.ping = dayjs().valueOf() - startTime; + } + } else { bean.msg = "Unknown Monitor Type"; bean.status = PENDING; diff --git a/server/monitor-types/monitor-type.js b/server/monitor-types/monitor-type.js index f3b4f709..f2c7cbee 100644 --- a/server/monitor-types/monitor-type.js +++ b/server/monitor-types/monitor-type.js @@ -1,5 +1,19 @@ class MonitorType { + name = undefined; + + /** + * + * @param {Monitor} monitor + * @param {Heartbeat} heartbeat + * @returns {Promise} + */ + async check(monitor, heartbeat) { + throw new Error("You need to override check()"); + } + } -module.exports = MonitorType; +module.exports = { + MonitorType, +}; diff --git a/server/plugin.js b/server/plugin.js new file mode 100644 index 00000000..77e09551 --- /dev/null +++ b/server/plugin.js @@ -0,0 +1,13 @@ +class Plugin { + async install() { + + } + + async uninstall() { + + } +} + +module.exports = { + Plugin, +}; diff --git a/server/plugins-manager.js b/server/plugins-manager.js index d0d9452c..837b7aae 100644 --- a/server/plugins-manager.js +++ b/server/plugins-manager.js @@ -4,9 +4,11 @@ const path = require("path"); class PluginsManager { + static disable = false; + /** * Plugin List - * @type {Plugin[]} + * @type {PluginWrapper[]} */ pluginList = []; @@ -20,28 +22,34 @@ class PluginsManager { * @param {UptimeKumaServer} server * @param {string} dir */ - constructor(server, dir) { - this.pluginsDir = dir; + constructor(server) { + if (!PluginsManager.disable) { + this.pluginsDir = "./data/plugins/"; - if (! fs.existsSync(this.pluginsDir)) { - fs.mkdirSync(this.pluginsDir, { recursive: true }); - } - - log.debug("plugin", "Scanning plugin directory"); - let list = fs.readdirSync(this.pluginsDir); - - this.pluginList = []; - for (let item of list) { - let plugin = new Plugin(server, this.pluginsDir + item); - - try { - plugin.load(); - this.pluginList.push(plugin); - } catch (e) { - log.error("plugin", "Failed to load plugin: " + this.pluginsDir + item); - log.error("plugin", "Reason: " + e.message); + if (! fs.existsSync(this.pluginsDir)) { + fs.mkdirSync(this.pluginsDir, { recursive: true }); } + + log.debug("plugin", "Scanning plugin directory"); + let list = fs.readdirSync(this.pluginsDir); + + this.pluginList = []; + for (let item of list) { + let plugin = new PluginWrapper(server, this.pluginsDir + item); + + try { + plugin.load(); + this.pluginList.push(plugin); + } catch (e) { + log.error("plugin", "Failed to load plugin: " + this.pluginsDir + item); + log.error("plugin", "Reason: " + e.message); + } + } + + } else { + log.warn("PLUGIN", "Skip scanning plugin directory"); } + } /** @@ -71,7 +79,7 @@ class PluginsManager { } } -class Plugin { +class PluginWrapper { server = undefined; pluginDir = undefined; @@ -129,5 +137,5 @@ class Plugin { module.exports = { PluginsManager, - Plugin + PluginWrapper }; diff --git a/server/server.js b/server/server.js index 2d81b1af..1bd2d0d4 100644 --- a/server/server.js +++ b/server/server.js @@ -167,7 +167,7 @@ let needSetup = false; Database.init(args); await initDatabase(testMode); await server.initAfterDatabaseReady(); - server.loadPlugins(Database.dataDir + "plugins/"); + server.loadPlugins(); server.entryPage = await Settings.get("entryPage"); await StatusPage.loadDomainMappingList(); diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index ebd4082c..892df2b1 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -55,6 +55,14 @@ class UptimeKumaServer { */ pluginsManager = null; + /** + * + * @type {{}} + */ + static monitorTypeList = { + + }; + static getInstance(args) { if (UptimeKumaServer.instance == null) { UptimeKumaServer.instance = new UptimeKumaServer(args); @@ -249,11 +257,34 @@ class UptimeKumaServer { } loadPlugins(dir) { - this.pluginsManager = new PluginsManager(this, dir); + this.pluginsManager = new PluginsManager(this); } + /** + * + * @param {MonitorType} monitorType + */ addMonitorType(monitorType) { - // TODO + if (monitorType instanceof MonitorType && monitorType.name) { + if (monitorType.name in UptimeKumaServer.monitorTypeList) { + log.error("", "Conflict Monitor Type name"); + } + UptimeKumaServer.monitorTypeList[monitorType.name] = monitorType; + } else { + log.error("", "Invalid Monitor Type: " + monitorType.name); + } + } + + /** + * + * @param {MonitorType} monitorType + */ + removeMonitorType(monitorType) { + if (UptimeKumaServer.monitorTypeList[monitorType.name] === monitorType) { + delete UptimeKumaServer.monitorTypeList[monitorType.name]; + } else { + log.error("", "Remove MonitorType failed: " + monitorType.name); + } } } @@ -264,3 +295,4 @@ module.exports = { // Must be at the end const MaintenanceTimeslot = require("./model/maintenance_timeslot"); +const { MonitorType } = require("./monitor-types/monitor-type"); diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 10293e0c..82a87392 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -64,7 +64,7 @@ @@ -77,7 +77,7 @@ -
+
@@ -99,10 +99,10 @@
-
+
-
+
{{ $t("keywordDescription") }}
diff --git a/src/util.js b/src/util.js index 09e6d0ee7a0dcb4b0d005f9f18d13eab3a468f01..44d29bd81cb134c5aa6b7134ecf225a66c46a788 100644 GIT binary patch literal 12207 zcmeIuF#!Mo0K%a4Pi+ZLh(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM Y7%*VKfB^#r3>YwAz<>b*1`M1B1~0Dw0RR91 literal 12207 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