From 63f76ce87a1790513e0e7e01fac593751e898748 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 14:53:45 +0100 Subject: [PATCH 1/8] Rename enabled to load_plugin Rename the config and status indicating whether to load a plugin or not from "Enabled" to "Load Plugin". The latter better describes what it does, and unlike the former doesn't imply plugins can be enabled or disabled on the fly. --- docs/configuration.md | 14 +++++++------- docs/writing-plugins.md | 2 +- packages/lib/config/classes.js | 4 ++-- packages/master/master.js | 6 +++--- packages/slave/slave.js | 2 +- packages/web_ui/src/components/PluginViewPage.jsx | 4 ++-- packages/web_ui/src/components/PluginsPage.jsx | 6 +++--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 889a1eaa..82b631c2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -130,10 +130,10 @@ Role to automatically grant to new users. If null no role is granted. Defaults to 1 which correspond to the default Player role. -### .enabled +### .load_plugin -Whether to enable the given plugin on the master server. Plugins -disabled on the master server will not be loaded on instances. +Whether to load the plugin on the master server. Plugins not loaded on +the master server will not be loaded on instances. Defaults to true. @@ -425,11 +425,11 @@ maximum_segment_size), which is around 20 in normal circumstances. Defaults to 5 -### .enabled +### .load_plugin -Whether to enable the given plugin on the instance. Note that plugins -need to be enabled on the master server in order for them to be loaded -on instances. +Whether to load the given plugin on the instance. Note that plugins +need to be loaded on the master server in order for them to be loaded on +instances. Defaults to true diff --git a/docs/writing-plugins.md b/docs/writing-plugins.md index 1f624fad..b80ace0c 100644 --- a/docs/writing-plugins.md +++ b/docs/writing-plugins.md @@ -115,7 +115,7 @@ The following properties are recognized: for [defining link messages](#defining-link-messages) below. The optional module folder contains a Clusterio module that will be -patched into the save when the plugin is enabled. See the section on +patched into the save when the plugin is loaded. See the section on [Clusterio Modules](developing-for-clusterio.md) in the Developing for Clusterio document. The only restriction imposed on modules embedded into plugins is that they must be named the same as the plugin. diff --git a/packages/lib/config/classes.js b/packages/lib/config/classes.js index 0394564a..dd85012f 100644 --- a/packages/lib/config/classes.js +++ b/packages/lib/config/classes.js @@ -813,8 +813,8 @@ class PluginConfigGroup extends ConfigGroup { if (!this._initialized) { super._initSubclass(); this.define({ - name: "enabled", - description: "Enable plugin", + name: "load_plugin", + title: "Load Plugin", type: "boolean", initial_value: true, }); diff --git a/packages/master/master.js b/packages/master/master.js index bb5a7da9..ffe9eb68 100755 --- a/packages/master/master.js +++ b/packages/master/master.js @@ -278,8 +278,8 @@ app.get("/api/plugins", (req, res) => { let plugins = []; for (let pluginInfo of pluginInfos) { let name = pluginInfo.name; - let enabled = masterPlugins.has(name) && masterConfig.group(name).get("enabled"); - plugins.push({ name, version: pluginInfo.version, enabled }); + let loaded = masterPlugins.has(name); + plugins.push({ name, version: pluginInfo.version, loaded }); } res.send(plugins); }); @@ -1699,7 +1699,7 @@ ${err.stack}` async function loadPlugins() { let plugins = new Map(); for (let pluginInfo of pluginInfos) { - if (!masterConfig.group(pluginInfo.name).get("enabled")) { + if (!masterConfig.group(pluginInfo.name).get("load_plugin")) { continue; } diff --git a/packages/slave/slave.js b/packages/slave/slave.js index 9366c5bc..a1217226 100755 --- a/packages/slave/slave.js +++ b/packages/slave/slave.js @@ -274,7 +274,7 @@ class Instance extends libLink.Link { if ( !pluginInfo.instanceEntrypoint || !this._slave.serverPlugins.has(pluginInfo.name) - || !this.config.group(pluginInfo.name).get("enabled") + || !this.config.group(pluginInfo.name).get("load_plugin") ) { continue; } diff --git a/packages/web_ui/src/components/PluginViewPage.jsx b/packages/web_ui/src/components/PluginViewPage.jsx index 98313720..ae847103 100644 --- a/packages/web_ui/src/components/PluginViewPage.jsx +++ b/packages/web_ui/src/components/PluginViewPage.jsx @@ -30,7 +30,7 @@ export default function PluginViewPage() { title={pluginTitle} > {plugin.meta.version} - {plugin.meta.enabled ? "Yes" : "No"} + {plugin.meta.loaded ? "Yes" : "No"} {plugin.meta.version} - {plugin.meta.enabled ? "Yes" : "No"} + {plugin.meta.loaded ? "Yes" : "No"} {plugin.info.description} {plugin.package.homepage ? {plugin.package.homepage} diff --git a/packages/web_ui/src/components/PluginsPage.jsx b/packages/web_ui/src/components/PluginsPage.jsx index 7b9b0065..2537019a 100644 --- a/packages/web_ui/src/components/PluginsPage.jsx +++ b/packages/web_ui/src/components/PluginsPage.jsx @@ -33,9 +33,9 @@ export default function PluginsPage() { }, }, { - title: "Enabled", - dataIndex: ["meta", "enabled"], - render: enabled => (enabled ? "Yes" : null), + title: "Loaded", + dataIndex: ["meta", "loaded"], + render: loaded => (loaded ? "Yes" : null), responsive: ["sm"], }, ]} From 415f574e2d61cdc4b5c6eb6f6ae582db76bbbe99 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 14:55:57 +0100 Subject: [PATCH 2/8] Remove obsolete "updater" code Remove commented out reference to an updater module which was never completed in master.js. --- packages/master/master.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/master/master.js b/packages/master/master.js index ffe9eb68..6db0952f 100755 --- a/packages/master/master.js +++ b/packages/master/master.js @@ -14,10 +14,6 @@ * npx clusteriomaster run */ -// Attempt updating -// const updater = require("./updater"); -// updater.update().then(console.log); - "use strict"; const path = require("path"); const fs = require("fs-extra"); From fe9cef5e1ed38e9364d9480e62fafb39eac7d962 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 14:56:48 +0100 Subject: [PATCH 3/8] Log stack trace on errors loading web plugins --- packages/web_ui/src/bootstrap.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/web_ui/src/bootstrap.jsx b/packages/web_ui/src/bootstrap.jsx index 627f446b..c84405b7 100644 --- a/packages/web_ui/src/bootstrap.jsx +++ b/packages/web_ui/src/bootstrap.jsx @@ -54,6 +54,9 @@ async function loadPlugins() { } catch (err) { logger.error(`Failed to load plugin info for ${meta.name}`); + if (err) { + logger.error(err.stack); + } plugins.push({ meta, }); From b814d8a4009731c786eb0cc2649f4a57df91ef3c Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 14:59:30 +0100 Subject: [PATCH 4/8] Share each individual lib import webpack config The module sharing in Webpack works on a per import basis and therefore doesn't trigger when the value in the config is @clusterio/lib while the module imported is @clusterio/lib/config. This in turn caused a copy of lib to be bundled with each plugin. Fix by making sure each lib import is shared and specified in the configs. --- packages/master/webpack.config.js | 9 ++++++++- plugins/global_chat/webpack.config.js | 3 ++- plugins/research_sync/webpack.config.js | 3 ++- plugins/statistics_exporter/webpack.config.js | 3 ++- plugins/subspace_storage/webpack.config.js | 3 ++- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/master/webpack.config.js b/packages/master/webpack.config.js index 8fca09c6..14350778 100644 --- a/packages/master/webpack.config.js +++ b/packages/master/webpack.config.js @@ -19,7 +19,14 @@ module.exports = (env = {}) => merge(common(env), { new webpack.container.ModuleFederationPlugin({ name: "master", shared: { - "@clusterio/lib": { singleton: true }, + "@clusterio/lib/config": { singleton: true }, + "@clusterio/lib/errors": { singleton: true }, + "@clusterio/lib/helpers": { singleton: true }, + "@clusterio/lib/link": { singleton: true }, + "@clusterio/lib/logging": { singleton: true }, + "@clusterio/lib/plugin": { singleton: true }, + "@clusterio/lib/schema": { singleton: true }, + "@clusterio/lib/users": { singleton: true }, "@clusterio/web_ui": { singleton: true }, "ajv": {}, "antd": { singleton: true }, diff --git a/plugins/global_chat/webpack.config.js b/plugins/global_chat/webpack.config.js index 6f19d7f7..6efae364 100644 --- a/plugins/global_chat/webpack.config.js +++ b/plugins/global_chat/webpack.config.js @@ -22,7 +22,8 @@ module.exports = (env = {}) => merge(common(env), { "./package.json": "./package.json", }, shared: { - "@clusterio/lib": { import: false }, + "@clusterio/lib/config": { import: false }, + "@clusterio/lib/link": { import: false }, "@clusterio/web_ui": { import: false }, "ajv": { import: false }, }, diff --git a/plugins/research_sync/webpack.config.js b/plugins/research_sync/webpack.config.js index 80a7863e..78645a96 100644 --- a/plugins/research_sync/webpack.config.js +++ b/plugins/research_sync/webpack.config.js @@ -22,7 +22,8 @@ module.exports = (env = {}) => merge(common(env), { "./package.json": "./package.json", }, shared: { - "@clusterio/lib": { import: false }, + "@clusterio/lib/config": { import: false }, + "@clusterio/lib/link": { import: false }, "@clusterio/web_ui": { import: false }, "ajv": { import: false }, }, diff --git a/plugins/statistics_exporter/webpack.config.js b/plugins/statistics_exporter/webpack.config.js index 9a8259e7..6ca9a1a4 100644 --- a/plugins/statistics_exporter/webpack.config.js +++ b/plugins/statistics_exporter/webpack.config.js @@ -22,7 +22,8 @@ module.exports = (env = {}) => merge(common(env), { "./package.json": "./package.json", }, shared: { - "@clusterio/lib": { import: false }, + "@clusterio/lib/config": { import: false }, + "@clusterio/lib/link": { import: false }, "@clusterio/web_ui": { import: false }, "ajv": { import: false }, }, diff --git a/plugins/subspace_storage/webpack.config.js b/plugins/subspace_storage/webpack.config.js index c53e2ca3..65853b7f 100644 --- a/plugins/subspace_storage/webpack.config.js +++ b/plugins/subspace_storage/webpack.config.js @@ -22,7 +22,8 @@ module.exports = (env = {}) => merge(common(env), { "./package.json": "./package.json", }, shared: { - "@clusterio/lib": { import: false }, + "@clusterio/lib/config": { import: false }, + "@clusterio/lib/link": { import: false }, "@clusterio/web_ui": { import: false }, "ajv": { import: false }, "antd": { import: false }, From a17e9295e721fb340377028e18abd989f3e38d16 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 15:14:38 +0100 Subject: [PATCH 5/8] Use relative imports in lib Use relative imports in lib to avoid an issue with webpack thinking absolute imports inside @clusterio/lib are for a separate module and giving out warnings for it being missing in package.json. --- packages/lib/command.js | 4 ++-- packages/lib/config/classes.js | 2 +- packages/lib/database.js | 2 +- packages/lib/factorio/export.js | 2 +- packages/lib/factorio/patch.js | 2 +- packages/lib/factorio/server.js | 6 +++--- packages/lib/link/connectors.js | 6 +++--- packages/lib/link/link.js | 6 +++--- packages/lib/link/messages.js | 6 +++--- packages/lib/logging_utils.js | 4 ++-- packages/lib/plugin_loader.js | 2 +- packages/lib/shared_commands.js | 6 +++--- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/lib/command.js b/packages/lib/command.js index cd4c1760..133a8805 100644 --- a/packages/lib/command.js +++ b/packages/lib/command.js @@ -7,8 +7,8 @@ * @module lib/command */ "use strict"; -const libLink = require("@clusterio/lib/link"); -const libErrors = require("@clusterio/lib/errors"); +const libLink = require("./link"); +const libErrors = require("./errors"); /** * Represents a command that can be runned by clusterioctl diff --git a/packages/lib/config/classes.js b/packages/lib/config/classes.js index dd85012f..0be19776 100644 --- a/packages/lib/config/classes.js +++ b/packages/lib/config/classes.js @@ -4,7 +4,7 @@ const events = require("events"); const isDeepStrictEqual = require("../is_deep_strict_equal"); -const { basicType } = require("@clusterio/lib/helpers"); +const { basicType } = require("../helpers"); /** diff --git a/packages/lib/database.js b/packages/lib/database.js index 7a727bd2..665cf58a 100644 --- a/packages/lib/database.js +++ b/packages/lib/database.js @@ -8,7 +8,7 @@ "use strict"; const fs = require("fs-extra"); -const { basicType } = require("@clusterio/lib/helpers"); +const { basicType } = require("./helpers"); /** diff --git a/packages/lib/factorio/export.js b/packages/lib/factorio/export.js index 165f011a..093e9be3 100644 --- a/packages/lib/factorio/export.js +++ b/packages/lib/factorio/export.js @@ -6,7 +6,7 @@ const ini = require("ini"); const Jimp = require("jimp"); const JSZip = require("jszip"); -const libBuildMod = require("@clusterio/lib/build_mod"); +const libBuildMod = require("../build_mod"); /** * Generate the export mod needed for exportData diff --git a/packages/lib/factorio/patch.js b/packages/lib/factorio/patch.js index e0322bfe..59df7b83 100644 --- a/packages/lib/factorio/patch.js +++ b/packages/lib/factorio/patch.js @@ -7,7 +7,7 @@ const JSZip = require("jszip"); const path = require("path"); const semver = require("semver"); -const libHash = require("@clusterio/lib/hash"); +const libHash = require("../hash"); const knownScenarios = { diff --git a/packages/lib/factorio/server.js b/packages/lib/factorio/server.js index 896860b1..a4b5079f 100644 --- a/packages/lib/factorio/server.js +++ b/packages/lib/factorio/server.js @@ -9,9 +9,9 @@ const crypto = require("crypto"); const ini = require("ini"); const rconClient = require("rcon-client"); -const libErrors = require("@clusterio/lib/errors"); -const { logger } = require("@clusterio/lib/logging"); -const { escapeRegExp } = require("@clusterio/lib/helpers"); +const libErrors = require("../errors"); +const { logger } = require("../logging"); +const { escapeRegExp } = require("../helpers"); /** diff --git a/packages/lib/link/connectors.js b/packages/lib/link/connectors.js index 0932070f..ef78fefd 100644 --- a/packages/lib/link/connectors.js +++ b/packages/lib/link/connectors.js @@ -3,9 +3,9 @@ const events = require("events"); const WebSocket = require("isomorphic-ws"); -const libSchema = require("@clusterio/lib/schema"); -const libErrors = require("@clusterio/lib/errors"); -const { logger } = require("@clusterio/lib/logging"); +const libSchema = require("../schema"); +const libErrors = require("../errors"); +const { logger } = require("../logging"); /** diff --git a/packages/lib/link/link.js b/packages/lib/link/link.js index a13f22c8..fa98e927 100644 --- a/packages/lib/link/link.js +++ b/packages/lib/link/link.js @@ -1,9 +1,9 @@ // Implementation of Link class "use strict"; -const libSchema = require("@clusterio/lib/schema"); -const libErrors = require("@clusterio/lib/errors"); -const { logger } = require("@clusterio/lib/logging"); +const libSchema = require("../schema"); +const libErrors = require("../errors"); +const { logger } = require("../logging"); const messages = require("./messages"); // Some definitions for the terminology used here: diff --git a/packages/lib/link/messages.js b/packages/lib/link/messages.js index 89a6cbdd..1bbf7bef 100644 --- a/packages/lib/link/messages.js +++ b/packages/lib/link/messages.js @@ -1,8 +1,8 @@ // Message definitions for links "use strict"; -const libSchema = require("@clusterio/lib/schema"); -const libErrors = require("@clusterio/lib/errors"); -const { logger } = require("@clusterio/lib/logging"); +const libSchema = require("../schema"); +const libErrors = require("../errors"); +const { logger } = require("../logging"); class MissingLinkHandlerError extends Error { constructor(type, source, target) { diff --git a/packages/lib/logging_utils.js b/packages/lib/logging_utils.js index 9c0284a3..c80b6997 100644 --- a/packages/lib/logging_utils.js +++ b/packages/lib/logging_utils.js @@ -4,8 +4,8 @@ const Transport = require("winston-transport"); const { LEVEL, MESSAGE } = require("triple-beam"); const chalk = require("chalk"); -const libLink = require("@clusterio/lib/link"); -const libErrors = require("@clusterio/lib/errors"); +const libLink = require("./link"); +const libErrors = require("./errors"); /** diff --git a/packages/lib/plugin_loader.js b/packages/lib/plugin_loader.js index 58cacda7..b784776b 100644 --- a/packages/lib/plugin_loader.js +++ b/packages/lib/plugin_loader.js @@ -5,7 +5,7 @@ */ "use strict"; -const libErrors = require("@clusterio/lib/errors"); +const libErrors = require("./errors"); const path = require("path"); diff --git a/packages/lib/shared_commands.js b/packages/lib/shared_commands.js index 5decd578..2cc378af 100644 --- a/packages/lib/shared_commands.js +++ b/packages/lib/shared_commands.js @@ -6,9 +6,9 @@ const fs = require("fs-extra"); const path = require("path"); -const libConfig = require("@clusterio/lib/config"); -const { logger } = require("@clusterio/lib/logging"); -const libHelpers = require("@clusterio/lib/helpers"); +const libConfig = require("./config"); +const { logger } = require("./logging"); +const libHelpers = require("./helpers"); function print(...content) { From e1c7d35ce4bf988999d0610a1574a0c2d53bbea0 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 13:39:17 +0100 Subject: [PATCH 6/8] Fix plugin shutdown not called on bad startup During startup the plugins are loaded one by one and init is called for each of them. But due to the already loaded plugins being discarded if one of the plugins throw an error an unclean shutdown that might hang on timers started by plugins occurs. This leads to the master server starting up, printing an error, displaying the shutdown sequence and then hang forever. Fix by storing the plugins loaded into masterPlugins as they are loaded instead only after all of them have been loaded. --- packages/master/master.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/master/master.js b/packages/master/master.js index 6db0952f..b7af2e5d 100755 --- a/packages/master/master.js +++ b/packages/master/master.js @@ -1693,7 +1693,6 @@ ${err.stack}` }); async function loadPlugins() { - let plugins = new Map(); for (let pluginInfo of pluginInfos) { if (!masterConfig.group(pluginInfo.name).get("load_plugin")) { continue; @@ -1712,7 +1711,7 @@ async function loadPlugins() { pluginInfo, { app, config: masterConfig, db, slaveConnections }, { endpointHitCounter }, logger ); await masterPlugin.init(); - plugins.set(pluginInfo.name, masterPlugin); + masterPlugins.set(pluginInfo.name, masterPlugin); } catch (err) { throw new libErrors.PluginError(pluginInfo.name, err); @@ -1720,13 +1719,12 @@ async function loadPlugins() { logger.info(`Loaded plugin ${pluginInfo.name} in ${Date.now() - pluginLoadStarted}ms`); } - return plugins; } // handle plugins on the master async function pluginManagement() { let startPluginLoad = Date.now(); - masterPlugins = await loadPlugins(); + await loadPlugins(); logger.info(`All plugins loaded in ${Date.now() - startPluginLoad}ms`); } From f007dd640dd62e54118f8d72a12b77e7d400476f Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 15:32:32 +0100 Subject: [PATCH 7/8] Fix statistics exporter name and description --- plugins/statistics_exporter/info.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/statistics_exporter/info.js b/plugins/statistics_exporter/info.js index 001f039e..b8fd3ea0 100644 --- a/plugins/statistics_exporter/info.js +++ b/plugins/statistics_exporter/info.js @@ -15,8 +15,10 @@ InstanceConfigGroup.finalize(); module.exports = { name: "statistics_exporter", - title: "Prometheus Statistics Export", - description: "Exports statistics to Prometheus", + title: "Statistics Exporter", + description: + "Provides in-game item/fluid production, builds, kills, and pollution "+ + "statistics to the cluster's Prometheus endpoint.", instanceEntrypoint: "instance", InstanceConfigGroup, }; From 6c4e094d44af2caa233c6a435d3d7e75f6bb3c9e Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 7 Mar 2021 15:56:27 +0100 Subject: [PATCH 8/8] Mention plugins by Hornwitser in README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ae113c07..20127ac7 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,14 @@ supported and maintained by the Clusterio developers: Provide shared storage that can transport items between servers via teleport chests. +There's also plugins developed and maintained by the community: + +- [Discord Bridge](https://github.com/Hornwitser/discord_bridge): + Bridges chat between instances and Discord. By Hornwitser. +- [Server Select](https://github.com/Hornwitser/server_select): + In-game GUI for connecting to other server in the cluster. Originally + by Godmave, ported to 2.0 by Hornwitser. + Want to make your own plugin? Check out the documentation on [Writing Plugins](/docs/writing-plugins.md) for where to start.