diff --git a/package-lock.json b/package-lock.json index c6e18b9c..37850567 100644 --- a/package-lock.json +++ b/package-lock.json @@ -133,6 +133,15 @@ "node": "14.* || 16.* || 18.*" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@actions/github": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz", @@ -15193,17 +15202,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" diff --git a/server/database.js b/server/database.js index c02c70c6..bd7c7647 100644 --- a/server/database.js +++ b/server/database.js @@ -3,7 +3,7 @@ const { R } = require("redbean-node"); const { setSetting, setting } = require("./util-server"); const { log, sleep } = require("../src/util"); const knex = require("knex"); -const { PluginsManager } = require("./plugins-manager"); + /** * Database & App Data Folder @@ -88,12 +88,6 @@ class Database { // 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/git.js b/server/git.js deleted file mode 100644 index 77a12d93..00000000 --- a/server/git.js +++ /dev/null @@ -1,24 +0,0 @@ -const childProcess = require("child_process"); - -class Git { - - static clone(repoURL, cwd, targetDir = ".") { - let result = childProcess.spawnSync("git", [ - "clone", - repoURL, - targetDir, - ], { - cwd: cwd, - }); - - if (result.status !== 0) { - throw new Error(result.stderr.toString("utf-8")); - } else { - return result.stdout.toString("utf-8") + result.stderr.toString("utf-8"); - } - } -} - -module.exports = { - Git, -}; diff --git a/server/plugin.js b/server/plugin.js deleted file mode 100644 index 8b687ad6..00000000 --- a/server/plugin.js +++ /dev/null @@ -1,13 +0,0 @@ -class Plugin { - async load() { - - } - - async unload() { - - } -} - -module.exports = { - Plugin, -}; diff --git a/server/plugins-manager.js b/server/plugins-manager.js deleted file mode 100644 index 674ab969..00000000 --- a/server/plugins-manager.js +++ /dev/null @@ -1,256 +0,0 @@ -const fs = require("fs"); -const { log } = require("../src/util"); -const path = require("path"); -const axios = require("axios"); -const { Git } = require("./git"); -const childProcess = require("child_process"); - -class PluginsManager { - - static disable = false; - - /** - * Plugin List - * @type {PluginWrapper[]} - */ - pluginList = []; - - /** - * Plugins Dir - */ - pluginsDir; - - server; - - /** - * - * @param {UptimeKumaServer} server - */ - constructor(server) { - this.server = 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) { - this.loadPlugin(item); - } - - } else { - log.warn("PLUGIN", "Skip scanning plugin directory"); - } - - } - - /** - * Install a Plugin - */ - async loadPlugin(name) { - log.info("plugin", "Load " + name); - let plugin = new PluginWrapper(this.server, this.pluginsDir + name); - - try { - await plugin.load(); - this.pluginList.push(plugin); - } catch (e) { - log.error("plugin", "Failed to load plugin: " + this.pluginsDir + name); - log.error("plugin", "Reason: " + e.message); - } - } - - /** - * Download a Plugin - * @param {string} repoURL Git repo url - * @param {string} name Directory name, also known as plugin unique name - */ - downloadPlugin(repoURL, name) { - if (fs.existsSync(this.pluginsDir + name)) { - log.info("plugin", "Plugin folder already exists? Removing..."); - fs.rmSync(this.pluginsDir + name, { - recursive: true - }); - } - log.info("plugin", "Installing plugin: " + name + " " + repoURL); - let result = Git.clone(repoURL, this.pluginsDir, name); - log.info("plugin", "Install result: " + result); - } - - /** - * Remove a plugin - * @param {string} name - */ - async removePlugin(name) { - log.info("plugin", "Removing plugin: " + name); - for (let plugin of this.pluginList) { - if (plugin.info.name === name) { - await plugin.unload(); - - // Delete the plugin directory - fs.rmSync(this.pluginsDir + name, { - recursive: true - }); - - this.pluginList.splice(this.pluginList.indexOf(plugin), 1); - return; - } - } - log.warn("plugin", "Plugin not found: " + name); - throw new Error("Plugin not found: " + name); - } - - /** - * TODO: Update a plugin - * Only available for plugins which were downloaded from the official list - * @param pluginID - */ - updatePlugin(pluginID) { - - } - - /** - * Get the plugin list from server + local installed plugin list - * Item will be merged if the `name` is the same. - * @returns {Promise<[]>} - */ - async fetchPluginList() { - let remotePluginList; - try { - const res = await axios.get("https://uptime.kuma.pet/c/plugins.json"); - remotePluginList = res.data.pluginList; - } catch (e) { - log.error("plugin", "Failed to fetch plugin list: " + e.message); - remotePluginList = []; - } - - for (let plugin of this.pluginList) { - let find = false; - // Try to merge - for (let remotePlugin of remotePluginList) { - if (remotePlugin.name === plugin.info.name) { - find = true; - remotePlugin.installed = true; - remotePlugin.name = plugin.info.name; - remotePlugin.fullName = plugin.info.fullName; - remotePlugin.description = plugin.info.description; - remotePlugin.version = plugin.info.version; - break; - } - } - - // Local plugin - if (!find) { - plugin.info.local = true; - remotePluginList.push(plugin.info); - } - } - - // Sort Installed first, then sort by name - return remotePluginList.sort((a, b) => { - if (a.installed === b.installed) { - if (a.fullName < b.fullName) { - return -1; - } - if (a.fullName > b.fullName) { - return 1; - } - return 0; - } else if (a.installed) { - return -1; - } else { - return 1; - } - }); - } -} - -class PluginWrapper { - - server = undefined; - pluginDir = undefined; - - /** - * Must be an `new-able` class. - * @type {function} - */ - pluginClass = undefined; - - /** - * - * @type {Plugin} - */ - object = undefined; - info = {}; - - /** - * - * @param {UptimeKumaServer} server - * @param {string} pluginDir - */ - constructor(server, pluginDir) { - this.server = server; - this.pluginDir = pluginDir; - } - - async load() { - let indexFile = this.pluginDir + "/index.js"; - let packageJSON = this.pluginDir + "/package.json"; - - log.info("plugin", "Installing dependencies"); - - if (fs.existsSync(indexFile)) { - // Install dependencies - let result = childProcess.spawnSync("npm", [ "install" ], { - cwd: this.pluginDir, - env: { - ...process.env, - PLAYWRIGHT_BROWSERS_PATH: "../../browsers", // Special handling for read-browser-monitor - } - }); - - if (result.stdout) { - log.info("plugin", "Install dependencies result: " + result.stdout.toString("utf-8")); - } else { - log.warn("plugin", "Install dependencies result: no output"); - } - - this.pluginClass = require(path.join(process.cwd(), indexFile)); - - let pluginClassType = typeof this.pluginClass; - - if (pluginClassType === "function") { - this.object = new this.pluginClass(this.server); - await this.object.load(); - } else { - throw new Error("Invalid plugin, it does not export a class"); - } - - if (fs.existsSync(packageJSON)) { - this.info = require(path.join(process.cwd(), packageJSON)); - } else { - this.info.fullName = this.pluginDir; - this.info.name = "[unknown]"; - this.info.version = "[unknown-version]"; - } - - this.info.installed = true; - log.info("plugin", `${this.info.fullName} v${this.info.version} loaded`); - } - } - - async unload() { - await this.object.unload(); - } -} - -module.exports = { - PluginsManager, - PluginWrapper -}; diff --git a/server/server.js b/server/server.js index 20b2fdfe..cc19bbd9 100644 --- a/server/server.js +++ b/server/server.js @@ -147,7 +147,6 @@ const { apiKeySocketHandler } = require("./socket-handlers/api-key-socket-handle const { generalSocketHandler } = require("./socket-handlers/general-socket-handler"); const { Settings } = require("./settings"); const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); -const { pluginsHandler } = require("./socket-handlers/plugins-handler"); const apicache = require("./modules/apicache"); app.use(express.json()); @@ -177,7 +176,6 @@ let needSetup = false; Database.init(args); await initDatabase(testMode); await server.initAfterDatabaseReady(); - server.loadPlugins(); server.entryPage = await Settings.get("entryPage"); await StatusPage.loadDomainMappingList(); @@ -1537,7 +1535,6 @@ let needSetup = false; maintenanceSocketHandler(socket); apiKeySocketHandler(socket); generalSocketHandler(socket, server); - pluginsHandler(socket, server); log.debug("server", "added all socket handlers"); diff --git a/server/socket-handlers/plugins-handler.js b/server/socket-handlers/plugins-handler.js deleted file mode 100644 index 533da309..00000000 --- a/server/socket-handlers/plugins-handler.js +++ /dev/null @@ -1,69 +0,0 @@ -const { checkLogin } = require("../util-server"); -const { PluginsManager } = require("../plugins-manager"); -const { log } = require("../../src/util.js"); - -/** - * Handlers for plugins - * @param {Socket} socket Socket.io instance - * @param {UptimeKumaServer} server - */ -module.exports.pluginsHandler = (socket, server) => { - - const pluginManager = server.getPluginManager(); - - // Get Plugin List - socket.on("getPluginList", async (callback) => { - try { - checkLogin(socket); - - log.debug("plugin", "PluginManager.disable: " + PluginsManager.disable); - - if (PluginsManager.disable) { - throw new Error("Plugin Disabled: In order to enable plugin feature, you need to use the default data directory: ./data/"); - } - - let pluginList = await pluginManager.fetchPluginList(); - callback({ - ok: true, - pluginList, - }); - } catch (error) { - log.warn("plugin", "Error: " + error.message); - callback({ - ok: false, - msg: error.message, - }); - } - }); - - socket.on("installPlugin", async (repoURL, name, callback) => { - try { - checkLogin(socket); - pluginManager.downloadPlugin(repoURL, name); - await pluginManager.loadPlugin(name); - callback({ - ok: true, - }); - } catch (error) { - callback({ - ok: false, - msg: error.message, - }); - } - }); - - socket.on("uninstallPlugin", async (name, callback) => { - try { - checkLogin(socket); - await pluginManager.removePlugin(name); - callback({ - ok: true, - }); - } catch (error) { - callback({ - ok: false, - msg: error.message, - }); - } - }); -}; diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 914e12e4..9af32b8b 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -10,7 +10,6 @@ const util = require("util"); const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); const { Settings } = require("./settings"); const dayjs = require("dayjs"); -const { PluginsManager } = require("./plugins-manager"); // DO NOT IMPORT HERE IF THE MODULES USED `UptimeKumaServer.getInstance()` /** @@ -47,12 +46,6 @@ class UptimeKumaServer { */ indexHTML = ""; - /** - * Plugins Manager - * @type {PluginsManager} - */ - pluginsManager = null; - /** * * @type {{}} @@ -289,46 +282,6 @@ class UptimeKumaServer { async stop() { } - - loadPlugins() { - this.pluginsManager = new PluginsManager(this); - } - - /** - * - * @returns {PluginsManager} - */ - getPluginManager() { - return this.pluginsManager; - } - - /** - * - * @param {MonitorType} monitorType - */ - addMonitorType(monitorType) { - 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); - } - } - } module.exports = { diff --git a/src/components/PluginItem.vue b/src/components/PluginItem.vue deleted file mode 100644 index 4925bc9c..00000000 --- a/src/components/PluginItem.vue +++ /dev/null @@ -1,102 +0,0 @@ - - - - - diff --git a/src/components/settings/Plugins.vue b/src/components/settings/Plugins.vue deleted file mode 100644 index 614034fc..00000000 --- a/src/components/settings/Plugins.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index d3c153df..f3c6b776 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -116,12 +116,6 @@ export default { backup: { title: this.$t("Backup"), }, - /* - Hidden for now: Unfortunately, after some test, I found that Playwright requires a lot of libraries to be installed on the Linux host in order to start Chrome or Firefox. - It will be hard to install, so I hide this feature for now. But it still accessible via URL: /settings/plugins. - plugins: { - title: this.$tc("plugin", 2), - },*/ about: { title: this.$t("About"), }, diff --git a/src/router.js b/src/router.js index 4d5293b8..a8644805 100644 --- a/src/router.js +++ b/src/router.js @@ -19,7 +19,6 @@ import DockerHosts from "./components/settings/Docker.vue"; import MaintenanceDetails from "./pages/MaintenanceDetails.vue"; import ManageMaintenance from "./pages/ManageMaintenance.vue"; import APIKeys from "./components/settings/APIKeys.vue"; -import Plugins from "./components/settings/Plugins.vue"; // Settings - Sub Pages import Appearance from "./components/settings/Appearance.vue"; @@ -130,10 +129,6 @@ const routes = [ path: "backup", component: Backup, }, - { - path: "plugins", - component: Plugins, - }, { path: "about", component: About,