From 70ad295a89143e6368bf0001515a52744b682f18 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Wed, 22 Feb 2023 00:47:24 +0100 Subject: [PATCH] Rename Master to Controller The role of the master server as the party controlling every part of the cluster is not well reflected in its name and has caused confusion among users on several occasions. Rename master to controller to better reflects its role. --- .gitignore | 2 +- CHANGELOG.md | 23 +- Dockerfile | 2 +- README.md | 54 ++-- docker-compose.yml | 4 +- docs/communication.md | 2 +- docs/config-system.md | 14 +- docs/configuration.md | 88 +++---- docs/contributing.md | 10 +- docs/devs/protocol.md | 24 +- docs/how-it-works.md | 2 +- docs/jsdoc.json | 4 +- docs/managing-a-cluster.md | 6 +- docs/setting-up-tls.md | 18 +- docs/writing-plugins.md | 112 ++++---- package.json | 2 +- packages/{master => controller}/.npmignore | 0 packages/{master => controller}/README.md | 30 +-- .../master.js => controller/controller.js} | 138 +++++----- packages/{master => controller}/package.json | 8 +- .../src/BaseConnection.js | 34 +-- .../src/ControlConnection.js | 230 ++++++++-------- .../src/Controller.js} | 120 ++++----- .../{master => controller}/src/HttpCloser.js | 2 +- .../src/SlaveConnection.js | 78 +++--- .../{master => controller}/src/UserManager.js | 4 +- .../{master => controller}/src/WsServer.js | 56 ++-- .../src/WsServerConnector.js | 4 +- .../{master => controller}/src/metrics.js | 2 +- packages/{master => controller}/src/routes.js | 36 +-- .../{master => controller}/web/index.html | 0 packages/{master => controller}/web/index.jsx | 0 .../web/pictures/clusterio_icon.png | Bin .../{master => controller}/webpack.config.js | 2 +- packages/create/create.js | 82 +++--- packages/ctl/README.md | 6 +- packages/ctl/ctl.js | 22 +- packages/ctl/src/commands.js | 92 +++---- packages/lib/README.md | 2 +- packages/lib/command.js | 8 +- packages/lib/config/definitions.js | 114 ++++---- packages/lib/data/ModInfo.js | 2 +- packages/lib/database.js | 4 +- packages/lib/link/connectors.js | 12 +- packages/lib/link/link.js | 6 +- packages/lib/link/messages.js | 246 +++++++++--------- packages/lib/logging.js | 10 +- packages/lib/logging_utils.js | 20 +- packages/lib/plugin.js | 124 ++++----- packages/lib/plugin_loader.js | 8 +- packages/lib/shared_commands.js | 2 +- packages/lib/users.js | 32 +-- packages/slave/README.md | 6 +- packages/slave/slave.js | 20 +- packages/slave/src/Instance.js | 12 +- packages/slave/src/InstanceConnection.js | 10 +- packages/slave/src/Slave.js | 38 +-- packages/web_ui/src/components/App.jsx | 6 +- ...onfigTree.jsx => ControllerConfigTree.jsx} | 10 +- .../{MasterPage.jsx => ControllerPage.jsx} | 14 +- .../src/components/InstanceViewPage.jsx | 2 +- .../web_ui/src/components/InstancesPage.jsx | 2 +- packages/web_ui/src/components/LogConsole.jsx | 4 +- packages/web_ui/src/components/LoginForm.jsx | 2 +- packages/web_ui/src/components/ModDetails.jsx | 5 +- .../web_ui/src/components/ModPackViewPage.jsx | 2 +- .../web_ui/src/components/PluginViewPage.jsx | 6 +- .../web_ui/src/components/RoleViewPage.jsx | 2 +- .../web_ui/src/components/SlaveViewPage.jsx | 2 +- packages/web_ui/src/components/SlavesPage.jsx | 10 +- .../web_ui/src/components/UserViewPage.jsx | 2 +- packages/web_ui/src/index.jsx | 2 +- packages/web_ui/src/pages.jsx | 8 +- packages/web_ui/src/util/websocket.jsx | 12 +- plugins/global_chat/README.md | 4 +- plugins/global_chat/info.js | 4 +- plugins/global_chat/instance.js | 2 +- plugins/inventory_sync/README.md | 18 +- .../{master.js => controller.js} | 28 +- plugins/inventory_sync/info.js | 36 +-- plugins/inventory_sync/instance.js | 6 +- .../module/download_inventory.lua | 4 +- .../module/gui/dialog_failed_download.lua | 8 +- .../inventory_sync/module/inventory_sync.lua | 14 +- plugins/inventory_sync/web/index.jsx | 2 +- plugins/player_auth/README.md | 6 +- .../player_auth/{master.js => controller.js} | 26 +- plugins/player_auth/info.js | 26 +- plugins/player_auth/instance.js | 2 +- plugins/player_auth/test/plugin.js | 114 ++++---- plugins/research_sync/README.md | 4 +- .../{master.js => controller.js} | 16 +- plugins/research_sync/info.js | 18 +- plugins/research_sync/instance.js | 6 +- plugins/research_sync/module/sync.lua | 12 +- plugins/research_sync/test/missing.js | 2 +- plugins/statistics_exporter/README.md | 4 +- plugins/statistics_exporter/info.js | 2 +- plugins/statistics_exporter/instance.js | 2 +- plugins/subspace_storage/README.md | 4 +- .../{master.js => controller.js} | 40 +-- plugins/subspace_storage/dole_nn_base.js | 8 +- plugins/subspace_storage/info.js | 38 +-- plugins/subspace_storage/instance.js | 8 +- plugins/subspace_storage/routes.js | 8 +- plugins/subspace_storage/test/missing.js | 2 +- plugins/subspace_storage/test/routes.js | 2 +- plugins/subspace_storage/web/index.jsx | 2 +- test/{master => controller}/HttpCloser.js | 4 +- test/{master => controller}/routes.js | 28 +- test/file/log/test-2021-12-10.log | 2 +- test/file/log/test-2021-12-11.log | 2 +- test/integration/clusterio.js | 42 +-- test/integration/index.js | 44 ++-- test/lib/command.js | 4 +- test/lib/logging_utils.js | 4 +- test/lib/plugin.js | 26 +- test/lib/plugin_loader.js | 26 +- test/mock.js | 30 +-- 119 files changed, 1394 insertions(+), 1376 deletions(-) rename packages/{master => controller}/.npmignore (100%) rename packages/{master => controller}/README.md (69%) rename packages/{master/master.js => controller/controller.js} (71%) rename packages/{master => controller}/package.json (85%) rename packages/{master => controller}/src/BaseConnection.js (70%) rename packages/{master => controller}/src/ControlConnection.js (75%) rename packages/{master/src/Master.js => controller/src/Controller.js} (85%) rename packages/{master => controller}/src/HttpCloser.js (98%) rename packages/{master => controller}/src/SlaveConnection.js (68%) rename packages/{master => controller}/src/UserManager.js (94%) rename packages/{master => controller}/src/WsServer.js (81%) rename packages/{master => controller}/src/WsServerConnector.js (98%) rename packages/{master => controller}/src/metrics.js (89%) rename packages/{master => controller}/src/routes.js (92%) rename packages/{master => controller}/web/index.html (100%) rename packages/{master => controller}/web/index.jsx (100%) rename packages/{master => controller}/web/pictures/clusterio_icon.png (100%) rename packages/{master => controller}/webpack.config.js (97%) rename packages/web_ui/src/components/{MasterConfigTree.jsx => ControllerConfigTree.jsx} (69%) rename packages/web_ui/src/components/{MasterPage.jsx => ControllerPage.jsx} (55%) rename plugins/inventory_sync/{master.js => controller.js} (83%) rename plugins/player_auth/{master.js => controller.js} (80%) rename plugins/research_sync/{master.js => controller.js} (88%) rename plugins/subspace_storage/{master.js => controller.js} (80%) rename test/{master => controller}/HttpCloser.js (98%) rename test/{master => controller}/routes.js (93%) diff --git a/.gitignore b/.gitignore index 37bf1a49..97266127 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ Factorio* /mods /database /plugin-list.json -/config-master.json +/config-controller.json /config-control.json /config-slave.json pnpm-lock.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 424c643e..7c37c33b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,9 @@ Regular freeplay games can now be used with Clusterio and will be compatible without having to convert them to Hotpatch. - Daemonized slaves. Slaves now have the ability to run multiple Factorio instances, starting and stopping them individually. - To manage this the local command line interface has been replaced with a remote interface on the master server that can be accessed through the clusterioctl cli tool. -- Rewritten the communication between slaves and the master from scratch. - The new system is based on a WebSocket connection between the slaves and the master server and provides efficient validated bi-directonal communication. + To manage this the local command line interface has been replaced with a remote interface on the controller that can be accessed through the clusterioctl cli tool. +- Rewritten the communication between slaves and the controller from scratch. + The new system is based on a WebSocket connection between the slaves and the controller and provides efficient validated bi-directonal communication. - Rewritten the plugin system from scratch. Plugins now inherit from a base class and use the same WebSocket connection Clusterio uses to communicate. - New configuration system with support for initializing configs when needed, modifying config entries using built-in commands, and updating instance configuration remotely. @@ -24,9 +24,9 @@ ### Features - Added export of pollution statitics. -- Reconnection logic that esures no data is dropped talking to the master server provided the session can be resumed. +- Reconnection logic that esures no data is dropped talking to the controller provided the session can be resumed. - Added support for having multiple Factorio installs and selecting which version to use on a per instance basis. -- Added config to specify which path the master interface is accessed under, allowing it to be proxied behind web-server. +- Added config to specify which path the controller interface is accessed under, allowing it to be proxied behind web-server. - Added WebSocket usage statistics. - Added commands sent statistic. - Added Factorio server CPU and memory usage statistic. @@ -42,13 +42,13 @@ - Added option to configure timeout for exported Prometheus metrics. - Added option to set address to bind HTTP(S) port to. - Added an overview of the installed plugins to the web interface. -- Added clusterioctl command to list plugins on the master server. +- Added clusterioctl command to list plugins on the controller. - Added Player Auth plugin for logging in to the web interface by proving the ability to log in to a server as a given user. - Added Node.js based installer to simplify setting up a cluster. ### Changes -- Added error handling during master startup. +- Added error handling during controller startup. - Factorio game and rcon port now defaults to a random port above 49151. - Removed unimplemented mods update command. - Fixed rcon password being generated with Math.random(). @@ -76,7 +76,8 @@ - Removed info and shout command from globalChat plugin - Removed mirrorAllChat and enableCrossServerShout configuration options for globalChat plugin. - Removed UPSdisplay plugin. UPS statistics is exported by the statistics exporter plugin. -- Master server now defaults to hosting on https on port 8443. +- Controller now defaults to hosting on https on port 8443. +- Renamed master to controller. - Renamed client to slave. - Removed rotation of factorio-current.log files. @@ -134,13 +135,13 @@ - Removed msBetweenCommands config option. The RCON is instead limited to 5 concurrent commands. - Removed allowRemoteCommandExecution config option. - Remote commands are always allowed with the move to master managing slaves/instances. -- Removed `--databaseDirectory`, `--masterPort`, and `--sslPort` command line arguments from the master server. + Remote commands are always allowed with the move to controller managing slaves/instances. +- Removed `--databaseDirectory`, `--controllerPort`, and `--sslPort` command line arguments from the controller. - Implemented a new config system that replaces the old. Breaks all plugins. - Removed usage of socket.io entirely in favor of a plain WebSocket connection. - Renamed clusterioMod plugin to subspace_storage. -- Master no longer creates secret-api-token.txt. +- Controller no longer creates secret-api-token.txt. - Removed automatic creation of self-signed TLS certificate. - Node.js versions below 12 are no longer supported. diff --git a/Dockerfile b/Dockerfile index 3eb36c04..a6052df5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ RUN pnpm install # Install plugins. This is intended as a reasonable default, enabling plugins to make for fun gameplay. # If you want a different set of plugins, consider using this as the base image for your own. #RUN pnpm install @clusterio/plugin-subspace_storage -#RUN npx clusteriomaster plugin add @clusterio/plugin-subspace_storage +#RUN npx clusteriocontroller plugin add @clusterio/plugin-subspace_storage COPY --from=subspace_storage_builder /subspace_storage/dist/ /clusterio/mods/ diff --git a/README.md b/README.md index c209e732..9ef6594a 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ If you are starting a new cluster, it's highly recommended to use the 2.0 alpha. * [Windows setup](#windows-setup) * [MacOS setup](#macos-setup) * [Installing Plugins](#installing-plugins) -* [Configure Master Server](#configure-master-server) +* [Configure Controller](#configure-controller) * [Managing Factorio mods](#managing-factorio-mods) * [Setting up shared storage](#setting-up-shared-storage) * [Running Clusterio](#running-clusterio) @@ -71,7 +71,7 @@ These are the plugins supported and maintained by the Clusterio developers: - [Global Chat](/plugins/global_chat/README.md): share the in-game chat between servers. - [Research Sync](/plugins/research_sync/README.md): synchronize research progress and technologies unlocked between servers. -- [Statistics Exporter](/plugins/statistics_exporter/README.md): collect in-game statistics from all the servers and makes it available to the Prometheus endpoint on the master server. +- [Statistics Exporter](/plugins/statistics_exporter/README.md): collect in-game statistics from all the servers and makes it available to the Prometheus endpoint on the controller. - [Subspace Storage](https://github.com/clusterio/subspace_storage): Provide shared storage that can transport items between servers via teleport chests. - [Player Auth](/plugins/player_auth/README.md): Provides authentication to the cluster via logging into a Factorio server. - [Inventory Sync](/plugins/inventory_sync/README.md): Synchronizes your inventory between servers. @@ -126,7 +126,7 @@ Clusterio has *very* limited support for using docker. sudo docker build -t clusterio --no-cache --force-rm clusterio - sudo docker run --name master -e MODE=master -p 1234:8080 -d -it --restart=unless-stopped danielvestol/clusterio + sudo docker run --name controller -e MODE=controller -p 1234:8080 -d -it --restart=unless-stopped danielvestol/clusterio sudo docker run --name slave -e MODE=slave -e INSTANCE=world1 -v /srv/clusterio/instances:/clusterio/instances -p 1235:34167 -it --restart=unless-stopped danielvestol/clusterio @@ -173,37 +173,37 @@ First install the package the plugin is provided by via npm, for example Then tell clusterio that this plugin exists by adding it as a plugin. - npx clusteriomaster plugin add @clusterio/plugin-subspace_storage + npx clusteriocontroller plugin add @clusterio/plugin-subspace_storage -This adds it to the default `plugin-list.json` file which in the shared folder setup is loaded by master, slave and ctl. +This adds it to the default `plugin-list.json` file which in the shared folder setup is loaded by controller, slave and ctl. If you have slaves or ctl installed on separate computers (or directories) then you need to repeat the plugin install process for all of them. -The clusteriomaster, clusterioslave and clusterioctl commands has the plugin sub-command so you do not need to install clusteriomaster to add plugins, instead use the clusterio command you have available. +The clusteriocontroller, clusterioslave and clusterioctl commands has the plugin sub-command so you do not need to install clusteriocontroller to add plugins, instead use the clusterio command you have available. For development purposes the `plugin add` command supports adding plugins by the absolute path to them, or a relative path that must start with either . or .. (which will then be resolved to an absolute path). -## Configure Master Server +## Configure Controller -By default the master server will listen for HTTP on port 8080. +By default the controller will listen for HTTP on port 8080. You can change the port used with the command - npx clusteriomaster config set master.http_port 1234 + npx clusteriocontroller config set controller.http_port 1234 When changing the port you will also need to change the address slaves connect with. For the standalone installation mode you can use - npx clusterioslave config set slave.master_url http://localhost:1234/ + npx clusterioslave config set slave.controller_url http://localhost:1234/ If you plan to make your cluster available externally set the address that it will be accessible under with, for example - npx clusteriomaster config set master.external_address http://203.0.113.4:1234/ + npx clusteriocontroller config set controller.external_address http://203.0.113.4:1234/ -Change the url to reflect the IP, protocol, and port the master server is accessible under, dns names are also supported. -If you're planning on making the master server accessible on the internet it's recommended to set up TLS, see the [Setting Up TLS](/docs/setting-up-tls.md) document for more details. +Change the url to reflect the IP, protocol, and port the controller is accessible under, dns names are also supported. +If you're planning on making the controller accessible on the internet it's recommended to set up TLS, see the [Setting Up TLS](/docs/setting-up-tls.md) document for more details. -You can list the config of the master server with the `npx clusteriomaster config list` command. -See the [readme for @clusterio/master](/packages/master/README.md) for more information. +You can list the config of the controller with the `npx clusteriocontroller config list` command. +See the [readme for @clusterio/controller](/packages/controller/README.md) for more information. ## Managing Factorio mods @@ -218,7 +218,7 @@ Better remote management of mods is a planned feature. ## Setting up shared storage -The chests teleporting items to and from the shared storage on the master server has been moved into the Subspace Storage mod and plugin. +The chests teleporting items to and from the shared storage on the controller has been moved into the Subspace Storage mod and plugin. To get this to work you will need to install the Subspace Storage plugin and copy the [Subspace Storage mod](https://mods.factorio.com/mod/subspace_storage) and the [Clusterio Lib mod](https://mods.factorio.com/mod/clusterio_lib) into the `sharedMods` folder on each slave installation. Do not install the [Clusterio mod](https://mods.factorio.com/mod/clusterio), this was for the old 1.2.x version of Clusterio and is not compatible with Clusterio 2.0. @@ -226,43 +226,43 @@ Do not install the [Clusterio mod](https://mods.factorio.com/mod/clusterio), thi ## Running Clusterio -After completing the installation start up the master server and at least one slave separately. -The installer provides the `run-master` and `run-slave` scripts to make this simple. -Once the master process is running you can log into the web interface which is hosted by default on http://localhost:8080/ (adjust the port number if you changed it), use the admin authentication token provided from the installation to log in. +After completing the installation start up the controller and at least one slave separately. +The installer provides the `run-controller` and `run-slave` scripts to make this simple. +Once the controller process is running you can log into the web interface which is hosted by default on http://localhost:8080/ (adjust the port number if you changed it), use the admin authentication token provided from the installation to log in. The basics of setting up a Factorio server from the web interface is to create an instance, assign it to a slave and then click start. ### Running via Systemd -The install script creates systemd service scripts for clusteriomaster and clusterioslave (if applicable) to start up as the user than ran the installer. +The install script creates systemd service scripts for clusteriocontroller and clusterioslave (if applicable) to start up as the user than ran the installer. If you have copied these files over to `/etc/systemd/system/` then you can startup Clusterio as a background service using: #### To start as a service run: - sudo systemctl start clusteriomaster # for the master server + sudo systemctl start clusteriocontroller # for the controller sudo systemctl start clusterioslave # for each server hosting a slave #### To automatically get it to start on boot: - sudo systemctl enable clusteriomaster # for the master server + sudo systemctl enable clusteriocontroller # for the controller sudo systemctl enable clusterioslave # for each server hosting a slave ## Setting up remote slaves -Run the installer as described in the installation section and choose "Slave only" as the operating mode to install, it'll ask for a master URL and an authentication token. +Run the installer as described in the installation section and choose "Slave only" as the operating mode to install, it'll ask for a controller URL and an authentication token. The URL is the same as what is needed to connect to the web interface, and the authentication token can be generated on the Slaves page in the web interface. Once you start up the slave it should show up in the Slaves list and be available for assigning and running instances on. ## Setting up clusterioctl -There's a command line interface available for Clusterio which is installed separately with the same installer as for the master and slave. +There's a command line interface available for Clusterio which is installed separately with the same installer as for the controller and slave. Run the installer as described in the installation section and choose "Ctl only" as the operating mode to install, you can do this in the same directory as you have installed other Clusterio component(s) to. -The installer will ask for a master URL and an authentication token, these are the same as you would use to connect to the web interface. +The installer will ask for a controller URL and an authentication token, these are the same as you would use to connect to the web interface. If you want to use a different user for the command line interface, you can generate an authentication token for an existing user with - npx clusteriomaster bootstrap generate-user-token + npx clusteriocontroller bootstrap generate-user-token ## Common problems @@ -276,7 +276,7 @@ According to [this link](https://askubuntu.com/questions/839520/open-port-443-fo sudo setcap 'cap_net_bind_service=+ep' $(readlink -f $(which node)) -### Port forwarding doesn't work on the master server when running under WSL +### Port forwarding doesn't work on the controller when running under WSL If you follow the ubuntu guide on WSL (Windows Subsystem for Linux, Bash on Ubuntu on Windows specifically), you will find that the website works on localhost and on your local ip, but not on the global ip. This is also true when you correctly port-forwarded the correct ports. diff --git a/docker-compose.yml b/docker-compose.yml index d173c612..cf6123f4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,9 @@ version: '3' services: - master: + controller: build: . - command: npx clusteriomaster run + command: npx clusteriocontroller run slave: build: . command: npx clusterioslave run diff --git a/docs/communication.md b/docs/communication.md index e421b016..63805da9 100644 --- a/docs/communication.md +++ b/docs/communication.md @@ -11,7 +11,7 @@ Links represents one side of a two way communication pipe, connectors deal with The Link class represents one side of a two way communication channel where the actual communication is done by a connector associated with the link. The link also knows what the endpoint types it's connected to are via the source and target attributes. -The endpoint types currently implemented are master, slave, instance, and control. +The endpoint types currently implemented are controller, slave, instance, and control. Although slave and instances run in the same Node.js program they use virtual links to communicate between them in order to simplify the communication architecture. Upon creation the link will register with the connector in order to receive and process messages from it. diff --git a/docs/config-system.md b/docs/config-system.md index 3bf01e17..c1bc4a3f 100644 --- a/docs/config-system.md +++ b/docs/config-system.md @@ -2,11 +2,11 @@ This document describes the implementation and inner working of the configuration system in Clusterio, and unless you're developing Clusterio it's probably not going to be very useful for you. -Clusterio uses a group based configuration system to manage settings for the master server, instances, slaves, and the clusterioctl utility. -Plugins get their own config group for the master server and instances which they can add their own fields to. +Clusterio uses a group based configuration system to manage settings for the controller, instances, slaves, and the clusterioctl utility. +Plugins get their own config group for the controller and instances which they can add their own fields to. The fields are defined early in the startup, and the groups and their fields for disabled plugins will still be created. -The built-in config groups and their fields are defined in [packages/lib/config/definitions.js](/packages/lib/config/definitions.js) while plugins can add their own config groups to the `MasterConfigGroup` and `InstanceConfigGroup` properties of the `info.js` export using subclasses of `PluginConfigGroup`. +The built-in config groups and their fields are defined in [packages/lib/config/definitions.js](/packages/lib/config/definitions.js) while plugins can add their own config groups to the `ControllerConfigGroup` and `InstanceConfigGroup` properties of the `info.js` export using subclasses of `PluginConfigGroup`. The plugin group has the enabled field pre-defined on it, and it's used to enable/disable plugins. @@ -17,10 +17,10 @@ The `define` method takes an object as argument with the following properties: **access**: The locations this config field can be read and modified from. - This is an array of strings which can contain the values `"master"`, `"slave"` and `"control"`. + This is an array of strings which can contain the values `"controller"`, `"slave"` and `"control"`. If a party is missing in this array then that party will not receive the value of this field when the config is shared, and will be unable to modify the field. Takes the value of `defaultAccess` set on the config group class if not passed. - Note that instance config groups should have both `"master"` and `"slave"` for all of its fields or unexpected behaviour may occur. + Note that instance config groups should have both `"controller"` and `"slave"` for all of its fields or unexpected behaviour may occur. **type**: The type of config value this field will support. @@ -73,6 +73,6 @@ Values for all config fields are created when the config is initialized, as well Once a field has a value it is never automatically removed, even if the field or group it was part of no longer exists. This ensures that plugin configuration is not lost should the server be started up without the plugins that defined the configuration installed. -For instance configs, they are kept on the master server and serialized and sent over to the relevant slaves on startup. +For instance configs, they are kept on the controller and serialized and sent over to the relevant slaves on startup. This makes it possible to edit instance configs when the slave the instance is on is offline. -A copy is also stored in the instance directory on the slave, and this config will be deliverd to the master server on slave startup, which enables instances to be copied between clusters as long as their IDs are unique. +A copy is also stored in the instance directory on the slave, and this config will be deliverd to the controller on slave startup, which enables instances to be copied between clusters as long as their IDs are unique. diff --git a/docs/configuration.md b/docs/configuration.md index a99c37fb..b819d720 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,9 +1,9 @@ # Configuration -## Master Configuration +## Controller Configuration -### master.name +### controller.name Name of the cluster. Used to distinguish it from other clusters and is prepended to the name of servers in the server list. @@ -11,37 +11,37 @@ Used to distinguish it from other clusters and is prepended to the name of serve Defaluts to "Your Cluster". -### master.database_directory +### controller.database_directory Directory used to store cluster data to. -Needs to be writeable by the master server. +Needs to be writeable by the controller. This is also used by plugins to store its data. Defaults to "database". -### master.http_port +### controller.http_port Port to host HTTP server on. If set to null no HTTP server will be exposed. -At least one of this and master.https_port needs to be set to a port. +At least one of this and controller.https_port needs to be set to a port. Defaults to 8080. -### master.https_port +### controller.https_port Port to host HTTPS server on. -Uses master.tls_certificate and master.tls_private_key as the certificate and private key for the HTTPS server. +Uses controller.tls_certificate and controller.tls_private_key as the certificate and private key for the HTTPS server. If set to null no HTTPS server will be exposed. -At least one of this and master.http_port needs to be set to a port. +At least one of this and controller.http_port needs to be set to a port. See the [Setting up TLS](/docs/setting-up-tls.md) document for a guide to setting up HTTPS with Clusterio. Defaults to null. -### master.bind_address +### controller.bind_address IP address to bind the HTTP and HTTPS ports on. Useful to limit which interface to accept connections from. @@ -51,30 +51,30 @@ interfaces. Defaults to null. -### master.external_address +### controller.external_address -External address the master server is accessible on. -Currently only used for `clusteriomaster bootstrap create-ctl-config` in order to give the right url to connect to. +External address the controller is accessible on. +Currently only used for `clusteriocontroller bootstrap create-ctl-config` in order to give the right url to connect to. This should be a full URL ending with a /. Defaults to null meaning assume localhost. -### master.tls_certificate +### controller.tls_certificate -Path to TLS certificate to use for the HTTPS server when master.https_port is configured. +Path to TLS certificate to use for the HTTPS server when controller.https_port is configured. Defaults to "database/certificates/cert.crt". -### master.tls_private_key +### controller.tls_private_key -Path to TLS private key to use for the HTTPS server when master.https_port is configured. +Path to TLS private key to use for the HTTPS server when controller.https_port is configured. Defaults to "database/certificates/cert.key". -### master.auth_secret +### controller.auth_secret Base64 encoded authentication secret used to verify tokens issued to slaves, users, and sessions. This should contain 256 bytes of random data, and if changed will cause all tokens become invalid. @@ -83,7 +83,7 @@ Keep this secret if leaked an attacker could easily compromise the cluster. Defaults to null which means generate a secure secret on startup. -### master.heartbeat_interval +### controller.heartbeat_interval Interval in seconds heartbeats are sent out at for WebSocket connections. If a WebSocket connection hasn't received a heartbeat in 2 times the heartbeat interval it will be considered stale and closed. @@ -92,17 +92,17 @@ A lower value means less time between connections going stale and them being clo Defaults to 15. -### master.session_timeout +### controller.session_timeout Time in seconds from the connection is closed following a heartbeat timeout until the session is invalidated and data loss occurs. A higher timeout gives more time for a client to recconect and resume an active session over a connection that was dropped, but also leads to stale connections taking longer to clear out. -In the case of the master or client crashing the data loss is unavoidable. +In the case of the controller or client crashing the data loss is unavoidable. -Value should not be less than the configured `max_reconnect_delay` of the clients and it should be greater than 2 times `master.heartbeat_interval`. +Value should not be less than the configured `max_reconnect_delay` of the clients and it should be greater than 2 times `controller.heartbeat_interval`. Defaults to 60. -### master.metrics_timeout +### controller.metrics_timeout Timeout in seconds before a call to gather metrics from a slave times out. This should be less than both the timeout and collection interval configured for the collection job in Prometheus. @@ -110,15 +110,15 @@ This should be less than both the timeout and collection interval configured for Defaults to 8. -### master.stream_timeout +### controller.stream_timeout -Timeout in seconds for proxy streams through the master that has been created but is not yet sending data to be automatically closed. +Timeout in seconds for proxy streams through the controller that has been created but is not yet sending data to be automatically closed. Streams that have started sending data before this timeout is not affected. Defaults to 15. -### master.default_role_id +### controller.default_role_id Role to automatically grant to new users. If null no role is granted. @@ -128,8 +128,8 @@ Defaults to 1 which correspond to the default Player role. ### .load_plugin -Whether to load the plugin on the master server. -Plugins not loaded on the master server will not be loaded on instances. +Whether to load the plugin on the controller. +Plugins not loaded on the controller will not be loaded on instances. Defaults to true. @@ -167,16 +167,16 @@ One sub-directory will be created in it for each instance assigned to this slave Defaults to "instances". -### slave.master_url +### slave.controller_url -URL to connect to the master server to. +URL to connect to the controller to. Defaults to "http://localhost:8080/". -### slave.master_token +### slave.controller_token -Access token used for authenticating with the master server. +Access token used for authenticating with the controller. You can generate an access token with `clusterioctl slave generate-token --id `, or use the `clusterioctl slave create-config` to create a new slave config with the correct url and token in it. Defaults to "enter token here". @@ -184,8 +184,8 @@ Defaults to "enter token here". ### slave.tls_ca -Path to certificate in PEM format to use for validating a TLS connection to the master server. -If you have a self signed certificate on the master server you will need to copy the certificate to your slaves and set it as the certificate authority with this option. +Path to certificate in PEM format to use for validating a TLS connection to the controller. +If you have a self signed certificate on the controller you will need to copy the certificate to your slaves and set it as the certificate authority with this option. Defaults to null meaning use Node.js's default set of trusted certificate authorities. @@ -200,7 +200,7 @@ Defaults to "localhost". ### slave.max_reconnect_delay -Maximum delay in seconds to wait after connection to the master server is dropped before attempting to reconnect to it. +Maximum delay in seconds to wait after connection to the controller is dropped before attempting to reconnect to it. The actual delay on each reconnect will be a random number between 0 and this configured value to avoid all clients trying to reconnect at the same time. Defaults to 60. @@ -383,39 +383,39 @@ Defaults to 5. ### .load_plugin 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. +Note that plugins need to be loaded on the controller in order for them to be loaded on instances. Defaults to true. ## Control Configuration -### control.master_url +### control.controller_url -URL to connect to the master server to. +URL to connect to the controller to. Defaults to null meaning complain about it not being set and exit. -### control.master_token +### control.controller_token -Access token used for authenticating with the master server. -You can generate an access token with `clusteriomaster bootstrap generate-user-token `, or use the `clusteriomaster bootstrap create-ctl-config ` to create a new ctl config with the correct url and token in it. +Access token used for authenticating with the controller. +You can generate an access token with `clusteriocontroller bootstrap generate-user-token `, or use the `clusteriocontroller bootstrap create-ctl-config ` to create a new ctl config with the correct url and token in it. Defaults to null meaning complain about it not being set and exit. ### control.tls_ca -Path to certificate in PEM format to use for validating a TLS connection to the master server. -If you have a self signed certificate on the master server you will need to copy the certificate to the computer you run clusterctl from and set it as the certificate authority with this option. +Path to certificate in PEM format to use for validating a TLS connection to the controller. +If you have a self signed certificate on the controller you will need to copy the certificate to the computer you run clusterctl from and set it as the certificate authority with this option. Defaults to null meaning use Node.js's default set of trusted certificate authorities. ### control.max_reconnect_delay -Max duration in seconds to wait before attempting to reconnect with the master server after the connection is dropped. +Max duration in seconds to wait before attempting to reconnect with the controller after the connection is dropped. The actual delay on each reconnect will be a random number between 0 and this configured value to avoid all clients trying to reconnect at the same time. Defaults to 60. diff --git a/docs/contributing.md b/docs/contributing.md index b84c0f9e..e140ee90 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -68,17 +68,17 @@ The `plugins/` directory contains the core plugins for the project and can be ad The documentation uses the binaries provided by the packages, but for the development environment you will need to call the packages directly: - npx clusteriomaster -> node packages/master + npx clusteriocontroller -> node packages/controller npx clusterioslave -> node packages/slave npx clusterioctl -> node packages/ctl Note that to use `clusterioctl` you will have to create a control config first: - node packages/master bootstrap create-ctl-config [admin-user] + node packages/controller bootstrap create-ctl-config [admin-user] -Once you've set up the cluster you can use `node packages/master run` to run the master server and `node packages/slave run` to run the slave which connects to the master server. +Once you've set up the cluster you can use `node packages/controller run` to run the controller and `node packages/slave run` to run the slave which connects to the controller. -For web development on the master there are also the following flags: +For web development on the controller there are also the following flags: `--dev` - Recompile the `web_ui` package on the fly providing live reloading of it. @@ -86,7 +86,7 @@ For web development on the master there are also the following flags: These options can be combined and multiple plugins can be actived for dev mode. Keep in mind if you're working on external plugins the `--dev-plugin` option is likely to only work if the plugin is placed inside the `external_plugins` directory and its dependencies are installed with pnpm as part of the clusterio repository workspace. -Note that webpack is configured to delete the web interface build when using these options, so you will have to run `pnpm run -r --if-present prepare` before you start the master without these flags again. +Note that webpack is configured to delete the web interface build when using these options, so you will have to run `pnpm run -r --if-present prepare` before you start the controller without these flags again. ### Starting a Feature Branch diff --git a/docs/devs/protocol.md b/docs/devs/protocol.md index d45957fe..9fa61fbd 100644 --- a/docs/devs/protocol.md +++ b/docs/devs/protocol.md @@ -12,9 +12,9 @@ Events and requests are defined as instances of the `Request` and `Event` classe All messages sent and received are validated with JSON schemas to catch potential errors in sending messages and avoid having to write lots of validation code in message handlers. Messages are sent by calling the `.send()` method of the message instance and passing a `Link` instance to send it over and the data to send. -For the master server there's a `Link` instance for each slave and control connection stored in the `WsServer` class. -For slaves the `Slave` instance is a link to the master server, and each `Instance` instance is an in-memory link to the `Slave` instance and has a corresponding `InstanceConnection` link stored on the `Slave` instance. -For ctl and web_ui there's a `Control` instance that acts as the link to the master server. +For the controller there's a `Link` instance for each slave and control connection stored in the `WsServer` class. +For slaves the `Slave` instance is a link to the controller, and each `Instance` instance is an in-memory link to the `Slave` instance and has a corresponding `InstanceConnection` link stored on the `Slave` instance. +For ctl and web_ui there's a `Control` instance that acts as the link to the controller. Messages received invokes message handlers that were registered when the link was brought up. These handlers are named after the name of the property the message is stored under with `EventHandler` appended for events and `RequestHandler` appended for requests. @@ -96,11 +96,11 @@ The following messages are the only valid messages that can be sent during the h #### `hello` -Sent by the master server when the WebSocket connection has been opened. +Sent by the controller when the WebSocket connection has been opened. -- `version: string` - The version of the master, e.g. "2.0.0". +- `version: string` - The version of the controller, e.g. "2.0.0". - `plugins: Object` - - Object mapping plugin names to plugin version for plugins that are loaded on the master server. + Object mapping plugin names to plugin version for plugins that are loaded on the controller. #### `register_slave` @@ -131,12 +131,12 @@ Handshake for resuming an existing connection session where the connection had d #### `invalidate` -Sent by the master server in reply to a resume for a session that cannot be resumed. +Sent by the controller in reply to a resume for a session that cannot be resumed. The client should start a new session with a register\_\* message in response. #### `continue` -Sent by the master server to signal resuming the session was successful. +Sent by the controller to signal resuming the session was successful. - `last_seq: integer | null` - Last message seq received by the server. - `session_timeout: integer` - Session timeout in seconds. @@ -144,7 +144,7 @@ Sent by the master server to signal resuming the session was successful. #### `ready` -Sent by the master server to signal the connection has been established with a new session. +Sent by the controller to signal the connection has been established with a new session. - `session_token: string` - Token to resume the session with. - `session_timeout: integer` - Session timeout in seconds. @@ -159,7 +159,7 @@ The heartbeat should contain the `seq` of the last received message, and receivi #### `heartbeat` -Sent by both the master server and clients at the interval given in the continue/ready messages. +Sent by both the controller and clients at the interval given in the continue/ready messages. - `last_seq: integer` - Last message seq received over the link. @@ -251,7 +251,7 @@ Slave registering a new connection session. } ``` -Master server reply signaling the session is established and ready. +Controller reply signaling the session is established and ready. ```json { @@ -265,4 +265,4 @@ Master server reply signaling the session is established and ready. } ``` -Slave and master can now send events and requests over the connection. +Slave and controller can now send events and requests over the connection. diff --git a/docs/how-it-works.md b/docs/how-it-works.md index 4e61a9bb..6a943554 100644 --- a/docs/how-it-works.md +++ b/docs/how-it-works.md @@ -11,6 +11,6 @@ This can be disabled with the `factorio.enable_save_patching` config on a per in ## User Accounts -The master server creates and stores accounts for all Factorio users that log into instances under its control. +The controller creates and stores accounts for all Factorio users that log into instances under its control. These accounts are used to store per player data and authorize management of the cluster. By default users accounts are assigned a Player role that gives a limited read access to the cluster resources, and admins of the cluster can be assigned a Cluster Admin role to get access to manage it. diff --git a/docs/jsdoc.json b/docs/jsdoc.json index d2b4df6a..96368a55 100644 --- a/docs/jsdoc.json +++ b/docs/jsdoc.json @@ -11,8 +11,8 @@ }, "source": { "include": [ - "packages/master/src/", - "packages/master/master.js", + "packages/controller/src/", + "packages/controller/controller.js", "packages/slave/src/", "packages/slave/slave.js", "packages/ctl/src/", diff --git a/docs/managing-a-cluster.md b/docs/managing-a-cluster.md index ebf48211..7c4fe792 100644 --- a/docs/managing-a-cluster.md +++ b/docs/managing-a-cluster.md @@ -1,11 +1,11 @@ # Managing a Cluster -Clusterio clusters are managed through the master server by using the `clusterioctl` command line interface which is invoked by running `npx clusterioctl ` in the clusterio directory. +Clusterio clusters are managed through the controller by using the `clusterioctl` command line interface which is invoked by running `npx clusterioctl ` in the clusterio directory. This document uses the shorthand `ctl> foo` to indicate `npx clusterioctl foo` should be executed. Mandatory parameters are shown in `` and optional pameters are in `[square brackets]`. Before `clusterioctl` can be used it needs to be configured for the cluster it will connect to. -The easiest way to do this is to run `npx clusteriomaster bootstrap create-ctl-config ` on the master server, which creates the necessary `config-control.json` for managing the cluster as the given user. +The easiest way to do this is to run `npx clusteriocontroller bootstrap create-ctl-config ` on the controller, which creates the necessary `config-control.json` for managing the cluster as the given user. ## Slaves @@ -189,7 +189,7 @@ By default there's a roled named Cluster Admin which grants access to everything ctl> user delete -Deletes everything stored on the master server for this user. +Deletes everything stored on the controller for this user. Note: If the player is banned from the cluster this will effectively unban them, as the ban status is stored with the user account. diff --git a/docs/setting-up-tls.md b/docs/setting-up-tls.md index 416416c0..c8d90c06 100644 --- a/docs/setting-up-tls.md +++ b/docs/setting-up-tls.md @@ -1,7 +1,7 @@ # Setting up TLS By default Clusterio will listen for connections over HTTP which is fine for local networks but over the Internet it should idealy be over HTTPS as there are some credentials that could be exposed to eavesdroppers. -The recommended setup is to have an ordinary HTTPS server software like Apache or Nginx to act as a reverse proxy in front of the Clusterio master server. +The recommended setup is to have an ordinary HTTPS server software like Apache or Nginx to act as a reverse proxy in front of the Clusterio controller. The reverse proxy would then be set up with a TLS certificate from a Certificate Authoritiy like [Let's Encrypt](https://letsencrypt.org). Alternatively you can have Clusterio listen for connections over HTTPS directly by providing it with a TLS certificate and private key. @@ -11,17 +11,17 @@ See the last section for how to create and use a self-signed certificate for an ## Using a reverse proxy -Configure the proxy to forward requests over HTTP to the port the master server is listening to so that for example a request to `https://example.com/instances/` is forwarded to `http://localhost:8080/instances/`. -It is possible to host the interface under a sub-path, in that case a request under the sub-path should be mapped to the master server with the sub-path stripped out. +Configure the proxy to forward requests over HTTP to the port the controller is listening to so that for example a request to `https://example.com/instances/` is forwarded to `http://localhost:8080/instances/`. +It is possible to host the interface under a sub-path, in that case a request under the sub-path should be mapped to the controller with the sub-path stripped out. For example `https://example.com/sub/path/instances/` would be mapped to `http://localhost:8080/instances`. Additianlly WebSocket connections to `/api/socket` also needs to be forwarded. Typically this requires explicit configuration and support for forwarding WebSocket connections. If the interface hosted under a sub-path the `/api/socket` address is relative to the sub-path and the sub-path also needs to be stripped out when forwarded. -You can also optionally set the master server to listen only on the loopback interface to prevent it being directly connected to from the outside. +You can also optionally set the controller to listen only on the loopback interface to prevent it being directly connected to from the outside. - npx clusteriomaster config set master.bind_address 127.0.0.1 + npx clusteriocontroller config set controller.bind_address 127.0.0.1 ### Apache Config @@ -44,7 +44,7 @@ Pay attention to the use of trailing slashes, as they are important. ## Hosting HTTPS directly from Node.js -Listening on HTTPS is supported by the Clusterio master server via the `master.https_port` option provided paths to a certificate file and a private key file is configured for the `master.tls_certificate` and `master.tls_private_key` options. +Listening on HTTPS is supported by the Clusterio controller via the `controller.https_port` option provided paths to a certificate file and a private key file is configured for the `controller.tls_certificate` and `controller.tls_private_key` options. Both of these are expected to be unencrypted PEM files. @@ -58,10 +58,10 @@ substituting `` with the IP address the server will be accessed under, for e Multiple addresses can be given by supplying a comma sepparated list of `IP:address` pairs and DNS names can also be specified using the `DNS:example.com` format. You need to supply every name you want to connect to the server under the subjectAltName field, for example to connect to the HTTPS port locally via an address like `https://localhost:4443/` you need to add `DNS:localhost`. -This creates a private key file named `key.pem` and a public certificate file named `cert.pem` and these are used for the `master.tls_certificate` and `master.tls_private_key` config options respectively on the master server: +This creates a private key file named `key.pem` and a public certificate file named `cert.pem` and these are used for the `controller.tls_certificate` and `controller.tls_private_key` config options respectively on the controller: - npx clusteriomaster config set master.tls_certificate cert.pem - npx clusteriomaster config set master.tls_private_key key.pem + npx clusteriocontroller config set controller.tls_certificate cert.pem + npx clusteriocontroller config set controller.tls_private_key key.pem Additionally you will need copy the `cert.pem` file to all of the computers you want to set up as slaves and configure it as the `slave.tls_ca` option: diff --git a/docs/writing-plugins.md b/docs/writing-plugins.md index b1871b63..bb86c67e 100644 --- a/docs/writing-plugins.md +++ b/docs/writing-plugins.md @@ -27,7 +27,7 @@ The basic file structure of a plugin is the following. plugin_name/ +- info.js +- package.json - +- master.js + +- controller.js +- instance.js +- control.js +- test/ @@ -41,7 +41,7 @@ The usual guides for creating such packages apply. At minimum the `package.json` file must contain a version entry. A possible workflow for developing plugins is to place the plugin in a sub-directory of where clusterio has been installed, and rely on Node.js searching up the folder heirarchy for it to find `@clusterio/lib`. -To add it to `plugin-list.json` so that it gets loaded use the `plugin add ` sub-command to either clusteriomaster, clusterioslave or clusterioctl. +To add it to `plugin-list.json` so that it gets loaded use the `plugin add ` sub-command to either clusteriocontroller, clusterioslave or clusterioctl. Note that it's important that the path starts with ./ or ../ (use .\ or ..\ on Windows). For a plugin the most important file is the `info.js` file. @@ -56,7 +56,7 @@ module.exports = { title: "Foo Frobber", description: "Does advanced frobnication", instanceEntrypoint: "instance", - masterEntrypoint: "master", + controllerEntrypoint: "controller", messages: { /* See below */ }, @@ -80,19 +80,19 @@ The following properties are recognized: **instanceEntrypoint**: Path to a Node.js module relative to the plugin directory which contains the InstancePlugin class definition for this plugin. This is an optional paramater. - A plugin may have code only for instances but it must still be loaded on the master in order for it to be possible to load it on an instance. + A plugin may have code only for instances but it must still be loaded on the controller in order for it to be possible to load it on an instance. **InstanceConfigGroup**: Subclass of `PluginConfigGroup` for defining the per instance configuration fields for this plugin. See [Plugin Configuration](#plugin-configuration) -**masterEntrypoint**: - Path to a Node.js module relative to the plugin directory which contains the MasterPlugin class definiton for this plugin. +**controllerEntrypoint**: + Path to a Node.js module relative to the plugin directory which contains the ControllerPlugin class definiton for this plugin. This is an optional parameter. - A plugin can be made that only runs on the master server. + A plugin can be made that only runs on the controller. -**MasterConfigGroup**: - Subclass of `PluginConfigGroup` for defining the master server configuration fields for this plugin. +**ControllerConfigGroup**: + Subclass of `PluginConfigGroup` for defining the controller configuration fields for this plugin. See [Plugin Configuration](#plugin-configuration) **controlEntrypoint**: @@ -108,21 +108,21 @@ The optional module folder contains a Clusterio module that will be patched into 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. -While there is no standard for how to organize a plugin it's recommended to put the MasterPlugin class definition into master.js and the InstancePlugin class definition into instance.js. +While there is no standard for how to organize a plugin it's recommended to put the ControllerPlugin class definition into controller.js and the InstancePlugin class definition into instance.js. You can put them into whatever file you want (even the same one for both). -For both instanceEntrypoint and masterEntrypoint the path should not end with .js and it should use forward slashes for directory separators if any. +For both instanceEntrypoint and controllerEntrypoint the path should not end with .js and it should use forward slashes for directory separators if any. ## Defining the plugin class The plugin class should derive from its respective base class defined in `lib/plugin`. -For example, to define a MasterPlugin class the following code can be used: +For example, to define a ControllerPlugin class the following code can be used: ```js const libPlugin = require("@clusterio/lib/plugin"); -class MasterPlugin extends libPlugin.BaseMasterPlugin { +class ControllerPlugin extends libPlugin.BaseControllerPlugin { async init() { this.foo = 42; await this.startFrobnication(); @@ -132,11 +132,11 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin { } module.exports = { - MasterPlugin, + ControllerPlugin, } ``` -For the instance plugin it's exactly the same except "Master" is replaced with "Instance", and for the clusterioctl plugin "Control" is used. +For the instance plugin it's exactly the same except "Controller" is replaced with "Instance", and for the clusterioctl plugin "Control" is used. The available hooks that you can override are documented in the base class [in lib/plugin.js](/packages/lib/plugin.js). It's best to avoid defining a constructor, but if you insist on defining one, forward all arguments to the base class. @@ -202,39 +202,39 @@ For plugin hooks expections thrown are automatically catched and logged, but for ## Plugin Configuration Clusterio provides a configuration system that handles storing, distributing, editing and validating config fields for you. -You can take advantage of it by subclassing `PluginConfigGroup`, setting `defaultAccess` to where config entries can be accessed from, setting the `groupName` to your plugin name, defining fields on it, finalizing it, and passing it as either `MasterConfigGroup` or `InstanceConfigGroup` in the `info.js` export. +You can take advantage of it by subclassing `PluginConfigGroup`, setting `defaultAccess` to where config entries can be accessed from, setting the `groupName` to your plugin name, defining fields on it, finalizing it, and passing it as either `ControllerConfigGroup` or `InstanceConfigGroup` in the `info.js` export. For example in info.js: ```js const libConfig = require("@clusterio/lib/config"); -class MasterConfigGroup extends libConfig.PluginConfigGroup { } -MasterConfigGroup.defaultAccess = ["master", "slave", "control"]; -MasterConfigGroup.groupName = "foo_frobber"; -MasterConfigGroup.define({ +class ControllerConfigGroup extends libConfig.PluginConfigGroup { } +ControllerConfigGroup.defaultAccess = ["controller", "slave", "control"]; +ControllerConfigGroup.groupName = "foo_frobber"; +ControllerConfigGroup.define({ name: "level", description: "Level of frobnication done", type: "number", initial_value: 2, }); -MasterConfigGroup.finalize(); +ControllerConfigGroup.finalize(); module.exports = { ... - MasterConfigGroup: MasterConfigGroup, + ControllerConfigGroup: ControllerConfigGroup, }; ``` -Code inside the `MasterPlugin` class will then be able to access the level config field through the `Config` object at `this.master.config`, for example in the MasterPluginClass: +Code inside the `ControllerPlugin` class will then be able to access the level config field through the `Config` object at `this.controller.config`, for example in the ControllerPluginClass: ```js async init() { - let level = this.master.config.get("foo_frobber.level"); + let level = this.controller.config.get("foo_frobber.level"); this.logger.info(`I got a frobnication level of ${level}`); } ``` -The same applies for instance configs, replace "master" with "instance" where appropriate. +The same applies for instance configs, replace "controller" with "instance" where appropriate. See [Configuration System](config-system.md) for more details on how this system works. @@ -313,8 +313,8 @@ For RCON, commands longer than 50 characters may end up being executed after sho ## Defining Link Messages -You will most likely have to communicate with the master or other instances in your plugin for it to do anything useful. -For this there's a WebSocket communication channel established between the slaves and the master server that plugins can define their own messages to send over it. +You will most likely have to communicate with the controller or other instances in your plugin for it to do anything useful. +For this there's a WebSocket communication channel established between the slaves and the controller that plugins can define their own messages to send over it. This channel is bi-directional and all messages sent over it are validated with a JSON schema (see [this guide][guide] for an introduction to writing JSON schema). [guide]: https://json-schema.org/learn/getting-started-step-by-step.html @@ -335,7 +335,7 @@ The Event constructor takes an object of properties that define the event, for e messages: { startFrobnication: new libLink.Event({ type: "foo_frobber:start_frobnication", - links: ["master-slave", "slave-instance"], + links: ["controller-slave", "slave-instance"], forwardTo: "instance", eventRequired: ["frobnication_type"], eventProperties: { @@ -346,7 +346,7 @@ messages: { }, ``` -This specifies an event that can be sent from the master to a slave, and from a slave to an instance. +This specifies an event that can be sent from the controller to a slave, and from a slave to an instance. It also specifies that the event must contain the property `frobnication_type`, with a string value in the data payload and that it may optionally contain a boolean `urgent` property. It will also be forwarded by slaves to a specific instance. @@ -361,17 +361,17 @@ The type of the message sent over the socket will have the suffix `_event` appen #### links An array of strings describing which links this event can be sent over. -Direction matters, `"master-slave"` means the event can be sent from the master to the slave, but can't be sent back the other way, unless `"slave-master"` is also present in the links array. +Direction matters, `"controller-slave"` means the event can be sent from the controller to the slave, but can't be sent back the other way, unless `"slave-controller"` is also present in the links array. -The available endpoints are `master`, `slave`, `instance`, and `control`. -Master talks with slave and control, and slave talks to instance. -The full chain must be specified as the individual links in order for a message to travers multiple hops, (i.e., for a message to go from master to instance it must have both `"master-slave"` and `"slave-instance"` in the links array). +The available endpoints are `controller`, `slave`, `instance`, and `control`. +Controller talks with slave and control, and slave talks to instance. +The full chain must be specified as the individual links in order for a message to travers multiple hops, (i.e., for a message to go from controller to instance it must have both `"controller-slave"` and `"slave-instance"` in the links array). See `forwardTo` and `broadcastTo` for ways to forward an event to the next link in a chain. #### forwardTo Target to forward an event to. -Can either be `"master"`, to indicate a slave should forward it to the master server, or `"instance"`, to indicate it should be forwarded to the instances specified by the `instance_id` event property. +Can either be `"controller"`, to indicate a slave should forward it to the controller, or `"instance"`, to indicate it should be forwarded to the instances specified by the `instance_id` event property. This works by using a default handler for the event at the links that forward it. #### broadcastTo @@ -393,8 +393,8 @@ Object with properties mapping to a JSON schema of that property that specifies This is equivalent to using the `properties` keyword in JSON schema, except that the properties specified are by default required and additional properties are not allowed. See [this guide][guide] for an introduction to writing JSON schemas. -The forwardTo and broadcastTo can be combined such that specifying `"master"` as the forwardTo value and `"instance"` as the broadcastTo value will cause the event to be broadcast to all instances in the cluster. -For this to work, you will need to specify `instance-slave`, `slave-master`, `master-slave`, and `slave-instance` as the links. +The forwardTo and broadcastTo can be combined such that specifying `"controller"` as the forwardTo value and `"instance"` as the broadcastTo value will cause the event to be broadcast to all instances in the cluster. +For this to work, you will need to specify `instance-slave`, `slave-controller`, `controller-slave`, and `slave-instance` as the links. Keep in mind when forwarding events that if the target an event is being forwarded to is not online, the event will be dropped. Use a request if you need a confirmation that the message was received. @@ -410,7 +410,7 @@ For example, the following could be defined in `info.js`: messages: { reportFrobnication: new libLink.Request({ type: "foo_frobber:report_frobnication", - links: ["master-slave", "slave-instance"], + links: ["controller-slave", "slave-instance"], forwardTo: "instance", requestRequired: ["verbosity"], requestProperties: { @@ -427,7 +427,7 @@ messages: { }, ``` -This specifies a request that can be sent from the master to a slave, and from a slave to an instance. +This specifies a request that can be sent from the controller to a slave, and from a slave to an instance. The request data must contain the property `verbosity` with an integer number as the value, as well as the `instance_id` property (implied by `forwardTo: "instance"`) and it may also contain a boolean `special` property. It also defines that the response sent must contain a `report` property mapping to an array of strings. When received by a slave, it will also be forwarded to the instance specified by `instance_id`. @@ -443,17 +443,17 @@ The type of the message sent over the socket will have the suffix `_request` app #### links An array of strings describing which links this request can be sent over. -Direction matters; `"master-slave"` means the request can be sent from the master to the slave and the slave can reply to the master, but the slave can't send a request to the master unless `"slave-master"` is also present in the links array. +Direction matters; `"controller-slave"` means the request can be sent from the controller to the slave and the slave can reply to the controller, but the slave can't send a request to the controller unless `"slave-controller"` is also present in the links array. -The available endpoints are `master`, `slave`, `instance`, and `control`. -Master talks with slave and control, and slave talks to instance. -The full chain must be specified as the individual links in order for a message to travers multiple hops, (i.e., for a message to go from master to instance it must have both `"master-slave"` and `"slave-instance"` in the links array). +The available endpoints are `controller`, `slave`, `instance`, and `control`. +Controller talks with slave and control, and slave talks to instance. +The full chain must be specified as the individual links in order for a message to travers multiple hops, (i.e., for a message to go from controller to instance it must have both `"controller-slave"` and `"slave-instance"` in the links array). See `forwardTo` for ways to forward a request to the next link in a chain. #### forwardTo Target to forward the request to. -Can either be `"master"` to indicate a slave should forward it to the master server when receiving it from an instance, or `"instance"` to indicate it should be forwarded to the instances specified by the `instance_id` request property. +Can either be `"controller"` to indicate a slave should forward it to the controller when receiving it from an instance, or `"instance"` to indicate it should be forwarded to the instances specified by the `instance_id` request property. This works by using a default handler for the request by the links that forward it. #### requestRequired @@ -497,12 +497,12 @@ For the Request class the send method is async and returns the response data rec ### Handling connection events There are a few connection related events that plugins neeed to repsond to in order to avoid data loss and connection problems. -The most important is the prepare disconnect for the link between master and slave. -This is signaled to `MasterPlugin` classes via the `onPrepareSlaveDisconnect` hook and to `InstancePlugin` classes via the `onPrepareMasterDisconnect` hook. +The most important is the prepare disconnect for the link between controller and slave. +This is signaled to `ControllerPlugin` classes via the `onPrepareSlaveDisconnect` hook and to `InstancePlugin` classes via the `onPrepareControllerDisconnect` hook. After the prepare disconnect the connection will be closed, which will result in pending requests and events being dropped. Plugins must respond to the prepare disconnect by stopping any processess it does that send events or requests over the link in question. -This can be accomplished either through listening for the prepare disconnect hook, or by checking the `connected` property of the `SlaveConnection` class and `Slave` class on the master and slave respectively. +This can be accomplished either through listening for the prepare disconnect hook, or by checking the `connected` property of the `SlaveConnection` class and `Slave` class on the controller and slave respectively. For example the sending of an event from an `InstancePlugin` class can be stopped while the connection is not connected, not in the dropped state, and not in the process of discunnecting by using the following code: ```js @@ -511,12 +511,12 @@ if (this.slave.connected) { } ``` -If the event or request needs to be sent to the master it can be put into a queue stored on the plugin instance and sent out when the connection is established again. -The re-establishement of the connection is notified to plugins via the `connect` event to the `onMasterConnectionEvent` and `onSlaveConnectionEvent` hooks. +If the event or request needs to be sent to the controller it can be put into a queue stored on the plugin instance and sent out when the connection is established again. +The re-establishement of the connection is notified to plugins via the `connect` event to the `onControllerConnectionEvent` and `onSlaveConnectionEvent` hooks. -The second connection event which is of lesser importance to respond to is the `drop` connection event served through `onMasterConnectionEvent` for `InstancePlugin` classes and through `onSlaveConnectionEvent` for `MasterPlugin` classes. -This is raised when the connection between the master and slave in question is lost, most likely due to networking issues. -When in the dropped state the slave will keep trying to reconnect to the master server in order to re-establish it, and if successful no events or requests will be lost. +The second connection event which is of lesser importance to respond to is the `drop` connection event served through `onControllerConnectionEvent` for `InstancePlugin` classes and through `onSlaveConnectionEvent` for `ControllerPlugin` classes. +This is raised when the connection between the controller and slave in question is lost, most likely due to networking issues. +When in the dropped state the slave will keep trying to reconnect to the controller in order to re-establish it, and if successful no events or requests will be lost. However while in the dropped state any requests and events sent gets queued up in memory until the connection is either re-established or the session times out. This means that if your plugin sends a lot of events or requests, they can end up being queued up in a buffer and sent out all at once the connection is re-estabished. To avoid this you should be throtteling and/or stopping your requests/events after `drop` has been raised, and continue back as normal when `resume` is raised. @@ -536,11 +536,11 @@ const fooMetric = new Counter( "clusterio_foo_frobber_foo_metric", "Measures the level of foo", ); -// Somewhere in the master plugin code +// Somewhere in the controller plugin code fooMetric.inc(); ``` -This works for master plugins, and the metric will be automatically available through the /metric HTTP endpoint. +This works for controller plugins, and the metric will be automatically available through the /metric HTTP endpoint. It's recommended that plugin metrics follow `clusterio__` as the naming scheme. For metrics that are per-instance, you must define an `instance_id` label and set it accordingly, for example: @@ -557,11 +557,11 @@ const barMetric = new Gauge( barMetric.labels(String(this.instance.id)).set(someValue); ``` -Metrics are automatically registered to the default registry, and this default registry is automatically polled by the master server on slaves. +Metrics are automatically registered to the default registry, and this default registry is automatically polled by the controller on slaves. This means that it's important that you place the definition of the metric at module level so that it's not created more than once over the lifetime of a slave. Since the metrics remember their values and would continue to be exported after an instance is shutdown, there's code at instance shutdown that removes all the values where the `instance_id` label matches the id of the instance shut down. -For statistics you need to update on collection there's an `onMetrics` hook on both master and instance plugins that is run before the metrics in the default registry are collected. +For statistics you need to update on collection there's an `onMetrics` hook on both controller and instance plugins that is run before the metrics in the default registry are collected. ## Adding Custom Commands to clusterioctl @@ -600,7 +600,7 @@ For a command the `definition` is the arguments to pass to [yargs.command](http: The `handler` is an async function that's invoked when the command is executed and it's passed the parsed command line arguments and a reference to the `Control` class of clusterioctl. It's possible to optain a reference to the plugin class with `control.plugins.get(info.name)`. -Note that messages sent from clusterioctl needs to have `"control-master"` as a part of the links array for it to be accepted by the master server, see [Defining Link Messages](#defining-link-messages) for how to define the messages that can be sent to the master. +Note that messages sent from clusterioctl needs to have `"control-controller"` as a part of the links array for it to be accepted by the controller, see [Defining Link Messages](#defining-link-messages) for how to define the messages that can be sent to the controller. To have the command tree become part of clusterioctl it needs to be added to the rootCommand tree in `addCommands` callback of the Control plugin: diff --git a/package.json b/package.json index 2a07c477..63ab56b9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "devDependencies": { "@clusterio/ctl": "workspace:*", "@clusterio/lib": "workspace:*", - "@clusterio/master": "workspace:*", + "@clusterio/controller": "workspace:*", "@clusterio/slave": "workspace:*", "eslint": "^8.18.0", "eslint-plugin-node": "^11.1.0", diff --git a/packages/master/.npmignore b/packages/controller/.npmignore similarity index 100% rename from packages/master/.npmignore rename to packages/controller/.npmignore diff --git a/packages/master/README.md b/packages/controller/README.md similarity index 69% rename from packages/master/README.md rename to packages/controller/README.md index f63568b1..32bc0b85 100644 --- a/packages/master/README.md +++ b/packages/controller/README.md @@ -1,27 +1,27 @@ -# Clusterio Master Server +# Clusterio Controller Communication hub for Clusterio clusters. -The master server forwards data between Clusterio slaves connected to it and allows the cluster to be remotely managed through WebSocket connections to it either by using the included web interface or the Clusterio ctl command line utility. +The controller forwards data between Clusterio slaves connected to it and allows the cluster to be remotely managed through WebSocket connections to it either by using the included web interface or the Clusterio ctl command line utility. # Usage - npx clusteriomaster + npx clusteriocontroller Common options: - * `--plugin-list ` JSON file to use for storing the list of plugins that are available to the master server. + * `--plugin-list ` JSON file to use for storing the list of plugins that are available to the controller. Defaults to `plugin-list.json` and will be created if it does not exist. See the `plugin` command for managing this list. - * `--config ` JSON file to use for storing configuration for the master server. - Defaults to `config-master.json` and will be created if it does not exist. + * `--config ` JSON file to use for storing configuration for the controller. + Defaults to `config-controller.json` and will be created if it does not exist. See the `config` command for inspecting and modifying the configuration. ### `plugin ` -Configure plugins available to be loaded by the master server. +Configure plugins available to be loaded by the controller. The available plugins will be loaded unless they have been disabled in the configuration, see the config command for disabling plugins. @@ -33,9 +33,9 @@ A relative path must start with ./ or ../ (or .\ and ..\ on Windows) otherwise i For example, installing the Subspace Storage plugin: npm install @clusterio/plugin-subspace_storage - npx clusteriomaster plugin add @clusterio/plugin-subspace_storage + npx clusteriocontroller plugin add @clusterio/plugin-subspace_storage -Since the `plugin-list.json` is shared between master, slave and ctl you usually only need to do this once per machine. +Since the `plugin-list.json` is shared between controller, slave and ctl you usually only need to do this once per machine. #### `plugin remove ` @@ -46,10 +46,10 @@ Removing and unistalling a plugin is usually not neccessary as the functions pro For example, uninstalling the Subspace Storage plugin: - npx clusteriomaster plugin remove subspace_storage + npx clusteriocontroller plugin remove subspace_storage npm uninstall @clusterio/plugin-subspace_storage -Since the `plugin-list.json` is shared between master, slave and ctl you usually only need to do this once per machine. +Since the `plugin-list.json` is shared between controller, slave and ctl you usually only need to do this once per machine. #### `plugin list` @@ -59,8 +59,8 @@ Lists the plugins set up to be available by name followed by path. ### `config` -Manage the master server configuration offline. -This should only be used when the master server is stopped, otherwise the config read might be out of date and config changes will be overwritten when the master server shuts down. +Manage the controller configuration offline. +This should only be used when the controller is stopped, otherwise the config read might be out of date and config changes will be overwritten when the controller shuts down. #### `config set [value]` @@ -96,7 +96,7 @@ You should be using your own Factorio multiplayer username here. #### `bootstrap generate-user-token ` Generate an access token for logging in and possibly managing the cluster from the given user account. -This can be used both in the web interface and as the `master_token` to connect with clusterioctl. +This can be used both in the web interface and as the `controller_token` to connect with clusterioctl. #### `bootstrap create-ctl-config ` @@ -106,7 +106,7 @@ Creates a clusterioctl config for the given user with url and token set up for c ### `run` -Runs the master server. +Runs the controller. ## See Also diff --git a/packages/master/master.js b/packages/controller/controller.js similarity index 71% rename from packages/master/master.js rename to packages/controller/controller.js index b1a21cc9..94622fc1 100755 --- a/packages/master/master.js +++ b/packages/controller/controller.js @@ -1,17 +1,17 @@ #!/usr/bin/env node /** - * Clusterio master server + * Clusterio controller * * Facilitates communication between slaves and control of the cluster * through WebSocet connections, and hosts a webserver for browser * interfaces and Prometheus statistics export. It is remotely controlled * by {@link module:ctl/ctl}. * - * @module master/master + * @module controller/controller * @author Danielv123, Hornwitser * @example - * npx clusteriomaster run + * npx clusteriocontroller run */ "use strict"; @@ -36,25 +36,25 @@ const libSharedCommands = require("@clusterio/lib/shared_commands"); const { ConsoleTransport, levels, logger } = require("@clusterio/lib/logging"); const libLoggingUtils = require("@clusterio/lib/logging_utils"); -const Master = require("./src/Master"); +const Controller = require("./src/Controller"); const UserManager = require("./src/UserManager"); const version = require("./package").version; // globals -let master; +let controller; void new libPrometheus.Gauge( - "clusterio_master_slave_mapping", + "clusterio_controller_slave_mapping", "Mapping of Slave ID to name", { labels: ["slave_id", "slave_name"], callback: function(gauge) { gauge.clear(); - if (!master || !master.slaves) { + if (!controller || !controller.slaves) { return; } - for (let [id, slave] of master.slaves) { + for (let [id, slave] of controller.slaves) { gauge.labels({ slave_id: String(id), slave_name: slave.name, @@ -65,16 +65,16 @@ void new libPrometheus.Gauge( ); void new libPrometheus.Gauge( - "clusterio_master_instance_mapping", + "clusterio_controller_instance_mapping", "Mapping of Instance ID to name and slave", { labels: ["instance_id", "instance_name", "slave_id"], callback: function(gauge) { gauge.clear(); - if (!master || !master.instances) { + if (!controller || !controller.instances) { return; } - for (let [id, instance] of master.instances) { + for (let [id, instance] of controller.instances) { gauge.labels({ instance_id: String(id), instance_name: String(instance.config.get("instance.name")), @@ -86,32 +86,32 @@ void new libPrometheus.Gauge( ); void new libPrometheus.Gauge( - "clusterio_master_websocket_active_connections", - "How many WebSocket connections are currently open to the master server", - { callback: function(gauge) { gauge.set(master.wsServer.activeConnectors.size); }} + "clusterio_controller_websocket_active_connections", + "How many WebSocket connections are currently open to the controller", + { callback: function(gauge) { gauge.set(controller.wsServer.activeConnectors.size); }} ); void new libPrometheus.Gauge( - "clusterio_master_active_slaves", - "How many slaves are currently connected to the master", - { callback: function(gauge) { gauge.set(master.wsServer.slaveConnections.size); }} + "clusterio_controller_active_slaves", + "How many slaves are currently connected to the controller", + { callback: function(gauge) { gauge.set(controller.wsServer.slaveConnections.size); }} ); void new libPrometheus.Gauge( - "clusterio_master_connected_clients_count", "How many clients are currently connected to this master server", + "clusterio_controller_connected_clients_count", "How many clients are currently connected to this controller", { labels: ["type"], callback: async function(gauge) { - gauge.labels("slave").set(master.wsServer.slaveConnections.size); - gauge.labels("control").set(master.wsServer.controlConnections.length); + gauge.labels("slave").set(controller.wsServer.slaveConnections.size); + gauge.labels("control").set(controller.wsServer.controlConnections.length); }, }, ); -async function handleBootstrapCommand(args, masterConfig) { +async function handleBootstrapCommand(args, controllerConfig) { let subCommand = args._[1]; - let userManager = new UserManager(masterConfig); - await userManager.load(path.join(masterConfig.get("master.database_directory"), "users.json")); + let userManager = new UserManager(controllerConfig); + await userManager.load(path.join(controllerConfig.get("controller.database_directory"), "users.json")); if (subCommand === "create-admin") { if (!args.name) { logger.error("name cannot be blank"); @@ -127,7 +127,7 @@ async function handleBootstrapCommand(args, masterConfig) { let adminRole = libUsers.ensureDefaultAdminRole(userManager.roles); admin.roles.add(adminRole); admin.isAdmin = true; - await userManager.save(path.join(masterConfig.get("master.database_directory"), "users.json")); + await userManager.save(path.join(controllerConfig.get("controller.database_directory"), "users.json")); } else if (subCommand === "generate-user-token") { let user = userManager.users.get(args.name); @@ -137,13 +137,13 @@ async function handleBootstrapCommand(args, masterConfig) { return; } // eslint-disable-next-line no-console - console.log(user.createToken(masterConfig.get("master.auth_secret"))); + console.log(user.createToken(controllerConfig.get("controller.auth_secret"))); } else if (subCommand === "generate-slave-token") { // eslint-disable-next-line no-console console.log(jwt.sign( { aud: "slave", slave: args.id }, - Buffer.from(masterConfig.get("master.auth_secret"), "base64") + Buffer.from(controllerConfig.get("controller.auth_secret"), "base64") )); } else if (subCommand === "create-ctl-config") { @@ -156,8 +156,10 @@ async function handleBootstrapCommand(args, masterConfig) { let controlConfig = new libConfig.ControlConfig("control"); await controlConfig.init(); - controlConfig.set("control.master_url", Master.calculateMasterUrl(masterConfig)); - controlConfig.set("control.master_token", admin.createToken(masterConfig.get("master.auth_secret"))); + controlConfig.set("control.controller_url", Controller.calculateControllerUrl(controllerConfig)); + controlConfig.set( + "control.controller_token", admin.createToken(controllerConfig.get("controller.auth_secret")) + ); let content = JSON.stringify(controlConfig.serialize(), null, 4); if (args.output === "-") { @@ -176,13 +178,13 @@ async function initialize() { shouldRun: false, clusterLogger: null, pluginInfos: null, - masterConfigPath: null, - masterConfig: null, + controllerConfigPath: null, + controllerConfig: null, }; // argument parsing parameters.args = yargs - .scriptName("master") + .scriptName("controller") .usage("$0 [options]") .option("log-level", { nargs: 1, @@ -199,8 +201,8 @@ async function initialize() { }) .option("config", { nargs: 1, - describe: "master config file to use", - default: "config-master.json", + describe: "controller config file to use", + default: "config-controller.json", type: "string", }) .option("plugin-list", { @@ -210,7 +212,7 @@ async function initialize() { type: "string", }) .command("plugin", "Manage available plugins", libSharedCommands.pluginCommand) - .command("config", "Manage Master config", libSharedCommands.configCommand) + .command("config", "Manage Controller config", libSharedCommands.configCommand) .command("bootstrap", "Bootstrap access to cluster", yargs => { yargs .command("create-admin ", "Create a cluster admin") @@ -226,7 +228,7 @@ async function initialize() { }) .demandCommand(1, "You need to specify a command to run"); }) - .command("run", "Run master server", yargs => { + .command("run", "Run controller", yargs => { yargs.option("dev", { hidden: true, type: "boolean", nargs: 0 }); yargs.option("dev-plugin", { hidden: true, type: "array" }); }) @@ -247,12 +249,12 @@ async function initialize() { console.log("Migration complete, you should delete cluster.log now"); } - let masterLogDirectory = path.join(parameters.args.logDirectory, "master"); - if (!await fs.pathExists(masterLogDirectory) && await fs.pathExists("master.log")) { - console.log("Migrating master log..."); - await fs.ensureDir(masterLogDirectory); - await libLoggingUtils.migrateLogs("master.log", masterLogDirectory, "master-%DATE%.log"); - console.log("Migration complete, you should delete master.log now"); + let controllerLogDirectory = path.join(parameters.args.logDirectory, "controller"); + if (!await fs.pathExists(controllerLogDirectory) && await fs.pathExists("controller.log")) { + console.log("Migrating controller log..."); + await fs.ensureDir(controllerLogDirectory); + await libLoggingUtils.migrateLogs("controller.log", controllerLogDirectory, "controller-%DATE%.log"); + console.log("Migration complete, you should delete controller.log now"); } /* eslint-enable no-console */ } @@ -269,11 +271,11 @@ async function initialize() { dirname: path.join(parameters.args.logDirectory, "cluster"), })); - // Log stream for the master server. + // Log stream for the controller. logger.add(new winston.transports.DailyRotateFile({ format: winston.format.json(), - filename: "master-%DATE%.log", - dirname: path.join(parameters.args.logDirectory, "master"), + filename: "controller-%DATE%.log", + dirname: path.join(parameters.args.logDirectory, "controller"), })); logger.add(new winston.transports.Stream({ stream: parameters.clusterLogger, @@ -288,7 +290,7 @@ async function initialize() { let command = parameters.args._[0]; if (command === "run") { - logger.info(`Starting Clusterio master ${version}`); + logger.info(`Starting Clusterio controller ${version}`); parameters.shouldRun = true; } @@ -313,39 +315,39 @@ async function initialize() { libConfig.registerPluginConfigGroups(parameters.pluginInfos); libConfig.finalizeConfigs(); - parameters.masterConfigPath = parameters.args.config; - logger.info(`Loading config from ${parameters.masterConfigPath}`); - parameters.masterConfig = new libConfig.MasterConfig("master"); + parameters.controllerConfigPath = parameters.args.config; + logger.info(`Loading config from ${parameters.controllerConfigPath}`); + parameters.controllerConfig = new libConfig.ControllerConfig("controller"); try { - await parameters.masterConfig.load(JSON.parse(await fs.readFile(parameters.masterConfigPath))); + await parameters.controllerConfig.load(JSON.parse(await fs.readFile(parameters.controllerConfigPath))); } catch (err) { if (err.code === "ENOENT") { logger.info("Config not found, initializing new config"); - await parameters.masterConfig.init(); + await parameters.controllerConfig.init(); } else { - throw new libErrors.StartupError(`Failed to load ${parameters.masterConfigPath}: ${err.message}`); + throw new libErrors.StartupError(`Failed to load ${parameters.controllerConfigPath}: ${err.message}`); } } - if (!parameters.masterConfig.get("master.auth_secret")) { - logger.info("Generating new master authentication secret"); + if (!parameters.controllerConfig.get("controller.auth_secret")) { + logger.info("Generating new controller authentication secret"); let asyncRandomBytes = util.promisify(crypto.randomBytes); let bytes = await asyncRandomBytes(256); - parameters.masterConfig.set("master.auth_secret", bytes.toString("base64")); + parameters.controllerConfig.set("controller.auth_secret", bytes.toString("base64")); await libFileOps.safeOutputFile( - parameters.masterConfigPath, JSON.stringify(parameters.masterConfig.serialize(), null, 4) + parameters.controllerConfigPath, JSON.stringify(parameters.controllerConfig.serialize(), null, 4) ); } if (command === "config") { await libSharedCommands.handleConfigCommand( - parameters.args, parameters.masterConfig, parameters.masterConfigPath + parameters.args, parameters.controllerConfig, parameters.controllerConfigPath ); } else if (command === "bootstrap") { - await handleBootstrapCommand(parameters.args, parameters.masterConfig); + await handleBootstrapCommand(parameters.args, parameters.controllerConfig); } return parameters; @@ -354,14 +356,14 @@ async function initialize() { async function startup() { // Set the process title, shows up as the title of the CMD window on windows // and as the process name in ps/top on linux. - process.title = "clusterioMaster"; + process.title = "clusterioController"; - let { args, shouldRun, clusterLogger, pluginInfos, masterConfigPath, masterConfig } = await initialize(); + let { args, shouldRun, clusterLogger, pluginInfos, controllerConfigPath, controllerConfig } = await initialize(); if (!shouldRun) { return; } - master = new Master(clusterLogger, pluginInfos, masterConfigPath, masterConfig); + controller = new Controller(clusterLogger, pluginInfos, controllerConfigPath, controllerConfig); let secondSigint = false; process.on("SIGINT", () => { @@ -374,7 +376,7 @@ async function startup() { secondSigint = true; logger.info("Caught interrupt signal, shutting down"); - master.stop(); + controller.stop(); }); let secondSigterm = false; process.on("SIGTERM", () => { @@ -387,15 +389,15 @@ async function startup() { secondSigterm = true; logger.info("Caught termination signal, shutting down"); - master.stop(); + controller.stop(); }); process.on("SIGHUP", () => { logger.info("Terminal closed, shutting down"); - master.stop(); + controller.stop(); }); - await master.start(args); + await controller.start(args); } module.exports = { @@ -413,9 +415,9 @@ I version of clusterio. Expect things to break. I startup().catch(err => { if (err instanceof libErrors.StartupError) { logger.fatal(` -+----------------------------------+ -| Unable to to start master server | -+----------------------------------+ ++-------------------------------+ +| Unable to to start controller | ++-------------------------------+ ${err.stack}` ); } else if (err instanceof libErrors.PluginError) { @@ -428,7 +430,7 @@ ${err.original.stack}` } else { logger.fatal(` +------------------------------------------------------------+ -| Unexpected error occured while starting master, please | +| Unexpected error occured while starting controller, please | | report it to https://github.com/clusterio/clusterio/issues | +------------------------------------------------------------+ ${err.stack}` diff --git a/packages/master/package.json b/packages/controller/package.json similarity index 85% rename from packages/master/package.json rename to packages/controller/package.json index a25bac70..c5a94a4d 100644 --- a/packages/master/package.json +++ b/packages/controller/package.json @@ -1,16 +1,16 @@ { - "name": "@clusterio/master", - "description": "Implementation of Clusterio master server", + "name": "@clusterio/controller", + "description": "Implementation of Clusterio controller", "author": "Hornwitser", "license": "MIT", "version": "2.0.0-alpha.13", - "main": "master.js", + "main": "controller.js", "scripts": { "prepare": "webpack-cli --env production", "test": "echo \"Error: no test specified\" && exit 1" }, "bin": { - "clusteriomaster": "./master.js" + "clusteriocontroller": "./controller.js" }, "keywords": [ "factorio" diff --git a/packages/master/src/BaseConnection.js b/packages/controller/src/BaseConnection.js similarity index 70% rename from packages/master/src/BaseConnection.js rename to packages/controller/src/BaseConnection.js index 92e25c1d..07463634 100644 --- a/packages/master/src/BaseConnection.js +++ b/packages/controller/src/BaseConnection.js @@ -6,35 +6,35 @@ const libPlugin = require("@clusterio/lib/plugin"); /** - * Base class for master server connections + * Base class for controller connections * * @extends module:lib/link.Link - * @alias module:master/src/BaseConnection + * @alias module:controller/src/BaseConnection */ class BaseConnection extends libLink.Link { - constructor(target, connector, master) { - /** @member {module:master/src/WsServerConnector} module:master/src/BaseConnection#connector */ - super("master", target, connector); - this._master = master; + constructor(target, connector, controller) { + /** @member {module:controller/src/WsServerConnector} module:controller/src/BaseConnection#connector */ + super("controller", target, connector); + this._controller = controller; this._disconnecting = false; libLink.attachAllMessages(this); - for (let masterPlugin of this._master.plugins.values()) { - libPlugin.attachPluginMessages(this, masterPlugin); + for (let controllerPlugin of this._controller.plugins.values()) { + libPlugin.attachPluginMessages(this, controllerPlugin); } } async forwardRequestToInstance(message, request) { - return await this._master.forwardRequestToInstance(request, message.data); + return await this._controller.forwardRequestToInstance(request, message.data); } async forwardEventToInstance(message, event) { - let instance = this._master.instances.get(message.data.instance_id); + let instance = this._controller.instances.get(message.data.instance_id); if (!instance) { return; } let slaveId = instance.config.get("instance.assigned_slave"); if (slaveId === null) { return; } - let connection = this._master.wsServer.slaveConnections.get(slaveId); + let connection = this._controller.wsServer.slaveConnections.get(slaveId); if (!connection || connection.closing) { return; } if (event.plugin && !connection.plugins.has(event.plugin)) { return; } @@ -42,7 +42,7 @@ class BaseConnection extends libLink.Link { } async broadcastEventToSlaves(message, event) { - for (let slaveConnection of this._master.wsServer.slaveConnections.values()) { + for (let slaveConnection of this._controller.wsServer.slaveConnections.values()) { // Do not broadcast back to the source if (slaveConnection === this) { continue; } if (slaveConnection.connector.closing) { continue; } @@ -57,7 +57,7 @@ class BaseConnection extends libLink.Link { } async prepareDisconnectRequestHandler(message, request) { - await libPlugin.invokeHook(this._master.plugins, "onPrepareSlaveDisconnect", this); + await libPlugin.invokeHook(this._controller.plugins, "onPrepareSlaveDisconnect", this); this._disconnecting = true; this.connector.setClosing(); return await super.prepareDisconnectRequestHandler(message, request); @@ -87,7 +87,7 @@ class BaseConnection extends libLink.Link { async getModPackRequestHandler(message) { let { id } = message.data; - let modPack = this._master.modPacks.get(id); + let modPack = this._controller.modPacks.get(id); if (!modPack) { throw new libErrors.RequestError(`Mod pack with ID ${id} does not exist`); } @@ -95,11 +95,11 @@ class BaseConnection extends libLink.Link { } async getDefaultModPackRequestHandler(message) { - let id = this._master.config.get("master.default_mod_pack_id"); + let id = this._controller.config.get("controller.default_mod_pack_id"); if (id === null) { - throw new libErrors.RequestError("Default mod pack not set on master"); + throw new libErrors.RequestError("Default mod pack not set on controller"); } - let modPack = this._master.modPacks.get(id); + let modPack = this._controller.modPacks.get(id); if (!modPack) { throw new libErrors.RequestError(`Default mod pack configured (${id}) does not exist`); } diff --git a/packages/master/src/ControlConnection.js b/packages/controller/src/ControlConnection.js similarity index 75% rename from packages/master/src/ControlConnection.js rename to packages/controller/src/ControlConnection.js index 5fe52b8f..acc89075 100644 --- a/packages/master/src/ControlConnection.js +++ b/packages/controller/src/ControlConnection.js @@ -21,19 +21,19 @@ const routes = require("./routes"); const strcmp = new Intl.Collator(undefined, { numerice: "true", sensitivity: "base" }).compare; const queryLogTime = new libPrometheus.Summary( - "clusterio_master_query_log_duration_seconds", + "clusterio_controller_query_log_duration_seconds", "Time in seconds log queries took to execute." ); /** * Represents the connection to a control link * - * @extends module:master/src/BaseConnection - * @alias module:master/src/ControlConnection + * @extends module:controller/src/BaseConnection + * @alias module:controller/src/ControlConnection */ class ControlConnection extends BaseConnection { - constructor(registerData, connector, master, user) { - super("control", connector, master); + constructor(registerData, connector, controller, user) { + super("control", connector, controller); this._agent = registerData.agent; this._version = registerData.version; @@ -77,7 +77,7 @@ class ControlConnection extends BaseConnection { this.logTransport = null; this.logSubscriptions = { all: false, - master: false, + controller: false, slave_ids: [], instance_ids: [], }; @@ -92,42 +92,42 @@ class ControlConnection extends BaseConnection { logger.remove(this.logTransport); } if (this.ws_dumper) { - this._master.debugEvents.off("message", this.ws_dumper); + this._controller.debugEvents.off("message", this.ws_dumper); } }); for (let event of ["connect", "drop", "resume", "close"]) { this.connector.on(event, () => { - for (let masterPlugin of this._master.plugins.values()) { - masterPlugin.onControlConnectionEvent(this, event); + for (let controllerPlugin of this._controller.plugins.values()) { + controllerPlugin.onControlConnectionEvent(this, event); } }); } } - async getMasterConfigRequestHandler() { - return { serialized_config: this._master.config.serialize("control") }; + async getControllerConfigRequestHandler() { + return { serialized_config: this._controller.config.serialize("control") }; } - async setMasterConfigFieldRequestHandler(message) { - this._master.config.set(message.data.field, message.data.value, "control"); + async setControllerConfigFieldRequestHandler(message) { + this._controller.config.set(message.data.field, message.data.value, "control"); } - async setMasterConfigPropRequestHandler(message) { + async setControllerConfigPropRequestHandler(message) { let { field, prop, value } = message.data; - this._master.config.setProp(field, prop, value, "control"); + this._controller.config.setProp(field, prop, value, "control"); } async listSlavesRequestHandler(message) { let list = []; - for (let slave of this._master.slaves.values()) { + for (let slave of this._controller.slaves.values()) { list.push({ agent: slave.agent, version: slave.version, id: slave.id, name: slave.name, public_address: slave.public_address || null, - connected: this._master.wsServer.slaveConnections.has(slave.id), + connected: this._controller.wsServer.slaveConnections.has(slave.id), }); } return { list }; @@ -149,7 +149,7 @@ class ControlConnection extends BaseConnection { generateSlaveToken(slaveId) { return jwt.sign( { aud: "slave", slave: slaveId }, - Buffer.from(this._master.config.get("master.auth_secret"), "base64") + Buffer.from(this._controller.config.get("controller.auth_secret"), "base64") ); } @@ -165,7 +165,7 @@ class ControlConnection extends BaseConnection { let slaveConfig = new libConfig.SlaveConfig("control"); await slaveConfig.init(); - slaveConfig.set("slave.master_url", this._master.getMasterUrl()); + slaveConfig.set("slave.controller_url", this._controller.getControllerUrl()); if (message.data.id !== null) { slaveConfig.set("slave.id", message.data.id); } @@ -174,14 +174,14 @@ class ControlConnection extends BaseConnection { } if (message.data.generate_token) { this.user.checkPermission("core.slave.generate_token"); - slaveConfig.set("slave.master_token", this.generateSlaveToken(slaveConfig.get("slave.id"))); + slaveConfig.set("slave.controller_token", this.generateSlaveToken(slaveConfig.get("slave.id"))); } return { serialized_config: slaveConfig.serialize() }; } async getInstanceRequestHandler(message) { let id = message.data.id; - let instance = this._master.getRequestInstance(id); + let instance = this._controller.getRequestInstance(id); return { id, @@ -194,7 +194,7 @@ class ControlConnection extends BaseConnection { async listInstancesRequestHandler(message) { let list = []; - for (let instance of this._master.instances.values()) { + for (let instance of this._controller.instances.values()) { list.push({ id: instance.config.get("instance.id"), name: instance.config.get("instance.name"), @@ -227,18 +227,18 @@ class ControlConnection extends BaseConnection { // XXX should probably add a hook for slave reuqests? async createInstanceRequestHandler(message) { - let instanceConfig = new libConfig.InstanceConfig("master"); + let instanceConfig = new libConfig.InstanceConfig("controller"); await instanceConfig.load(message.data.serialized_config); let instanceId = instanceConfig.get("instance.id"); - if (this._master.instances.has(instanceId)) { + if (this._controller.instances.has(instanceId)) { throw new libErrors.RequestError(`Instance with ID ${instanceId} already exists`); } // Add common settings for the Factorio server let settings = { - "name": `${this._master.config.get("master.name")} - ${instanceConfig.get("instance.name")}`, - "description": `Clusterio instance for ${this._master.config.get("master.name")}`, + "name": `${this._controller.config.get("controller.name")} - ${instanceConfig.get("instance.name")}`, + "description": `Clusterio instance for ${this._controller.config.get("controller.name")}`, "tags": ["clusterio"], "max_players": 0, "visibility": { "public": true, "lan": true }, @@ -262,26 +262,26 @@ class ControlConnection extends BaseConnection { instanceConfig.set("factorio.settings", settings); let instance = { config: instanceConfig, status: "unassigned" }; - this._master.instances.set(instanceId, instance); - await libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", instance, null); - this._master.addInstanceHooks(instance); + this._controller.instances.set(instanceId, instance); + await libPlugin.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, null); + this._controller.addInstanceHooks(instance); } async deleteInstanceRequestHandler(message, request) { - let instance = this._master.getRequestInstance(message.data.instance_id); + let instance = this._controller.getRequestInstance(message.data.instance_id); if (instance.config.get("instance.assigned_slave") !== null) { await this.forwardRequestToInstance(message, request); } - this._master.instances.delete(message.data.instance_id); + this._controller.instances.delete(message.data.instance_id); let prev = instance.status; instance.status = "deleted"; - this._master.instanceUpdated(instance); - await libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", instance, prev); + this._controller.instanceUpdated(instance); + await libPlugin.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev); } async getInstanceConfigRequestHandler(message) { - let instance = this._master.getRequestInstance(message.data.instance_id); + let instance = this._controller.getRequestInstance(message.data.instance_id); return { serialized_config: instance.config.serialize("control"), }; @@ -290,7 +290,7 @@ class ControlConnection extends BaseConnection { async updateInstanceConfig(instance) { let slaveId = instance.config.get("instance.assigned_slave"); if (slaveId !== null) { - let connection = this._master.wsServer.slaveConnections.get(slaveId); + let connection = this._controller.wsServer.slaveConnections.get(slaveId); if (connection) { await libLink.messages.assignInstance.send(connection, { instance_id: instance.config.get("instance.id"), @@ -301,7 +301,7 @@ class ControlConnection extends BaseConnection { } async setInstanceConfigFieldRequestHandler(message) { - let instance = this._master.getRequestInstance(message.data.instance_id); + let instance = this._controller.getRequestInstance(message.data.instance_id); if (message.data.field === "instance.assigned_slave") { throw new libErrors.RequestError("instance.assigned_slave must be set through the assign-slave interface"); } @@ -316,7 +316,7 @@ class ControlConnection extends BaseConnection { } async setInstanceConfigPropRequestHandler(message) { - let instance = this._master.getRequestInstance(message.data.instance_id); + let instance = this._controller.getRequestInstance(message.data.instance_id); let { field, prop, value } = message.data; instance.config.setProp(field, prop, value, "control"); await this.updateInstanceConfig(instance); @@ -324,26 +324,26 @@ class ControlConnection extends BaseConnection { async assignInstanceCommandRequestHandler(message, request) { let { slave_id, instance_id } = message.data; - let instance = this._master.getRequestInstance(instance_id); + let instance = this._controller.getRequestInstance(instance_id); // Check if target slave is connected let newSlaveConnection; if (slave_id !== null) { - newSlaveConnection = this._master.wsServer.slaveConnections.get(slave_id); + newSlaveConnection = this._controller.wsServer.slaveConnections.get(slave_id); if (!newSlaveConnection) { // The case of the slave not getting the assign instance message // still have to be handled, so it's not a requirement that the - // target slave be connected to the master while doing the + // target slave be connected to the controller while doing the // assignment, but it is IMHO a better user experience if this // is the case. - throw new libErrors.RequestError("Target slave is not connected to the master server"); + throw new libErrors.RequestError("Target slave is not connected to the controller"); } } // Unassign from currently assigned slave if it is connected. let currentAssignedSlave = instance.config.get("instance.assigned_slave"); if (currentAssignedSlave !== null && slave_id !== currentAssignedSlave) { - let oldSlaveConnection = this._master.wsServer.slaveConnections.get(currentAssignedSlave); + let oldSlaveConnection = this._controller.wsServer.slaveConnections.get(currentAssignedSlave); if (oldSlaveConnection && !oldSlaveConnection.connector.closing) { await libLink.messages.unassignInstance.send(oldSlaveConnection, { instance_id }); } @@ -358,7 +358,7 @@ class ControlConnection extends BaseConnection { }); } else { instance.status = "unassigned"; - this._master.instanceUpdated(instance); + this._controller.instanceUpdated(instance); } } @@ -377,7 +377,7 @@ class ControlConnection extends BaseConnection { async downloadSaveRequestHandler(message) { let { instance_id, save } = message.data; - let stream = await routes.createProxyStream(this._master.app); + let stream = await routes.createProxyStream(this._controller.app); stream.filename = save; let ready = new Promise((resolve, reject) => { @@ -388,7 +388,7 @@ class ControlConnection extends BaseConnection { }); ready.catch(() => {}); - await this._master.forwardRequestToInstance(libLink.messages.pushSave, { + await this._controller.forwardRequestToInstance(libLink.messages.pushSave, { instance_id, stream_id: stream.id, save, @@ -409,8 +409,8 @@ class ControlConnection extends BaseConnection { if (instance_id === target_instance_id) { throw new libErrors.RequestError("Source and target instance may not be the same"); } - let sourceInstance = this._master.getRequestInstance(instance_id); - let targetInstance = this._master.getRequestInstance(target_instance_id); + let sourceInstance = this._controller.getRequestInstance(instance_id); + let targetInstance = this._controller.getRequestInstance(target_instance_id); let sourceSlaveId = sourceInstance.config.get("instance.assigned_slave"); let targetSlaveId = targetInstance.config.get("instance.assigned_slave"); if (sourceSlaveId === null) { @@ -426,18 +426,18 @@ class ControlConnection extends BaseConnection { } // Check connectivity - let sourceSlaveConnection = this._master.wsServer.slaveConnections.get(sourceSlaveId); + let sourceSlaveConnection = this._controller.wsServer.slaveConnections.get(sourceSlaveId); if (!sourceSlaveConnection || sourceSlaveConnection.closing) { - throw new libErrors.RequestError("Source slave is not connected to the master server"); + throw new libErrors.RequestError("Source slave is not connected to the controller"); } - let targetSlaveConnection = this._master.wsServer.slaveConnections.get(targetSlaveId); + let targetSlaveConnection = this._controller.wsServer.slaveConnections.get(targetSlaveId); if (!targetSlaveConnection || targetSlaveConnection.closing) { - throw new libErrors.RequestError("Target slave is not connected to the master server"); + throw new libErrors.RequestError("Target slave is not connected to the controller"); } // Create stream to proxy from target to source - let stream = await routes.createProxyStream(this._master.app); + let stream = await routes.createProxyStream(this._controller.app); stream.events.on("timeout", () => { if (stream.source) { stream.source.destroy(); @@ -451,7 +451,7 @@ class ControlConnection extends BaseConnection { // Establish push from source slave to stream, this is done first to // ensure the file size is known prior to the target slave pull. await Promise.all([ - this._master.forwardRequestToInstance(libLink.messages.pushSave, { + this._controller.forwardRequestToInstance(libLink.messages.pushSave, { instance_id, stream_id: stream.id, save: source_save, @@ -460,7 +460,7 @@ class ControlConnection extends BaseConnection { ]); // Establish pull from target slave to stream and wait for completion. - let result = await this._master.forwardRequestToInstance(libLink.messages.pullSave, { + let result = await this._controller.forwardRequestToInstance(libLink.messages.pullSave, { instance_id: target_instance_id, stream_id: stream.id, filename: target_save, @@ -468,7 +468,7 @@ class ControlConnection extends BaseConnection { // Delete source save if this is not a copy if (!copy) { - await this._master.forwardRequestToInstance(libLink.messages.deleteSave, { + await this._controller.forwardRequestToInstance(libLink.messages.deleteSave, { instance_id, save: source_save, }); @@ -478,7 +478,7 @@ class ControlConnection extends BaseConnection { } async listModPacksRequestHandler(message) { - return { list: [...this._master.modPacks.values()].map(pack => pack.toJSON()) }; + return { list: [...this._controller.modPacks.values()].map(pack => pack.toJSON()) }; } async setModPackSubscriptionsRequestHandler(message) { @@ -487,31 +487,31 @@ class ControlConnection extends BaseConnection { async createModPackRequestHandler(message) { let modPack = new libData.ModPack(message.data.mod_pack); - if (this._master.modPacks.has(modPack.id)) { + if (this._controller.modPacks.has(modPack.id)) { throw new libErrors.RequestError(`Mod pack with ID ${modPack.id} already exist`); } - this._master.modPacks.set(modPack.id, modPack); - this._master.modPackUpdated(modPack); + this._controller.modPacks.set(modPack.id, modPack); + this._controller.modPackUpdated(modPack); } async updateModPackRequestHandler(message) { let modPack = new libData.ModPack(message.data.mod_pack); - if (!this._master.modPacks.has(modPack.id)) { + if (!this._controller.modPacks.has(modPack.id)) { throw new libErrors.RequestError(`Mod pack with ID ${modPack.id} does not exist`); } - this._master.modPacks.set(modPack.id, modPack); - this._master.modPackUpdated(modPack); + this._controller.modPacks.set(modPack.id, modPack); + this._controller.modPackUpdated(modPack); } async deleteModPackRequestHandler(message) { let { id } = message.data; - let modPack = this._master.modPacks.get(id); + let modPack = this._controller.modPacks.get(id); if (!modPack) { throw new libErrors.RequestError(`Mod pack with ID ${id} does not exist`); } modPack.isDeleted = true; - this._master.modPacks.delete(id); - this._master.modPackUpdated(modPack); + this._controller.modPacks.delete(id); + this._controller.modPackUpdated(modPack); } modPackUpdated(modPack) { @@ -526,7 +526,7 @@ class ControlConnection extends BaseConnection { async getModRequestHandler(message) { let { name, version } = message.data; let filename = `${name}_${version}.zip`; - let mod = this._master.mods.get(filename); + let mod = this._controller.mods.get(filename); if (!mod) { throw new libErrors.RequestError(`Mod ${filename} does not exist`); } @@ -536,7 +536,7 @@ class ControlConnection extends BaseConnection { } async listModsRequestHandler(message) { - return { list: [...this._master.mods.values()].map(mod => mod.toJSON()) }; + return { list: [...this._controller.mods.values()].map(mod => mod.toJSON()) }; } static termsMatchesMod(terms, mod) { @@ -575,7 +575,7 @@ class ControlConnection extends BaseConnection { let factorioVersion = message.data.factorio_version; let results = new Map(); - for (let mod of this._master.mods.values()) { + for (let mod of this._controller.mods.values()) { if ( mod.factorioVersion !== factorioVersion || !ControlConnection.termsMatchesMod(query.terms, mod) @@ -634,13 +634,13 @@ class ControlConnection extends BaseConnection { async downloadModRequestHandler(message) { let { name, version } = message.data; let filename = `${name}_${version}.zip`; - let mod = this._master.mods.get(filename); + let mod = this._controller.mods.get(filename); if (!mod) { throw new libErrors.RequestError(`Mod ${filename} does not exist`); } - let modPath = path.join(this._master.config.get("master.mods_directory"), mod.filename); + let modPath = path.join(this._controller.config.get("controller.mods_directory"), mod.filename); - let stream = await routes.createProxyStream(this._master.app); + let stream = await routes.createProxyStream(this._controller.app); stream.filename = mod.filename; stream.source = fs.createReadStream(modPath); stream.mime = "application/zip"; @@ -650,7 +650,7 @@ class ControlConnection extends BaseConnection { } async deleteModRequestHandler(message) { - await this._master.deleteMod(message.data.name, message.data.version); + await this._controller.deleteMod(message.data.name, message.data.version); } async setLogSubscriptionsRequestHandler(message) { @@ -668,29 +668,29 @@ class ControlConnection extends BaseConnection { } updateLogSubscriptions() { - let { all, master, slave_ids, instance_ids } = this.logSubscriptions; - if (all || master || slave_ids.length || instance_ids.length) { + let { all, controller, slave_ids, instance_ids } = this.logSubscriptions; + if (all || controller || slave_ids.length || instance_ids.length) { if (!this.logTransport) { this.logTransport = new libLoggingUtils.LinkTransport({ link: this }); - this._master.clusterLogger.add(this.logTransport); + this._controller.clusterLogger.add(this.logTransport); } this.logTransport.filter = logFilter(this.logSubscriptions); } else if (this.logTransport) { - this._master.clusterLogger.remove(this.logTransport); + this._controller.clusterLogger.remove(this.logTransport); this.logTransport = null; } } async queryLogRequestHandler(message) { let observeDuration = queryLogTime.startTimer(); - let { all, master, slave_ids, instance_ids } = message.data; + let { all, controller, slave_ids, instance_ids } = message.data; let log; - if (!all && master && !slave_ids.length && !instance_ids.length) { - log = await this._master.queryMasterLog(message.data); + if (!all && controller && !slave_ids.length && !instance_ids.length) { + log = await this._controller.queryControllerLog(message.data); } else { - log = await this._master.queryClusterLog(message.data); + log = await this._controller.queryClusterLog(message.data); } observeDuration(); @@ -711,7 +711,7 @@ class ControlConnection extends BaseConnection { async listRolesRequestHandler(message) { let list = []; - for (let role of this._master.userManager.roles.values()) { + for (let role of this._controller.userManager.roles.values()) { list.push({ id: role.id, name: role.name, @@ -723,17 +723,17 @@ class ControlConnection extends BaseConnection { } async createRoleRequestHandler(message) { - let lastId = Math.max.apply(null, [...this._master.userManager.roles.keys()]); + let lastId = Math.max.apply(null, [...this._controller.userManager.roles.keys()]); // Start at 5 to leave space for future default roles let id = Math.max(5, lastId+1); - this._master.userManager.roles.set(id, new libUsers.Role({ id, ...message.data })); + this._controller.userManager.roles.set(id, new libUsers.Role({ id, ...message.data })); return { id }; } async updateRoleRequestHandler(message) { let { id, name, description, permissions } = message.data; - let role = this._master.userManager.roles.get(id); + let role = this._controller.userManager.roles.get(id); if (!role) { throw new libErrors.RequestError(`Role with ID ${id} does not exist`); } @@ -741,36 +741,36 @@ class ControlConnection extends BaseConnection { role.name = name; role.description = description; role.permissions = new Set(permissions); - this._master.rolePermissionsUpdated(role); + this._controller.rolePermissionsUpdated(role); } async grantDefaultRolePermissionsRequestHandler(message) { - let role = this._master.userManager.roles.get(message.data.id); + let role = this._controller.userManager.roles.get(message.data.id); if (!role) { throw new libErrors.RequestError(`Role with ID ${message.data.id} does not exist`); } role.grantDefaultPermissions(); - this._master.rolePermissionsUpdated(role); + this._controller.rolePermissionsUpdated(role); } async deleteRoleRequestHandler(message) { let id = message.data.id; - let role = this._master.userManager.roles.get(id); + let role = this._controller.userManager.roles.get(id); if (!role) { throw new libErrors.RequestError(`Role with ID ${id} does not exist`); } - this._master.userManager.roles.delete(id); - for (let user of this._master.userManager.users.values()) { + this._controller.userManager.roles.delete(id); + for (let user of this._controller.userManager.users.values()) { user.roles.delete(role); - this._master.userPermissionsUpdated(user); + this._controller.userPermissionsUpdated(user); } } async getUserRequestHandler(message) { let name = message.data.name; - let user = this._master.userManager.users.get(name); + let user = this._controller.userManager.users.get(name); if (!user) { throw new libErrors.RequestError(`User ${name} does not exist`); } @@ -790,7 +790,7 @@ class ControlConnection extends BaseConnection { async listUsersRequestHandler(message) { let list = []; - for (let user of this._master.userManager.users.values()) { + for (let user of this._controller.userManager.users.values()) { list.push({ name: user.name, roles: [...user.roles].map(role => role.id), @@ -829,12 +829,12 @@ class ControlConnection extends BaseConnection { } async createUserRequestHandler(message) { - let user = this._master.userManager.createUser(message.data.name); - this._master.userUpdated(user); + let user = this._controller.userManager.createUser(message.data.name); + this._controller.userUpdated(user); } async revokeUserTokenRequestHandler(message) { - let user = this._master.userManager.users.get(message.data.name); + let user = this._controller.userManager.users.get(message.data.name); if (!user) { throw new libErrors.RequestError(`User '${message.data.name}' does not exist`); } @@ -843,23 +843,23 @@ class ControlConnection extends BaseConnection { } user.invalidateToken(); - for (let controlConnection of this._master.wsServer.controlConnections) { + for (let controlConnection of this._controller.wsServer.controlConnections) { if (controlConnection.user.name === user.name) { controlConnection.connector.terminate(); } } - this._master.userUpdated(user); + this._controller.userUpdated(user); } async updateUserRolesRequestHandler(message) { - let user = this._master.userManager.users.get(message.data.name); + let user = this._controller.userManager.users.get(message.data.name); if (!user) { throw new libErrors.RequestError(`User '${message.data.name}' does not exist`); } let resolvedRoles = new Set(); for (let roleId of message.data.roles) { - let role = this._master.userManager.roles.get(roleId); + let role = this._controller.userManager.roles.get(roleId); if (!role) { throw new libErrors.RequestError(`Role with ID ${roleId} does not exist`); } @@ -868,34 +868,34 @@ class ControlConnection extends BaseConnection { } user.roles = resolvedRoles; - this._master.userPermissionsUpdated(user); - this._master.userUpdated(user); + this._controller.userPermissionsUpdated(user); + this._controller.userUpdated(user); } async setUserAdminRequestHandler(message) { let { name, create, admin } = message.data; - let user = this._master.userManager.users.get(name); + let user = this._controller.userManager.users.get(name); if (!user) { if (create) { this.user.checkPermission("core.user.create"); - user = this._master.userManager.createUser(name); + user = this._controller.userManager.createUser(name); } else { throw new libErrors.RequestError(`User '${name}' does not exist`); } } user.isAdmin = admin; - this._master.userUpdated(user); + this._controller.userUpdated(user); this.broadcastEventToSlaves({ data: { name, admin }}, libLink.messages.adminlistUpdate); } async setUserBannedRequestHandler(message) { let { name, create, banned, reason } = message.data; - let user = this._master.userManager.users.get(name); + let user = this._controller.userManager.users.get(name); if (!user) { if (create) { this.user.checkPermission("core.user.create"); - user = this._master.userManager.createUser(name); + user = this._controller.userManager.createUser(name); } else { throw new libErrors.RequestError(`User '${name}' does not exist`); } @@ -903,36 +903,36 @@ class ControlConnection extends BaseConnection { user.isBanned = banned; user.banReason = reason; - this._master.userUpdated(user); + this._controller.userUpdated(user); this.broadcastEventToSlaves({ data: { name, banned, reason }}, libLink.messages.banlistUpdate); } async setUserWhitelistedRequestHandler(message) { let { name, create, whitelisted } = message.data; - let user = this._master.userManager.users.get(name); + let user = this._controller.userManager.users.get(name); if (!user) { if (create) { this.user.checkPermission("core.user.create"); - user = this._master.userManager.createUser(name); + user = this._controller.userManager.createUser(name); } else { throw new libErrors.RequestError(`User '${name}' does not exist`); } } user.isWhitelisted = whitelisted; - this._master.userUpdated(user); + this._controller.userUpdated(user); this.broadcastEventToSlaves({ data: { name, whitelisted }}, libLink.messages.whitelistUpdate); } async deleteUserRequestHandler(message) { - let user = this._master.userManager.users.get(message.data.name); + let user = this._controller.userManager.users.get(message.data.name); if (!user) { throw new libErrors.RequestError(`User '${message.data.name}' does not exist`); } user.isDeleted = true; - this._master.userManager.users.delete(message.data.name); - this._master.userUpdated(user); + this._controller.userManager.users.delete(message.data.name); + this._controller.userUpdated(user); if (user.is_admin) { this.broadcastEventToSlaves({ data: { name, admin: false }}, libLink.messages.adminlistUpdate); @@ -952,7 +952,7 @@ class ControlConnection extends BaseConnection { } }; this.connector._socket.clusterio_ignore_dump = true; - this._master.debugEvents.on("message", this.ws_dumper); + this._controller.debugEvents.on("message", this.ws_dumper); } } diff --git a/packages/master/src/Master.js b/packages/controller/src/Controller.js similarity index 85% rename from packages/master/src/Master.js rename to packages/controller/src/Controller.js index e4605896..2427fe16 100644 --- a/packages/master/src/Master.js +++ b/packages/controller/src/Controller.js @@ -27,21 +27,21 @@ const WsServer = require("./WsServer"); const endpointDurationSummary = new libPrometheus.Summary( - "clusterio_master_http_endpoint_duration_seconds", + "clusterio_controller_http_endpoint_duration_seconds", "Time it took to respond to a an HTTP request", { labels: ["route"] } ); const logSizeGauge = new libPrometheus.Gauge( - "clusterio_master_log_bytes", - "Size of all log files currently stored on the master." + "clusterio_controller_log_bytes", + "Size of all log files currently stored on the controller." ); /** - * Manages all master related operations - * @alias module:master/src/Master + * Manages all controller related operations + * @alias module:controller/src/Controller */ -class Master { +class Controller { constructor(clusterLogger, pluginInfos, configPath, config) { this.clusterLogger = clusterLogger; /** @@ -51,13 +51,13 @@ class Master { this.pluginInfos = pluginInfos; this.configPath = configPath; /** - * Master config. - * @type {module:lib/config.MasterConfig} + * Controller config. + * @type {module:lib/config.ControllerConfig} */ this.config = config; this.app = express(); - this.app.locals.master = this; + this.app.locals.controller = this; this.app.locals.streams = new Map(); /** @@ -86,7 +86,7 @@ class Master { /** * User and roles manager for the cluster - * @type {module:master/src/UserManager} + * @type {module:controller/src/UserManager} */ this.userManager = null; this.httpServer = null; @@ -96,13 +96,13 @@ class Master { /** * Mapping of plugin name to loaded plugin - * @type {Map} + * @type {Map} */ this.plugins = new Map(); /** * WebSocket server - * @type {module:master/src/WsServer} + * @type {module:controller/src/WsServer} */ this.wsServer = new WsServer(this); @@ -144,7 +144,7 @@ class Master { async logSize() { return (await Promise.all([ libFileOps.directorySize(path.join(this.logDirectory, "cluster")), - libFileOps.directorySize(path.join(this.logDirectory, "master")), + libFileOps.directorySize(path.join(this.logDirectory, "controller")), libFileOps.directorySize(path.join(this.logDirectory, "slave")), ])).reduce((a, v) => a + v, 0); } @@ -189,38 +189,38 @@ class Master { this.app.use(this.devMiddleware); } - let databaseDirectory = this.config.get("master.database_directory"); + let databaseDirectory = this.config.get("controller.database_directory"); await fs.ensureDir(databaseDirectory); - this.slaves = await Master.loadSlaves(path.join(databaseDirectory, "slaves.json")); - this.instances = await Master.loadInstances(path.join(databaseDirectory, "instances.json")); - this.modPacks = await Master.loadModPacks(path.join(databaseDirectory, "mod-packs.json")); + this.slaves = await Controller.loadSlaves(path.join(databaseDirectory, "slaves.json")); + this.instances = await Controller.loadInstances(path.join(databaseDirectory, "instances.json")); + this.modPacks = await Controller.loadModPacks(path.join(databaseDirectory, "mod-packs.json")); this.userManager = new UserManager(this.config); await this.userManager.load(path.join(databaseDirectory, "users.json")); - let modsDirectory = this.config.get("master.mods_directory"); + let modsDirectory = this.config.get("controller.mods_directory"); await fs.ensureDir(modsDirectory); - this.mods = await Master.loadModInfos(modsDirectory); + this.mods = await Controller.loadModInfos(modsDirectory); this.config.on("fieldChanged", (group, field, prev) => { - libPlugin.invokeHook(this.plugins, "onMasterConfigFieldChanged", group, field, prev); + libPlugin.invokeHook(this.plugins, "onControllerConfigFieldChanged", group, field, prev); }); for (let instance of this.instances.values()) { this.addInstanceHooks(instance); } // Make sure we're actually going to listen on a port - let httpPort = this.config.get("master.http_port"); - let httpsPort = this.config.get("master.https_port"); - let bindAddress = this.config.get("master.bind_address") || ""; + let httpPort = this.config.get("controller.http_port"); + let httpsPort = this.config.get("controller.https_port"); + let bindAddress = this.config.get("controller.bind_address") || ""; if (!httpPort && !httpsPort) { logger.fatal("Error: at least one of http_port and https_port must be configured"); process.exitCode = 1; return; } - let tls_cert = this.config.get("master.tls_certificate"); - let tls_key = this.config.get("master.tls_private_key"); + let tls_cert = this.config.get("controller.tls_certificate"); + let tls_key = this.config.get("controller.tls_private_key"); if (httpsPort && (!tls_cert || !tls_key)) { throw new libErrors.StartupError( @@ -228,10 +228,10 @@ class Master { ); } - Master.addAppRoutes(this.app, this.pluginInfos); + Controller.addAppRoutes(this.app, this.pluginInfos); if (!args.dev) { - let manifest = await Master.loadJsonObject(path.join(__dirname, "..", "dist", "web", "manifest.json")); + let manifest = await Controller.loadJsonObject(path.join(__dirname, "..", "dist", "web", "manifest.json")); if (!manifest["main.js"]) { logger.error("Missing main.js entry in dist/web/manifest.json"); } @@ -272,12 +272,12 @@ class Master { logger.info(`Listening for HTTPS on port ${this.httpsServer.address().port}`); } - logger.info("Started master"); + logger.info("Started controller"); this._state = "running"; } /** - * Stops the master server. + * Stops the controller. * * Save data and bring down the active connections. This is the reverse * of start and is valid at any point in time. @@ -299,7 +299,7 @@ class Master { async _stopInternal() { // This function should never throw. this._state = "stopping"; - logger.info("Stopping master"); + logger.info("Stopping controller"); clearInterval(this.clusterLogBuildInterval); if (this.clusterLogIndex) { await this.clusterLogIndex.save(); @@ -312,17 +312,17 @@ class Master { await new Promise((resolve, reject) => { this.devMiddleware.close(resolve); }); } - let databaseDirectory = this.config.get("master.database_directory"); + let databaseDirectory = this.config.get("controller.database_directory"); if (this.slaves) { - await Master.saveSlaves(path.join(databaseDirectory, "slaves.json"), this.slaves); + await Controller.saveSlaves(path.join(databaseDirectory, "slaves.json"), this.slaves); } if (this.instances) { - await Master.saveInstances(path.join(databaseDirectory, "instances.json"), this.instances); + await Controller.saveInstances(path.join(databaseDirectory, "instances.json"), this.instances); } if (this.modPacks) { - await Master.saveModPacks(path.join(databaseDirectory, "mod-packs.json"), this.modPacks); + await Controller.saveModPacks(path.join(databaseDirectory, "mod-packs.json"), this.modPacks); } if (this.userManager) { @@ -376,7 +376,7 @@ class Master { try { let serialized = JSON.parse(await fs.readFile(filePath)); for (let serializedConfig of serialized) { - let instanceConfig = new libConfig.InstanceConfig("master"); + let instanceConfig = new libConfig.InstanceConfig("controller"); await instanceConfig.load(serializedConfig); let status = instanceConfig.get("instance.assigned_slave") === null ? "unassigned" : "unknown"; let instance = { config: instanceConfig, status }; @@ -471,7 +471,7 @@ class Master { throw new Error(`Mod ${filename} does not exist`); } - let modsDirectory = this.config.get("master.mods_directory"); + let modsDirectory = this.config.get("controller.mods_directory"); await fs.unlink(path.join(modsDirectory, filename)); this.mods.delete(filename); mod.isDeleted = true; @@ -479,16 +479,16 @@ class Master { } /** - * Query master log + * Query controller log * * @param {module:lib/logging_utils~QueryLogFilter} filter - - * Filter to limit entries with. Note that only the master log can + * Filter to limit entries with. Note that only the controller log can * be queried from this function. * @returns {Promise>} log entries matching the filter */ - async queryMasterLog(filter) { + async queryControllerLog(filter) { return await libLoggingUtils.queryLog( - path.join(this.logDirectory, "master"), filter, + path.join(this.logDirectory, "controller"), filter, ); } @@ -530,11 +530,11 @@ class Master { // Add routes for the web interface for (let route of routes.webRoutes) { - app.get(route, Master.serveWeb(route)); + app.get(route, Controller.serveWeb(route)); } for (let pluginInfo of pluginInfos) { for (let route of pluginInfo.routes || []) { - app.get(route, Master.serveWeb(route)); + app.get(route, Controller.serveWeb(route)); } let pluginPackagePath = require.resolve(path.posix.join(pluginInfo.requirePath, "package.json")); @@ -684,7 +684,7 @@ class Master { for (let pluginInfo of this.pluginInfos) { try { let manifestPath = path.posix.join(pluginInfo.requirePath, "dist", "web", "manifest.json"); - pluginInfo.manifest = await Master.loadJsonObject(require.resolve(manifestPath), true); + pluginInfo.manifest = await Controller.loadJsonObject(require.resolve(manifestPath), true); } catch (err) { logger.warn(`Unable to load dist/web/manifest.json for plugin ${pluginInfo.name}`); } @@ -693,15 +693,15 @@ class Master { continue; } - let MasterPluginClass = libPlugin.BaseMasterPlugin; + let ControllerPluginClass = libPlugin.BaseControllerPlugin; try { - if (pluginInfo.masterEntrypoint) { - MasterPluginClass = await libPluginLoader.loadMasterPluginClass(pluginInfo); + if (pluginInfo.controllerEntrypoint) { + ControllerPluginClass = await libPluginLoader.loadControllerPluginClass(pluginInfo); } - let masterPlugin = new MasterPluginClass(pluginInfo, this, metrics, logger); - await masterPlugin.init(); - this.plugins.set(pluginInfo.name, masterPlugin); + let controllerPlugin = new ControllerPluginClass(pluginInfo, this, metrics, logger); + await controllerPlugin.init(); + this.plugins.set(pluginInfo.name, controllerPlugin); } catch (err) { throw new libErrors.PluginError(pluginInfo.name, err); @@ -743,21 +743,21 @@ class Master { /** - * Returns the URL needed to connect to the master server. + * Returns the URL needed to connect to the controller. * - * @returns {string} master URL. + * @returns {string} controller URL. */ - getMasterUrl() { - return Master.calculateMasterUrl(this.config); + getControllerUrl() { + return Controller.calculateControllerUrl(this.config); } - static calculateMasterUrl(config) { - let url = config.get("master.external_address"); + static calculateControllerUrl(config) { + let url = config.get("controller.external_address"); if (!url) { - if (config.get("master.https_port")) { - url = `https://localhost:${config.get("master.https_port")}/`; + if (config.get("controller.https_port")) { + url = `https://localhost:${config.get("controller.https_port")}/`; } else { - url = `http://localhost:${config.get("master.http_port")}/`; + url = `http://localhost:${config.get("controller.http_port")}/`; } } return url; @@ -789,7 +789,7 @@ class Master { fs.readFile(path.join(__dirname, "..", "web", "index.html"), "utf8").then((content) => { res.type("text/html"); res.send(content - .replace(/__CLUSTER_NAME__/g, res.app.locals.master.config.get("master.name")) + .replace(/__CLUSTER_NAME__/g, res.app.locals.controller.config.get("controller.name")) .replace(/__WEB_ROOT__/g, webRoot) .replace(/__STATIC_ROOT__/g, staticRoot) .replace(/__MAIN_BUNDLE__/g, mainBundle) @@ -832,4 +832,4 @@ class Master { } } -module.exports = Master; +module.exports = Controller; diff --git a/packages/master/src/HttpCloser.js b/packages/controller/src/HttpCloser.js similarity index 98% rename from packages/master/src/HttpCloser.js rename to packages/controller/src/HttpCloser.js index af10e14b..ef31e7d6 100644 --- a/packages/master/src/HttpCloser.js +++ b/packages/controller/src/HttpCloser.js @@ -17,7 +17,7 @@ const https = require("https"); * // in the shutdown logic * await serverCloser.close(); * - * @alias module:master/src/HttpCloser + * @alias module:controller/src/HttpCloser */ class HttpCloser { /** diff --git a/packages/master/src/SlaveConnection.js b/packages/controller/src/SlaveConnection.js similarity index 68% rename from packages/master/src/SlaveConnection.js rename to packages/controller/src/SlaveConnection.js index c011d01f..3b5975be 100644 --- a/packages/master/src/SlaveConnection.js +++ b/packages/controller/src/SlaveConnection.js @@ -11,12 +11,12 @@ const BaseConnection = require("./BaseConnection"); /** * Represents the connection to a slave * - * @extends module:master/src/BaseConnection - * @alias module:master/src/SlaveConnection + * @extends module:controller/src/BaseConnection + * @alias module:controller/src/SlaveConnection */ class SlaveConnection extends BaseConnection { - constructor(registerData, connector, master) { - super("slave", connector, master); + constructor(registerData, connector, controller) { + super("slave", connector, controller); this._agent = registerData.agent; this._id = registerData.id; @@ -25,7 +25,7 @@ class SlaveConnection extends BaseConnection { this.plugins = new Map(Object.entries(registerData.plugins)); this._checkPluginVersions(); - this._master.slaves.set(this._id, { + this._controller.slaves.set(this._id, { agent: this._agent, id: this._id, name: this._name, @@ -37,7 +37,7 @@ class SlaveConnection extends BaseConnection { for (let event of ["connect", "drop", "resume", "close"]) { // eslint-disable-next-line no-loop-func this.connector.on(event, () => { - for (let plugin of this._master.plugins.values()) { + for (let plugin of this._controller.plugins.values()) { plugin.onSlaveConnectionEvent(this, event); } }); @@ -45,32 +45,32 @@ class SlaveConnection extends BaseConnection { this.connector.on("close", () => { // Update status to unknown for instances on this slave. - for (let instance of this._master.instances.values()) { + for (let instance of this._controller.instances.values()) { if (instance.config.get("instance.assigned_slave") !== this._id) { continue; } let prev = instance.status; instance.status = "unknown"; - this._master.instanceUpdated(instance); - libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", instance, prev); + this._controller.instanceUpdated(instance); + libPlugin.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev); } }); } _checkPluginVersions() { - let pluginInfos = new Map(this._master.pluginInfos.map(i => [i.name, i])); + let pluginInfos = new Map(this._controller.pluginInfos.map(i => [i.name, i])); for (let [name, version] of this.plugins) { let info = pluginInfos.get(name); if (!info) { - logger.warn(`Slave ${this._name} has plugin ${name} ${version} which the master does not have`); + logger.warn(`Slave ${this._name} has plugin ${name} ${version} which the controller does not have`); continue; } if (info.version !== version) { logger.warn( `Slave ${this._name} has plugin ${name} ${version} which does not match the version of this ` + - `plugin on the master (${info.version})` + `plugin on the controller (${info.version})` ); } } @@ -92,7 +92,7 @@ class SlaveConnection extends BaseConnection { } async instanceStatusChangedEventHandler(message, event) { - let instance = this._master.instances.get(message.data.instance_id); + let instance = this._controller.instances.get(message.data.instance_id); // It's possible to get updates from an instance that does not exist // or is not assigned to the slave it originated from if it was @@ -116,13 +116,13 @@ class SlaveConnection extends BaseConnection { instance.status = message.data.status; instance.game_port = message.data.game_port; logger.verbose(`Instance ${instance.config.get("instance.name")} State: ${instance.status}`); - this._master.instanceUpdated(instance); - await libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", instance, prev); + this._controller.instanceUpdated(instance); + await libPlugin.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev); } async updateInstancesRequestHandler(message) { // Push updated instance configs - for (let instance of this._master.instances.values()) { + for (let instance of this._controller.instances.values()) { if (instance.config.get("instance.assigned_slave") === this._id) { await libLink.messages.assignInstance.send(this, { instance_id: instance.config.get("instance.id"), @@ -131,41 +131,43 @@ class SlaveConnection extends BaseConnection { } } - // Assign instances the slave has but master does not + // Assign instances the slave has but controller does not for (let instanceData of message.data.instances) { - let instanceConfig = new libConfig.InstanceConfig("master"); + let instanceConfig = new libConfig.InstanceConfig("controller"); await instanceConfig.load(instanceData.serialized_config, "slave"); - let masterInstance = this._master.instances.get(instanceConfig.get("instance.id")); - if (masterInstance) { + let controllerInstance = this._controller.instances.get(instanceConfig.get("instance.id")); + if (controllerInstance) { // Check if this instance is assigned somewhere else. - if (masterInstance.config.get("instance.assigned_slave") !== this._id) { + if (controllerInstance.config.get("instance.assigned_slave") !== this._id) { await libLink.messages.unassignInstance.send(this, { - instance_id: masterInstance.config.get("instance.id"), + instance_id: controllerInstance.config.get("instance.id"), }); continue; } // Already have this instance, update state instead - if (masterInstance.status !== instanceData.status) { - let prev = masterInstance.status; - masterInstance.status = instanceData.status; + if (controllerInstance.status !== instanceData.status) { + let prev = controllerInstance.status; + controllerInstance.status = instanceData.status; logger.verbose(`Instance ${instanceConfig.get("instance.name")} State: ${instanceData.status}`); - this._master.instanceUpdated(instance); - await libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", masterInstance, prev); + this._controller.instanceUpdated(instance); + await libPlugin.invokeHook( + this._controller.plugins, "onInstanceStatusChanged", controllerInstance, prev + ); } continue; } instanceConfig.set("instance.assigned_slave", this._id); let newInstance = { config: instanceConfig, status: instanceData.status }; - this._master.instances.set(instanceConfig.get("instance.id"), newInstance); - this._master.addInstanceHooks(newInstance); + this._controller.instances.set(instanceConfig.get("instance.id"), newInstance); + this._controller.addInstanceHooks(newInstance); await libLink.messages.assignInstance.send(this, { instance_id: instanceConfig.get("instance.id"), serialized_config: instanceConfig.serialize("slave"), }); - await libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", newInstance, null); + await libPlugin.invokeHook(this._controller.plugins, "onInstanceStatusChanged", newInstance, null); } // Push lists to make sure they are in sync. @@ -173,7 +175,7 @@ class SlaveConnection extends BaseConnection { let banlist = []; let whitelist = []; - for (let user of this._master.userManager.users.values()) { + for (let user of this._controller.userManager.users.values()) { if (user.isAdmin) { adminlist.push(user.name); } @@ -189,11 +191,11 @@ class SlaveConnection extends BaseConnection { } async saveListUpdateEventHandler(message) { - this._master.saveListUpdate(message.data); + this._controller.saveListUpdate(message.data); } async logMessageEventHandler(message) { - this._master.clusterLogger.log({ + this._controller.clusterLogger.log({ ...message.data.info, slave_id: this._id, slave_name: this._name, @@ -202,9 +204,9 @@ class SlaveConnection extends BaseConnection { async playerEventEventHandler(message) { let { instance_id, name, type, stats } = message.data; - let user = this._master.userManager.users.get(name); + let user = this._controller.userManager.users.get(name); if (!user) { - user = this._master.userManager.createUser(name); + user = this._controller.userManager.createUser(name); } if (type === "join") { @@ -214,11 +216,11 @@ class SlaveConnection extends BaseConnection { } user.instanceStats.set(instance_id, new PlayerStats(stats)); user.recalculatePlayerStats(); - this._master.userUpdated(user); + this._controller.userUpdated(user); delete message.data.stats; - let instance = this._master.instances.get(instance_id); - await libPlugin.invokeHook(this._master.plugins, "onPlayerEvent", instance, message.data); + let instance = this._controller.instances.get(instance_id); + await libPlugin.invokeHook(this._controller.plugins, "onPlayerEvent", instance, message.data); } } diff --git a/packages/master/src/UserManager.js b/packages/controller/src/UserManager.js similarity index 94% rename from packages/master/src/UserManager.js rename to packages/controller/src/UserManager.js index 3c00a85e..883d1a4d 100644 --- a/packages/master/src/UserManager.js +++ b/packages/controller/src/UserManager.js @@ -6,7 +6,7 @@ const libUsers = require("@clusterio/lib/users"); /** * Manages users and roles - * @alias module:master/src/UserManager + * @alias module:controller/src/UserManager */ class UserManager { constructor(config) { @@ -79,7 +79,7 @@ class UserManager { throw new Error(`User '${name}' already exists`); } - let defaultRoleId = this._config.get("master.default_role_id"); + let defaultRoleId = this._config.get("controller.default_role_id"); let user = new libUsers.User({ name, roles: [defaultRoleId] }, this.roles); this.users.set(name, user); return user; diff --git a/packages/master/src/WsServer.js b/packages/controller/src/WsServer.js similarity index 81% rename from packages/master/src/WsServer.js rename to packages/controller/src/WsServer.js index 2523873c..a85ff49e 100644 --- a/packages/master/src/WsServer.js +++ b/packages/controller/src/WsServer.js @@ -14,36 +14,36 @@ const WsServerConnector = require("./WsServerConnector"); const wsMessageCounter = new libPrometheus.Counter( - "clusterio_master_websocket_message_total", - "How many messages have been received over WebSocket on the master server", + "clusterio_controller_websocket_message_total", + "How many messages have been received over WebSocket on the controller", { labels: ["direction"] } ); const wsConnectionsCounter = new libPrometheus.Counter( - "clusterio_master_websocket_connections_total", - "How many WebSocket connections have been initiated on the master server" + "clusterio_controller_websocket_connections_total", + "How many WebSocket connections have been initiated on the controller" ); const wsRejectedConnectionsCounter = new libPrometheus.Counter( - "clusterio_master_websocket_rejected_connections_total", - "How many WebSocket connections have been rejected during the handshake on the master server" + "clusterio_controller_websocket_rejected_connections_total", + "How many WebSocket connections have been rejected during the handshake on the controller" ); /** * WebSocket server - * @alias module:master/src/WsServer + * @alias module:controller/src/WsServer */ class WsServer { - constructor(master) { - this.master = master; + constructor(controller) { + this.controller = controller; this.stopAcceptingNewSessions = false; - /** @type {Array} */ + /** @type {Array} */ this.controlConnections = []; - /** @type {Map} */ + /** @type {Map} */ this.slaveConnections = new Map(); - /** @type {Map} */ + /** @type {Map} */ this.activeConnectors = new Map(); /** @type {Set} */ this.pendingSockets = new Set(); @@ -104,21 +104,21 @@ class WsServer { socket.on("message", (message) => { wsMessageCounter.labels("in").inc(); if (!socket.clusterio_ignore_dump) { - this.master.debugEvents.emit("message", { direction: "in", content: message }); + this.controller.debugEvents.emit("message", { direction: "in", content: message }); } }); let originalSend = socket.send; socket.send = (...args) => { wsMessageCounter.labels("out").inc(); if (typeof args[0] === "string" && !socket.clusterio_ignore_dump) { - this.master.debugEvents.emit("message", { direction: "out", content: args[0] }); + this.controller.debugEvents.emit("message", { direction: "out", content: args[0] }); } return originalSend.call(socket, ...args); }; // Start connection handshake. let loadedPlugins = {}; - for (let [name, plugin] of this.master.plugins) { + for (let [name, plugin] of this.controller.plugins) { loadedPlugins[name] = plugin.info.version; } @@ -183,7 +183,7 @@ ${err.stack}` try { let payload = jwt.verify( data.session_token, - Buffer.from(this.master.config.get("master.auth_secret"), "base64"), + Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), { audience: this.sessionAud } ); @@ -215,7 +215,7 @@ ${err.stack}` if (type === "register_slave") { let tokenPayload = jwt.verify( data.token, - Buffer.from(this.master.config.get("master.auth_secret"), "base64"), + Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), { audience: "slave" } ); @@ -226,11 +226,11 @@ ${err.stack}` } else if (type === "register_control") { let tokenPayload = jwt.verify( data.token, - Buffer.from(this.master.config.get("master.auth_secret"), "base64"), + Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), { audience: "user" } ); - user = this.master.userManager.users.get(tokenPayload.user); + user = this.controller.userManager.users.get(tokenPayload.user); if (!user) { throw new Error("invalid user"); } @@ -251,10 +251,10 @@ ${err.stack}` this.nextSessionId += 1; let sessionToken = jwt.sign( { aud: this.sessionAud, sid: sessionId }, - Buffer.from(this.master.config.get("master.auth_secret"), "base64"), + Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), ); - let sessionTimeout = this.master.config.get("master.session_timeout"); - let heartbeatInterval = this.master.config.get("master.heartbeat_interval"); + let sessionTimeout = this.controller.config.get("controller.session_timeout"); + let heartbeatInterval = this.controller.config.get("controller.heartbeat_interval"); let connector = new WsServerConnector(sessionId, sessionTimeout, heartbeatInterval); this.activeConnectors.set(sessionId, connector); connector.on("close", () => { @@ -274,27 +274,27 @@ ${err.stack}` ); if (data.agent === "Clusterio Slave" && data.version !== packageVersion) { logger.warn( - `Slave ${data.name} (${data.id}) connected using version ${data.version} which does not match ` + - `the version of the master is currently running (${packageVersion}). It may not work as expected.` + `Host ${data.name} (${data.id}) connected using version ${data.version} which does not match the ` + + `version of the controller is currently running (${packageVersion}). It may not work as expected.` ); } - connection = new SlaveConnection(data, connector, this.master); + connection = new SlaveConnection(data, connector, this.controller); connector.on("close", () => { if (this.slaveConnections.get(data.id) === connection) { this.slaveConnections.delete(data.id); - this.master.slaveUpdated(this.master.slaves.get(data.id)); + this.controller.slaveUpdated(this.controller.slaves.get(data.id)); } else { logger.warn("Unlisted SlaveConnection closed"); } }); this.slaveConnections.set(data.id, connection); - this.master.slaveUpdated(this.master.slaves.get(data.id)); + this.controller.slaveUpdated(this.controller.slaves.get(data.id)); } else if (type === "register_control") { logger.verbose(`WsServer | registered control from ${req.socket.remoteAddress}`); - let connection = new ControlConnection(data, connector, this.master, user); + let connection = new ControlConnection(data, connector, this.controller, user); connector.on("close", () => { let index = this.controlConnections.indexOf(connection); if (index !== -1) { diff --git a/packages/master/src/WsServerConnector.js b/packages/controller/src/WsServerConnector.js similarity index 98% rename from packages/master/src/WsServerConnector.js rename to packages/controller/src/WsServerConnector.js index 84311284..004ef841 100644 --- a/packages/master/src/WsServerConnector.js +++ b/packages/controller/src/WsServerConnector.js @@ -6,10 +6,10 @@ const { logger } = require("@clusterio/lib/logging"); /** - * Connector for master server connections + * Connector for controller connections * * @extends module:lib/link.WebSocketBaseConnector - * @alias module:master/src/WsServerConnector + * @alias module:controller/src/WsServerConnector */ class WsServerConnector extends libLink.WebSocketBaseConnector { constructor(sessionId, sessionTimeout, heartbeatInterval) { diff --git a/packages/master/src/metrics.js b/packages/controller/src/metrics.js similarity index 89% rename from packages/master/src/metrics.js rename to packages/controller/src/metrics.js index ad400eed..0706ec33 100644 --- a/packages/master/src/metrics.js +++ b/packages/controller/src/metrics.js @@ -4,7 +4,7 @@ const libPrometheus = require("@clusterio/lib/prometheus"); const util = require("util"); exports.endpointHitCounter = new libPrometheus.Counter( - "clusterio_master_http_endpoint_hits_total", + "clusterio_controller_http_endpoint_hits_total", "How many requests a particular HTTP endpoint has gotten", { labels: ["route"], register: false } ); diff --git a/packages/master/src/routes.js b/packages/controller/src/routes.js similarity index 92% rename from packages/master/src/routes.js rename to packages/controller/src/routes.js index e9af7ff3..2322558c 100644 --- a/packages/master/src/routes.js +++ b/packages/controller/src/routes.js @@ -40,7 +40,7 @@ function mergeSamples(destinationResult, sourceResult) { // Prometheus polling endpoint async function getMetrics(req, res, next) { let results = []; - let pluginResults = await libPlugin.invokeHook(req.app.locals.master.plugins, "onMetrics"); + let pluginResults = await libPlugin.invokeHook(req.app.locals.controller.plugins, "onMetrics"); for (let metricIterator of pluginResults) { for await (let metric of metricIterator) { results.push(metric); @@ -48,8 +48,8 @@ async function getMetrics(req, res, next) { } let requests = []; - let timeout = req.app.locals.master.config.get("master.metrics_timeout") * 1000; - for (let slaveConnection of req.app.locals.master.wsServer.slaveConnections.values()) { + let timeout = req.app.locals.controller.config.get("controller.metrics_timeout") * 1000; + for (let slaveConnection of req.app.locals.controller.wsServer.slaveConnections.values()) { if (!slaveConnection.connected) { continue; } @@ -98,10 +98,10 @@ async function getMetrics(req, res, next) { function getPlugins(req, res) { let plugins = []; - for (let pluginInfo of req.app.locals.master.pluginInfos) { + for (let pluginInfo of req.app.locals.controller.pluginInfos) { let name = pluginInfo.name; - let loaded = req.app.locals.master.plugins.has(name); - let enabled = loaded && req.app.locals.master.config.group(pluginInfo.name).get("load_plugin"); + let loaded = req.app.locals.controller.plugins.has(name); + let enabled = loaded && req.app.locals.controller.config.group(pluginInfo.name).get("load_plugin"); let web = {}; let devPlugins = req.app.locals.devPlugins; if (devPlugins && devPlugins.has(name)) { @@ -133,7 +133,7 @@ function validateSlaveToken(req, res, next) { try { jwt.verify( token, - Buffer.from(req.app.locals.master.config.get("master.auth_secret"), "base64"), + Buffer.from(req.app.locals.controller.config.get("controller.auth_secret"), "base64"), { audience: "slave" } ); @@ -155,10 +155,10 @@ function validateUserToken(req, res, next) { try { let tokenPayload = jwt.verify( token, - Buffer.from(req.app.locals.master.config.get("master.auth_secret"), "base64"), + Buffer.from(req.app.locals.controller.config.get("controller.auth_secret"), "base64"), { audience: "user" } ); - let user = req.app.locals.master.userManager.users.get(tokenPayload.user); + let user = req.app.locals.controller.userManager.users.get(tokenPayload.user); if (!user) { throw new Error("invalid user"); } @@ -191,7 +191,7 @@ async function uploadExport(req, res) { res.sendStatus(400); return; } - let modPack = res.app.locals.master.modPacks.get(modPackId); + let modPack = res.app.locals.controller.modPacks.get(modPackId); if (!modPack) { res.sendStatus(400); return; @@ -234,7 +234,7 @@ async function uploadExport(req, res) { modPack.exportManifest = new libData.ExportManifest({ assets }); modPack.fillDefaultSettings(settingPrototypes, logger); - res.app.locals.master.modPackUpdated(modPack); + res.app.locals.controller.modPackUpdated(modPack); res.sendStatus(200); } @@ -251,7 +251,7 @@ async function createProxyStream(app) { events: new events.EventEmitter(), timeout: setTimeout(() => { stream.events.emit("timeout"); - }, app.locals.master.config.get("master.proxy_stream_timeout") * 1000), + }, app.locals.controller.config.get("controller.proxy_stream_timeout") * 1000), }; stream.events.on("close", () => { clearTimeout(stream.timeout); @@ -362,7 +362,7 @@ async function uploadSave(req, res) { try { let result = await Promise.race([ - req.app.locals.master.forwardRequestToInstance(libLink.messages.pullSave, { + req.app.locals.controller.forwardRequestToInstance(libLink.messages.pullSave, { instance_id: instanceId, stream_id: proxyStream.id, filename, @@ -498,7 +498,7 @@ async function uploadMod(req, res) { return; } - const modsDirectory = req.app.locals.master.config.get("master.mods_directory"); + const modsDirectory = req.app.locals.controller.config.get("controller.mods_directory"); let tempFilename = filename.replace(/(\.zip)?$/, ".tmp.zip"); try { @@ -521,8 +521,8 @@ async function uploadMod(req, res) { const modInfo = await libData.ModInfo.fromModFile(path.join(modsDirectory, tempFilename)); await fs.rename(path.join(modsDirectory, tempFilename), path.join(modsDirectory, modInfo.filename)); - req.app.locals.master.mods.set(modInfo.filename, modInfo); - req.app.locals.master.modUpdated(modInfo); + req.app.locals.controller.mods.set(modInfo.filename, modInfo); + req.app.locals.controller.modUpdated(modInfo); mods.push(modInfo.toJSON()); } catch (err) { @@ -624,10 +624,10 @@ function addRouteHandlers(app) { ); } -// Routes used in the web interface and served by the master server +// Routes used in the web interface and served by the controller const webRoutes = [ "/", - "/master", + "/controller", "/slaves", "/slaves/:id/view", "/instances", diff --git a/packages/master/web/index.html b/packages/controller/web/index.html similarity index 100% rename from packages/master/web/index.html rename to packages/controller/web/index.html diff --git a/packages/master/web/index.jsx b/packages/controller/web/index.jsx similarity index 100% rename from packages/master/web/index.jsx rename to packages/controller/web/index.jsx diff --git a/packages/master/web/pictures/clusterio_icon.png b/packages/controller/web/pictures/clusterio_icon.png similarity index 100% rename from packages/master/web/pictures/clusterio_icon.png rename to packages/controller/web/pictures/clusterio_icon.png diff --git a/packages/master/webpack.config.js b/packages/controller/webpack.config.js similarity index 97% rename from packages/master/webpack.config.js rename to packages/controller/webpack.config.js index e7e9a9fa..cd0155c4 100644 --- a/packages/master/webpack.config.js +++ b/packages/controller/webpack.config.js @@ -16,7 +16,7 @@ module.exports = (env = {}) => merge(common(env), { }, plugins: [ new webpack.container.ModuleFederationPlugin({ - name: "master", + name: "controller", shared: { "@clusterio/lib": { singleton: true }, "@clusterio/web_ui": { singleton: true }, diff --git a/packages/create/create.js b/packages/create/create.js index 42f6d83c..2736cb40 100755 --- a/packages/create/create.js +++ b/packages/create/create.js @@ -110,11 +110,11 @@ async function execFile(cmd, args) { }); } -async function execMaster(args) { +async function execController(args) { if (dev) { - return await execFile("node", [path.join("packages", "master"), ...args]); + return await execFile("node", [path.join("packages", "controller"), ...args]); } - return await execFile(path.join("node_modules", ".bin", `clusteriomaster${scriptExt}`), args); + return await execFile(path.join("node_modules", ".bin", `clusteriocontroller${scriptExt}`), args); } async function execSlave(args) { @@ -194,8 +194,8 @@ async function installClusterio(mode, plugins) { } let components = []; - if (["standalone", "master"].includes(mode)) { - components.push("@clusterio/master"); + if (["standalone", "controller"].includes(mode)) { + components.push("@clusterio/controller"); } if (["standalone", "slave"].includes(mode)) { components.push("@clusterio/slave"); @@ -250,22 +250,22 @@ async function groupIdToName(gid) { } async function writeScripts(mode) { - if (["standalone", "master"].includes(mode)) { + if (["standalone", "controller"].includes(mode)) { if (process.platform === "win32") { await safeOutputFile( - "run-master.cmd", - "@echo off\n.\\node_modules\\.bin\\clusteriomaster.cmd run\n" + "run-controller.cmd", + "@echo off\n.\\node_modules\\.bin\\clusteriocontroller.cmd run\n" ); } else { await safeOutputFile( - "run-master.sh", - "#!/bin/sh\nexec ./node_modules/.bin/clusteriomaster run\n", + "run-controller.sh", + "#!/bin/sh\nexec ./node_modules/.bin/clusteriocontroller run\n", { mode: 0o755 }, ); await safeOutputFile( - "systemd/clusteriomaster.service", + "systemd/clusteriocontroller.service", `[Unit] -Description=Clusterio Master +Description=Clusterio Controller [Service] User=${os.userInfo().username} @@ -273,7 +273,7 @@ Group=${await groupIdToName(os.userInfo().gid)} WorkingDirectory=${process.cwd()} KillMode=mixed KillSignal=SIGINT -ExecStart=${process.cwd()}/node_modules/.bin/clusteriomaster run --log-level=warn +ExecStart=${process.cwd()}/node_modules/.bin/clusteriocontroller run --log-level=warn [Install] WantedBy=multi-user.target @@ -324,8 +324,8 @@ async function inquirerMissingArgs(args) { message: "Operating mode to install", default: "standalone", choices: [ - { name: "Standalone (install both master and slave on this computer)", value: "standalone" }, - { name: "Master only", value: "master" }, + { name: "Standalone (install both controller and slave on this computer)", value: "standalone" }, + { name: "Controller only", value: "controller" }, { name: "Slave only", value: "slave" }, { name: "Ctl only", value: "ctl" }, { name: "Plugins only", value: "plugins" }, @@ -333,7 +333,7 @@ async function inquirerMissingArgs(args) { }, ], answers); - if (["standalone", "master"].includes(answers.mode)) { + if (["standalone", "controller"].includes(answers.mode)) { if (args.admin) { answers.admin = args.admin; } answers = await inquirer.prompt([ { @@ -362,27 +362,27 @@ async function inquirerMissingArgs(args) { } if (["slave", "ctl"].includes(answers.mode)) { - if (args.masterUrl) { answers.masterUrl = args.masterUrl; } + if (args.controllerUrl) { answers.controllerUrl = args.controllerUrl; } answers = await inquirer.prompt([ { type: "input", - name: "masterUrl", - message: "Master server URL", + name: "controllerUrl", + message: "Controller URL", }, ], answers); - if (args.masterToken) { answers.masterToken = args.masterToken; } + if (args.controllerToken) { answers.controllerToken = args.controllerToken; } answers = await inquirer.prompt([ { type: "input", - name: "masterToken", - message: "Master authentication Token", + name: "controllerToken", + message: "Controller authentication Token", }, ], answers); } if (answers.mode === "slave") { - validateSlaveToken(answers.masterToken); + validateSlaveToken(answers.controllerToken); } if (["standalone", "slave"].includes(answers.mode)) { @@ -532,19 +532,19 @@ async function main() { }) .option("mode", { nargs: 1, describe: "Operating mode to install", - choices: ["standalone", "master", "slave", "ctl", "plugins"], + choices: ["standalone", "controller", "slave", "ctl", "plugins"], }) .option("admin", { - nargs: 1, describe: "Admin account name [standalone/master]", type: "string", + nargs: 1, describe: "Admin account name [standalone/controller]", type: "string", }) .option("slave-name", { nargs: 1, describe: "Slave name [slave]", type: "string", }) - .option("master-url", { - nargs: 1, describe: "Master URL [slave/ctl]", type: "string", + .option("controller-url", { + nargs: 1, describe: "Controller URL [slave/ctl]", type: "string", }) - .option("master-token", { - nargs: 1, describe: "Master authentication token [slave/ctl]", type: "string", + .option("controller-token", { + nargs: 1, describe: "Controller authentication token [slave/ctl]", type: "string", }) .option("public-address", { nargs: 1, describe: "DNS/IP Address to connect to this server [standalone/slave]", type: "string", @@ -594,10 +594,10 @@ async function main() { } let adminToken = null; - if (["standalone", "master"].includes(answers.mode)) { - logger.info("Setting up master"); - await execMaster(["bootstrap", "create-admin", answers.admin]); - let result = await execMaster(["bootstrap", "generate-user-token", answers.admin]); + if (["standalone", "controller"].includes(answers.mode)) { + logger.info("Setting up controller"); + await execController(["bootstrap", "create-admin", answers.admin]); + let result = await execController(["bootstrap", "generate-user-token", answers.admin]); adminToken = result.stdout.split("\n").slice(-2)[0]; } @@ -608,33 +608,33 @@ async function main() { let result = await execSlave(["config", "show", "slave.id"]); let slaveId = Number.parseInt(result.stdout.split("\n").slice(-2)[0], 10); - result = await execMaster(["bootstrap", "generate-slave-token", slaveId]); + result = await execController(["bootstrap", "generate-slave-token", slaveId]); let slaveToken = result.stdout.split("\n").slice(-2)[0]; - await execSlave(["config", "set", "slave.master_token", slaveToken]); + await execSlave(["config", "set", "slave.controller_token", slaveToken]); await execSlave(["config", "set", "slave.public_address", answers.publicAddress]); await execSlave(["config", "set", "slave.factorio_directory", answers.factorioDir]); } if (answers.mode === "slave") { logger.info("Setting up slave"); - let slaveId = JSON.parse(Buffer.from(answers.masterToken.split(".")[1], "base64")).slave; + let slaveId = JSON.parse(Buffer.from(answers.controllerToken.split(".")[1], "base64")).slave; await execSlave(["config", "set", "slave.id", slaveId]); await execSlave(["config", "set", "slave.name", answers.slaveName]); - await execSlave(["config", "set", "slave.master_url", answers.masterUrl]); - await execSlave(["config", "set", "slave.master_token", answers.masterToken]); + await execSlave(["config", "set", "slave.controller_url", answers.controllerUrl]); + await execSlave(["config", "set", "slave.controller_token", answers.controllerToken]); await execSlave(["config", "set", "slave.public_address", answers.publicAddress]); await execSlave(["config", "set", "slave.factorio_directory", answers.factorioDir]); } - if (!dev && ["standalone", "master", "slave"].includes(answers.mode)) { + if (!dev && ["standalone", "controller", "slave"].includes(answers.mode)) { logger.info("Writing run scripts"); await writeScripts(answers.mode); } if (answers.mode === "ctl") { - await execCtl(["control-config", "set", "control.master_url", answers.masterUrl]); - await execCtl(["control-config", "set", "control.master_token", answers.masterToken]); + await execCtl(["control-config", "set", "control.controller_url", answers.controllerUrl]); + await execCtl(["control-config", "set", "control.controller_token", answers.controllerToken]); } /* eslint-disable no-console */ diff --git a/packages/ctl/README.md b/packages/ctl/README.md index b1b4860f..8daeb6c9 100644 --- a/packages/ctl/README.md +++ b/packages/ctl/README.md @@ -37,7 +37,7 @@ For example, installing the Subspace Storage plugin: npm install @clusterio/plugin-subspace_storage npx clusterioctl plugin add @clusterio/plugin-subspace_storage -Since the `plugin-list.json` is shared between master, slave and ctl you usually only need to do this once per machine. +Since the `plugin-list.json` is shared between controller, slave and ctl you usually only need to do this once per machine. #### `plugin remove ` @@ -51,7 +51,7 @@ For example, uninstalling the Subspace Storage plugin: npx clusterioctl plugin remove subspace_storage npm uninstall @clusterio/plugin-subspace_storage -Since the `plugin-list.json` is shared between master, slave and ctl you usually only need to do this once per machine. +Since the `plugin-list.json` is shared between controller, slave and ctl you usually only need to do this once per machine. #### `plugin list` @@ -62,7 +62,7 @@ Lists the plugins set up to be available by name followed by path. ### `config-control` Manage the ctl configuration. -This allows setting the url and token to the master server to manage. +This allows setting the url and token to the controller to manage. #### `config-control set [value]` diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 62ffd2bd..8000e783 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -24,7 +24,7 @@ const commands = require("./src/commands"); /** - * Connector for control connection to master server + * Connector for control connection to controller * @private */ class ControlConnector extends libLink.WebSocketClientConnector { @@ -46,22 +46,22 @@ class ControlConnector extends libLink.WebSocketClientConnector { /** * Handles running the control * - * Connects to the master server over WebSocket and sends commands to it. + * Connects to the controller over WebSocket and sends commands to it. * @static */ class Control extends libLink.Link { constructor(connector, controlConfig, tlsCa, controlPlugins) { - super("control", "master", connector); + super("control", "controller", connector); libLink.attachAllMessages(this); /** - * Control config used for connecting to the master. + * Control config used for connecting to the controller. * @type {module:lib/config.ControlConfig} */ this.config = controlConfig; /** - * Certificate authority used to validate TLS connections to the master. + * Certificate authority used to validate TLS connections to the controller. * @type {?string} */ this.tlsCa = tlsCa; @@ -97,13 +97,13 @@ class Control extends libLink.Link { async setLogSubscriptions({ all = false, - master = false, + controller = false, slave_ids = [], instance_ids = [], max_level = null, }) { await libLink.messages.setLogSubscriptions.send(this, { - all, master, slave_ids, instance_ids, max_level, + all, controller, slave_ids, instance_ids, max_level, }); } @@ -251,8 +251,8 @@ async function startControl() { targetCommand = targetCommand.get(commandPath.shift()); } - // The remaining commands require connecting to the master server. - if (!controlConfig.get("control.master_url") || !controlConfig.get("control.master_token")) { + // The remaining commands require connecting to the controller. + if (!controlConfig.get("control.controller_url") || !controlConfig.get("control.controller_token")) { logger.error("Missing URL and/or token to connect with. See README.md for setting up access."); process.exitCode = 1; return; @@ -265,10 +265,10 @@ async function startControl() { } let controlConnector = new ControlConnector( - controlConfig.get("control.master_url"), + controlConfig.get("control.controller_url"), controlConfig.get("control.max_reconnect_delay"), tlsCa, - controlConfig.get("control.master_token") + controlConfig.get("control.controller_token") ); let control = new Control(controlConnector, controlConfig, tlsCa, controlPlugins); try { diff --git a/packages/ctl/src/commands.js b/packages/ctl/src/commands.js index 9e0cc35d..07fc8255 100644 --- a/packages/ctl/src/commands.js +++ b/packages/ctl/src/commands.js @@ -84,14 +84,14 @@ async function serializedConfigToString(serializedConfig, configGroup, disallowe return allConfigElements; } -const masterCommands = new libCommand.CommandTree({ name: "master", description: "Master management" }); -const masterConfigCommands = new libCommand.CommandTree({ - name: "config", alias: ["c"], description: "master config management", +const controllerCommands = new libCommand.CommandTree({ name: "controller", description: "Controller management" }); +const controllerConfigCommands = new libCommand.CommandTree({ + name: "config", alias: ["c"], description: "controller config management", }); -masterConfigCommands.add(new libCommand.Command({ - definition: ["list", "List master configuration"], +controllerConfigCommands.add(new libCommand.Command({ + definition: ["list", "List controller configuration"], handler: async function(args, control) { - let response = await libLink.messages.getMasterConfig.send(control); + let response = await libLink.messages.getControllerConfig.send(control); for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { @@ -101,8 +101,8 @@ masterConfigCommands.add(new libCommand.Command({ }, })); -masterConfigCommands.add(new libCommand.Command({ - definition: ["set [value]", "Set field in master config", (yargs) => { +controllerConfigCommands.add(new libCommand.Command({ + definition: ["set [value]", "Set field in controller config", (yargs) => { yargs.positional("field", { describe: "Field to set", type: "string" }); yargs.positional("value", { describe: "Value to set", type: "string" }); yargs.options({ @@ -115,15 +115,15 @@ masterConfigCommands.add(new libCommand.Command({ } else if (args.value === undefined) { args.value = ""; } - await libLink.messages.setMasterConfigField.send(control, { + await libLink.messages.setControllerConfigField.send(control, { field: args.field, value: args.value, }); }, })); -masterConfigCommands.add(new libCommand.Command({ - definition: ["set-prop [value]", "Set property of field in master config", (yargs) => { +controllerConfigCommands.add(new libCommand.Command({ + definition: ["set-prop [value]", "Set property of field in controller config", (yargs) => { yargs.positional("field", { describe: "Field to set", type: "string" }); yargs.positional("prop", { describe: "Property to set", type: "string" }); yargs.positional("value", { describe: "JSON parsed value to set", type: "string" }); @@ -150,11 +150,11 @@ masterConfigCommands.add(new libCommand.Command({ } request.value = args.value; } - await libLink.messages.setMasterConfigProp.send(control, request); + await libLink.messages.setControllerConfigProp.send(control, request); }, })); -masterConfigCommands.add(new libCommand.Command({ - definition: ["edit [editor]", "Edit master configuration", (yargs) => { +controllerConfigCommands.add(new libCommand.Command({ + definition: ["edit [editor]", "Edit controller configuration", (yargs) => { yargs.positional("editor", { describe: "Editor to use", type: "string", @@ -162,14 +162,16 @@ masterConfigCommands.add(new libCommand.Command({ }); }], handler: async function(args, control) { - let response = await libLink.messages.getMasterConfig.send(control); + let response = await libLink.messages.getControllerConfig.send(control); let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = await getEditor(args.editor); if (editor === -1) { throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars - Try "ctl master config edit "`); + Try "ctl controller config edit "`); } - let allConfigElements = await serializedConfigToString(response.serialized_config, libConfig.MasterConfig, {}); + let allConfigElements = await serializedConfigToString( + response.serialized_config, libConfig.ControllerConfig, {} + ); await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; @@ -189,7 +191,7 @@ masterConfigCommands.add(new libCommand.Command({ for (let index in final) { if (index in final) { try { - await libLink.messages.setMasterConfigField.send(control, { + await libLink.messages.setControllerConfigField.send(control, { field: index, value: final[index], }); @@ -213,16 +215,16 @@ masterConfigCommands.add(new libCommand.Command({ }, })); -masterCommands.add(masterConfigCommands); +controllerCommands.add(controllerConfigCommands); -const masterPluginCommands = new libCommand.CommandTree({ - name: "plugin", alias: ["p"], description: "master plugin inspection", +const controllerPluginCommands = new libCommand.CommandTree({ + name: "plugin", alias: ["p"], description: "controller plugin inspection", }); -masterPluginCommands.add(new libCommand.Command({ - definition: ["list", "List plugins on master"], +controllerPluginCommands.add(new libCommand.Command({ + definition: ["list", "List plugins on controller"], handler: async function(args, control) { - let url = new URL(control.config.get("control.master_url")); + let url = new URL(control.config.get("control.controller_url")); url.pathname += "api/plugins"; let response = await phin({ url, @@ -232,12 +234,12 @@ masterPluginCommands.add(new libCommand.Command({ print(asTable(response.body)); }, })); -masterCommands.add(masterPluginCommands); +controllerCommands.add(controllerPluginCommands); const slaveCommands = new libCommand.CommandTree({ name: "slave", description: "Slave management" }); slaveCommands.add(new libCommand.Command({ - definition: [["list", "l"], "List slaves connected to the master"], + definition: [["list", "l"], "List slaves connected to the controller"], handler: async function(args, control) { let response = await libLink.messages.listSlaves.send(control); print(asTable(response.list)); @@ -293,7 +295,7 @@ const instanceCommands = new libCommand.CommandTree({ name: "instance", alias: ["i"], description: "Instance management", }); instanceCommands.add(new libCommand.Command({ - definition: [["list", "l"], "List instances known to the master"], + definition: [["list", "l"], "List instances known to the controller"], handler: async function(args, control) { let response = await libLink.messages.listInstances.send(control); print(asTable(response.list)); @@ -315,7 +317,7 @@ instanceCommands.add(new libCommand.Command({ instanceConfig.set("instance.id", args.id); } instanceConfig.set("instance.name", args.name); - let serialized_config = instanceConfig.serialize("master"); + let serialized_config = instanceConfig.serialize("controller"); await libLink.messages.createInstance.send(control, { serialized_config }); }, })); @@ -426,7 +428,7 @@ instanceConfigCommands.add(new libCommand.Command({ let editor = await getEditor(args.editor); if (editor === -1) { throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars - Try "ctl master config edit "`); + Try "ctl controller config edit "`); } let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; let allConfigElements = await serializedConfigToString( @@ -614,7 +616,7 @@ instanceSaveCommands.add(new libCommand.Command({ let content = await fs.readFile(args.filepath); let instanceId = await libCommand.resolveInstance(control, args.instance); - let url = new URL(control.config.get("control.master_url")); + let url = new URL(control.config.get("control.controller_url")); url.pathname += "api/upload-save"; url.searchParams.append("instance_id", instanceId); url.searchParams.append("filename", filename); @@ -622,7 +624,7 @@ instanceSaveCommands.add(new libCommand.Command({ let result = await phin({ url, method: "POST", headers: { - "X-Access-Token": control.config.get("control.master_token"), + "X-Access-Token": control.config.get("control.controller_token"), "Content-Type": "application/zip", }, core: { ca: control.tlsCa }, @@ -688,7 +690,7 @@ instanceSaveCommands.add(new libCommand.Command({ save: args.save, }); - let url = new URL(control.config.get("control.master_url")); + let url = new URL(control.config.get("control.controller_url")); url.pathname += `api/stream/${result.stream_id}`; let response = await phin({ url, method: "GET", @@ -1233,14 +1235,14 @@ modCommands.add(new libCommand.Command({ // phin doesn't support streaming requests :( let content = await fs.readFile(args.file); - let url = new URL(control.config.get("control.master_url")); + let url = new URL(control.config.get("control.controller_url")); url.pathname += "api/upload-mod"; url.searchParams.append("filename", filename); let result = await phin({ url, method: "POST", headers: { - "X-Access-Token": control.config.get("control.master_token"), + "X-Access-Token": control.config.get("control.controller_token"), "Content-Type": "application/zip", }, core: { ca: control.tlsCa }, @@ -1278,7 +1280,7 @@ modCommands.add(new libCommand.Command({ version: args.modVersion, }); - let url = new URL(control.config.get("control.master_url")); + let url = new URL(control.config.get("control.controller_url")); url.pathname += `api/stream/${result.stream_id}`; let response = await phin({ url, method: "GET", @@ -1583,20 +1585,20 @@ logCommands.add(new libCommand.Command({ definition: ["follow", "follow cluster log", (yargs) => { yargs.options({ "all": { describe: "Follow the whole cluster log", nargs: 0, type: "boolean", default: false }, - "master": { describe: "Follow log of the master server", nargs: 0, type: "boolean", default: false }, + "controller": { describe: "Follow log of the controller", nargs: 0, type: "boolean", default: false }, "slave": { describe: "Follow log of given slave", nargs: 1, type: "string", default: null }, "instance": { describe: "Follow log of given instance", nargs: 1, type: "string", default: null }, }); }], handler: async function(args, control) { - if (!args.all && !args.master && !args.slave && !args.instance) { - logger.error("At least one of --all, --master, --slave and --instance must be passed"); + if (!args.all && !args.controller && !args.slave && !args.instance) { + logger.error("At least one of --all, --controller, --slave and --instance must be passed"); process.exitCode = 1; return; } let instance_ids = args.instance ? [await libCommand.resolveInstance(control, args.instance)] : []; let slave_ids = args.slave ? [await libCommand.resolveSlave(control, args.slave)] : []; - await control.setLogSubscriptions({ all: args.all, master: args.master, slave_ids, instance_ids }); + await control.setLogSubscriptions({ all: args.all, controller: args.controller, slave_ids, instance_ids }); control.keepOpen = true; }, })); @@ -1605,7 +1607,7 @@ logCommands.add(new libCommand.Command({ definition: ["query", "Query cluster log", (yargs) => { yargs.options({ "all": { describe: "Query the whole cluster log", nargs: 0, type: "boolean", default: false }, - "master": { describe: "Query log of the master server", nargs: 0, type: "boolean", default: false }, + "controller": { describe: "Query log of the controller", nargs: 0, type: "boolean", default: false }, "slave": { describe: "Query log of given slave", nargs: 1, type: "string", default: null }, "instance": { describe: "Query log of given instance", nargs: 1, type: "string", default: null }, "max-level": { describe: "Maximum log level to return", nargs: 1, type: "string", default: null }, @@ -1614,8 +1616,8 @@ logCommands.add(new libCommand.Command({ }); }], handler: async function(args, control) { - if (!args.all && !args.master && !args.slave && !args.instance) { - logger.error("At least one of --all, --master, --slave and --instance must be passed"); + if (!args.all && !args.controller && !args.slave && !args.instance) { + logger.error("At least one of --all, --controller, --slave and --instance must be passed"); process.exitCode = 1; return; } @@ -1623,7 +1625,7 @@ logCommands.add(new libCommand.Command({ let slave_ids = args.slave ? [await libCommand.resolveSlave(control, args.slave)] : []; let result = await libLink.messages.queryLog.send(control, { all: args.all, - master: args.master, + controller: args.controller, slave_ids, instance_ids, max_level: args.maxLevel, @@ -1651,7 +1653,7 @@ logCommands.add(new libCommand.Command({ const debugCommands = new libCommand.CommandTree({ name: "debug", description: "Debugging utilities" }); debugCommands.add(new libCommand.Command({ - definition: ["dump-ws", "Dump WebSocket messages sent and received by master", (yargs) => { }], + definition: ["dump-ws", "Dump WebSocket messages sent and received by controller", (yargs) => { }], handler: async function(args, control) { await libLink.messages.debugDumpWs.send(control); control.keepOpen = true; @@ -1660,7 +1662,7 @@ debugCommands.add(new libCommand.Command({ async function registerCommands(controlPlugins, yargs) { const rootCommands = new libCommand.CommandTree({ name: "clusterioctl", description: "Manage cluster" }); - rootCommands.add(masterCommands); + rootCommands.add(controllerCommands); rootCommands.add(slaveCommands); rootCommands.add(instanceCommands); rootCommands.add(modPackCommands); diff --git a/packages/lib/README.md b/packages/lib/README.md index fab4c958..069ec951 100644 --- a/packages/lib/README.md +++ b/packages/lib/README.md @@ -1,5 +1,5 @@ # Common Library for Clusterio -This package contains functionality shared between master, slave, ctl and/or plugins of Clusterio. +This package contains functionality shared between controller, slave, ctl and/or plugins of Clusterio. See [the Clusterio repository](https://github.com/clusterio/clusterio) for more information on Clusterio. diff --git a/packages/lib/command.js b/packages/lib/command.js index 85b0f864..f1ac5cd0 100644 --- a/packages/lib/command.js +++ b/packages/lib/command.js @@ -140,7 +140,7 @@ class CommandTree { * Resolves a string with either an slave name or an id into an integer with * the slave ID. * - * @param {module:lib/link.Link} client - link to master server to query slave on. + * @param {module:lib/link.Link} client - link to controller to query slave on. * @param {string} slaveName - string with name or id of slave. * @returns {Promise} slave ID. * @static @@ -172,7 +172,7 @@ async function resolveSlave(client, slaveName) { * Resolves a string with either an instance name or an id into an integer * with the instance ID. * - * @param {module:lib/link.Link} client - link to master server to query instance on. + * @param {module:lib/link.Link} client - link to controller to query instance on. * @param {string} instanceName - string with name or id of instance. * @returns {Promise} instance ID. * @static @@ -205,7 +205,7 @@ async function resolveInstance(client, instanceName) { * with the mod pack ID. * * @param {module:lib/link.Link} client - - * link to master server to query mod pack on. + * link to controller to query mod pack on. * @param {string} modPackName - string with name or id of mod pack. * @returns {Promise} mod pack ID. * @static @@ -237,7 +237,7 @@ async function resolveModPack(client, modPackName) { * Resolves a string with either a role name or an id into an object * representing the role. * - * @param {module:lib/link.Link} client - link to master server to query role on. + * @param {module:lib/link.Link} client - link to controller to query role on. * @param {string} roleName - string with name or id of role. * @returns {Promise} Role info. * @static diff --git a/packages/lib/config/definitions.js b/packages/lib/config/definitions.js index 5165d021..70f30403 100644 --- a/packages/lib/config/definitions.js +++ b/packages/lib/config/definitions.js @@ -5,35 +5,35 @@ const classes = require("./classes"); /** - * Master config group for {@link module:lib/config.MasterConfig} + * Controller config group for {@link module:lib/config.ControllerConfig} * @extends module:lib/config.ConfigGroup * @memberof module:lib/config */ -class MasterGroup extends classes.ConfigGroup { } -MasterGroup.defaultAccess = ["master", "slave", "control"]; -MasterGroup.groupName = "master"; -MasterGroup.define({ +class ControllerGroup extends classes.ConfigGroup { } +ControllerGroup.defaultAccess = ["controller", "slave", "control"]; +ControllerGroup.groupName = "controller"; +ControllerGroup.define({ name: "name", title: "Name", description: "Name of the cluster.", type: "string", initial_value: "Your Cluster", }); -MasterGroup.define({ +ControllerGroup.define({ name: "mods_directory", title: "Mods Directory", description: "Path to directory where mods shared with the cluster are stored.", type: "string", initial_value: "mods", }); -MasterGroup.define({ +ControllerGroup.define({ name: "database_directory", title: "Database directory", description: "Directory where item and configuration data is stored.", type: "string", initial_value: "database", }); -MasterGroup.define({ +ControllerGroup.define({ name: "http_port", title: "HTTP Port", description: "Port to listen for HTTP connections on, set to null to not listen for HTTP connections.", @@ -42,7 +42,7 @@ MasterGroup.define({ optional: true, initial_value: 8080, }); -MasterGroup.define({ +ControllerGroup.define({ name: "https_port", title: "HTTPS Port", description: "Port to listen for HTTPS connection on, set to null to not listen for HTTPS connections.", @@ -50,7 +50,7 @@ MasterGroup.define({ type: "number", optional: true, }); -MasterGroup.define({ +ControllerGroup.define({ name: "bind_address", title: "Bind Address", description: "IP address to bind the HTTP and HTTPS ports on.", @@ -58,14 +58,14 @@ MasterGroup.define({ type: "string", optional: true, }); -MasterGroup.define({ +ControllerGroup.define({ name: "external_address", title: "External Address", - description: "Public facing address the master server is hosted on.", + description: "Public facing address the controller is hosted on.", type: "string", optional: true, }); -MasterGroup.define({ +ControllerGroup.define({ name: "tls_certificate", title: "TLS Certificate", description: "Path to the certificate to use for HTTPS.", @@ -73,7 +73,7 @@ MasterGroup.define({ type: "string", optional: true, }); -MasterGroup.define({ +ControllerGroup.define({ name: "tls_private_key", title: "TLS Private Key", description: "Path to the private key to use for HTTPS.", @@ -81,10 +81,10 @@ MasterGroup.define({ type: "string", optional: true, }); -MasterGroup.define({ - access: ["master"], +ControllerGroup.define({ + access: ["controller"], name: "auth_secret", - title: "Master Authentication Secret", + title: "Controller Authentication Secret", description: "Secret used to generate and verify authentication tokens. " + "Should be a long string of random letters and numbers. " + @@ -93,42 +93,42 @@ MasterGroup.define({ type: "string", optional: true, }); -MasterGroup.define({ +ControllerGroup.define({ name: "heartbeat_interval", title: "Heartbeat Interval", description: "Interval heartbeats are sent out on WebSocket connections.", type: "number", initial_value: 15, }); -MasterGroup.define({ +ControllerGroup.define({ name: "session_timeout", title: "Session Timeout", description: "Time in seconds before giving up resuming a dropped WebSocket session.", type: "number", initial_value: 60, }); -MasterGroup.define({ +ControllerGroup.define({ name: "metrics_timeout", title: "Metrics Timeout", description: "Timeout in seconds for metrics gathering from slaves.", type: "number", initial_value: 8, }); -MasterGroup.define({ +ControllerGroup.define({ name: "proxy_stream_timeout", title: "Proxy Stream Timeout", description: "Timeout in seconds for proxy streams to start flowing.", type: "number", initial_value: 15, }); -MasterGroup.define({ +ControllerGroup.define({ name: "default_mod_pack_id", title: "Default Mod Pack", description: "Mod pack used by default for instances.", type: "number", optional: true, }); -MasterGroup.define({ +ControllerGroup.define({ name: "default_role_id", title: "Default role", description: "ID of role assigned by default to new users.", @@ -136,15 +136,15 @@ MasterGroup.define({ optional: true, initial_value: 1, }); -MasterGroup.finalize(); +ControllerGroup.finalize(); /** - * Master Config class + * Controller Config class * @extends module:lib/config.Config * @memberof module:lib/config */ -class MasterConfig extends classes.Config { } -MasterConfig.registerGroup(MasterGroup); +class ControllerConfig extends classes.Config { } +ControllerConfig.registerGroup(ControllerGroup); /** @@ -153,7 +153,7 @@ MasterConfig.registerGroup(MasterGroup); * @memberof module:lib/config */ class SlaveGroup extends classes.ConfigGroup {} -SlaveGroup.defaultAccess = ["master", "slave", "control"]; +SlaveGroup.defaultAccess = ["controller", "slave", "control"]; SlaveGroup.groupName = "slave"; SlaveGroup.define({ name: "name", @@ -183,7 +183,7 @@ SlaveGroup.define({ SlaveGroup.define({ name: "mods_directory_is_shared", title: "Mods Directory is Shared", - description: "True if the mods directory is shared with the master server.", + description: "True if the mods directory is shared with the controller.", type: "boolean", initial_value: true, }); @@ -195,22 +195,22 @@ SlaveGroup.define({ initial_value: "instances", }); SlaveGroup.define({ - name: "master_url", - description: "URL to connect to the master server at", + name: "controller_url", + description: "URL to connect to the controller at", restartRequired: true, type: "string", initial_value: "http://localhost:8080/", }); SlaveGroup.define({ - name: "master_token", - description: "Token to authenticate to master server with.", + name: "controller_token", + description: "Token to authenticate to controller with.", restartRequired: true, type: "string", initial_value: "enter token here", }); SlaveGroup.define({ name: "tls_ca", - description: "Path to Certificate Authority to validate TLS connection to master against.", + description: "Path to Certificate Authority to validate TLS connection to controller against.", restartRequired: true, type: "string", optional: true, @@ -245,7 +245,7 @@ SlaveConfig.registerGroup(SlaveGroup); * @memberof module:lib/config */ class InstanceGroup extends classes.ConfigGroup { } -InstanceGroup.defaultAccess = ["master", "slave", "control"]; +InstanceGroup.defaultAccess = ["controller", "slave", "control"]; InstanceGroup.groupName = "instance"; InstanceGroup.define({ name: "name", @@ -277,7 +277,7 @@ InstanceGroup.finalize(); * @memberof module:lib/config */ class FactorioGroup extends classes.ConfigGroup { } -FactorioGroup.defaultAccess = ["master", "slave", "control"]; +FactorioGroup.defaultAccess = ["controller", "slave", "control"]; FactorioGroup.groupName = "factorio"; FactorioGroup.define({ name: "version", @@ -353,7 +353,7 @@ FactorioGroup.define({ "require_user_verification", "tags", "visibility", ], type: "object", - initial_value: {}, // See create instance handler in master. + initial_value: {}, // See create instance handler in controller. }); FactorioGroup.define({ name: "verbose_logging", @@ -371,19 +371,19 @@ FactorioGroup.define({ }); FactorioGroup.define({ name: "sync_adminlist", - description: "Synchronize adminlist with master server", + description: "Synchronize adminlist with controller", type: "boolean", initial_value: true, }); FactorioGroup.define({ name: "sync_whitelist", - description: "Synchronize whitelist with master server", + description: "Synchronize whitelist with controller", type: "boolean", initial_value: true, }); FactorioGroup.define({ name: "sync_banlist", - description: "Synchronize banlist with master server", + description: "Synchronize banlist with controller", type: "boolean", initial_value: true, }); @@ -415,20 +415,20 @@ class ControlGroup extends classes.ConfigGroup {} ControlGroup.defaultAccess = ["control"]; ControlGroup.groupName = "control"; ControlGroup.define({ - name: "master_url", - description: "URL to connect to the master server at", + name: "controller_url", + description: "URL to connect to the controller at", type: "string", optional: true, }); ControlGroup.define({ - name: "master_token", - description: "Token to authenticate to master server with.", + name: "controller_token", + description: "Token to authenticate to controller with.", type: "string", optional: true, }); ControlGroup.define({ name: "tls_ca", - description: "Path to Certificate Authority to validate TLS connection to master against.", + description: "Path to Certificate Authority to validate TLS connection to controller against.", type: "string", optional: true, }); @@ -472,16 +472,16 @@ function validateGroup(pluginInfo, groupName) { */ function registerPluginConfigGroups(pluginInfos) { for (let pluginInfo of pluginInfos) { - if (pluginInfo.MasterConfigGroup) { - validateGroup(pluginInfo, "MasterConfigGroup"); - MasterConfig.registerGroup(pluginInfo.MasterConfigGroup); + if (pluginInfo.ControllerConfigGroup) { + validateGroup(pluginInfo, "ControllerConfigGroup"); + ControllerConfig.registerGroup(pluginInfo.ControllerConfigGroup); } else { - class MasterConfigGroup extends classes.PluginConfigGroup { } - MasterConfigGroup.defaultAccess = ["master", "slave", "control"]; - MasterConfigGroup.groupName = pluginInfo.name; - MasterConfigGroup.finalize(); - MasterConfig.registerGroup(MasterConfigGroup); + class ControllerConfigGroup extends classes.PluginConfigGroup { } + ControllerConfigGroup.defaultAccess = ["controller", "slave", "control"]; + ControllerConfigGroup.groupName = pluginInfo.name; + ControllerConfigGroup.finalize(); + ControllerConfig.registerGroup(ControllerConfigGroup); } if (pluginInfo.instanceEntrypoint) { @@ -491,7 +491,7 @@ function registerPluginConfigGroups(pluginInfos) { } else { class InstanceConfigGroup extends classes.PluginConfigGroup { } - InstanceConfigGroup.defaultAccess = ["master", "slave", "control"]; + InstanceConfigGroup.defaultAccess = ["controller", "slave", "control"]; InstanceConfigGroup.groupName = pluginInfo.name; InstanceConfigGroup.finalize(); InstanceConfig.registerGroup(InstanceConfigGroup); @@ -506,20 +506,20 @@ function registerPluginConfigGroups(pluginInfos) { * @memberof module:lib/config */ function finalizeConfigs() { - MasterConfig.finalize(); + ControllerConfig.finalize(); SlaveConfig.finalize(); InstanceConfig.finalize(); ControlConfig.finalize(); } module.exports = { - MasterGroup, + ControllerGroup, SlaveGroup, InstanceGroup, FactorioGroup, ControlGroup, - MasterConfig, + ControllerConfig, SlaveConfig, InstanceConfig, ControlConfig, diff --git a/packages/lib/data/ModInfo.js b/packages/lib/data/ModInfo.js index 2c254935..e4953ae8 100644 --- a/packages/lib/data/ModInfo.js +++ b/packages/lib/data/ModInfo.js @@ -11,7 +11,7 @@ const { integerModVersion, integerFactorioVersion, modVersionRegExp } = require( /** - * Info about a mod available on the master server. + * Info about a mod available on the controller. * * See https://wiki.factorio.com/Tutorial:Mod_structure#info.json for * details of the invidiual fields sourced from info.json. diff --git a/packages/lib/database.js b/packages/lib/database.js index 87d3ea5e..61c63528 100644 --- a/packages/lib/database.js +++ b/packages/lib/database.js @@ -1,5 +1,5 @@ /** - * Implementation of master databases + * Implementation of controller databases * * @module lib/database * @author Hornwitser @@ -159,7 +159,7 @@ function checkCount(count) { /** * Item database * - * Stores counts of items for the master server. Items that have not been + * Stores counts of items for the controller. Items that have not been * stored in the database are treated as having a stored count of zero. When * serialized the database discards entries with a zero counts, and when * deserialized the content is verified. diff --git a/packages/lib/link/connectors.js b/packages/lib/link/connectors.js index fa0f2a91..68f8653d 100644 --- a/packages/lib/link/connectors.js +++ b/packages/lib/link/connectors.js @@ -179,7 +179,7 @@ class WebSocketBaseConnector extends events.EventEmitter { } /** - * Connector for master server clients + * Connector for controller clients * * @extends module:lib/link.WebSocketBaseConnector * @memberof module:lib/link @@ -278,7 +278,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector { } /** - * Connect to the master server + * Connect to the controller */ async connect() { this._check("closed"); @@ -294,7 +294,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector { let url = new URL(this._url); url.pathname += "api/socket"; - // Open WebSocket to master + // Open WebSocket to controller logger.verbose(`Connector | connecting to ${url}`); // eslint-disable-next-line node/no-process-env @@ -447,7 +447,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector { let { type, data } = message; if (type === "hello") { - logger.verbose(`Connector | received hello from master version ${data.version}`); + logger.verbose(`Connector | received hello from controller version ${data.version}`); this.emit("hello", data); if (this._sessionToken) { logger.verbose("Connector | Attempting resume"); @@ -460,7 +460,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector { } } else if (type === "ready") { - logger.verbose("Connector | received ready from master"); + logger.verbose("Connector | received ready from controller"); this._state = "connected"; this._sessionToken = data.session_token; this._sessionTimeout = data.session_timeout; @@ -485,7 +485,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector { this.emit("resume"); } else if (type === "invalidate") { - logger.warn("Connector | session invalidated by master"); + logger.warn("Connector | session invalidated by controller"); this._state = "connecting"; this._seq = 1; this._lastReceivedSeq = null; diff --git a/packages/lib/link/link.js b/packages/lib/link/link.js index ee68ba3d..cb292889 100644 --- a/packages/lib/link/link.js +++ b/packages/lib/link/link.js @@ -6,10 +6,10 @@ const libErrors = require("../errors"); const { logger } = require("../logging"); // Some definitions for the terminology used here: -// link: Either side of a master - client connection +// link: Either side of a controller - client connection // connector: Adapter between a link and a socket connection -// connection: the master server side of a link -// client: the side that is not the master server of a link +// connection: the controller side of a link +// client: the side that is not the controller of a link // message: the complete object sent using the 'message' event // data: the data property of a message, essentially the payload. // type: the type property of a message, identifies what to expect in data. diff --git a/packages/lib/link/messages.js b/packages/lib/link/messages.js index 5fa4707b..0f421620 100644 --- a/packages/lib/link/messages.js +++ b/packages/lib/link/messages.js @@ -67,11 +67,11 @@ class Request extends Message { * containing "-" specifications. * @param {?string} permission - * Permission required to send this request. Only applies to - * requests sent from control to master. + * requests sent from control to controller. * @param {?string} forwardTo - * Optional target to forward this request to. 'instance' add * instance_id into the requestProperties and forward to the given - * instance. 'master' forwards it to the master server. + * instance. 'controller' forwards it to the controller. * @param {?Array} requestRequired - * List of properties that are required to be present in the data * payload of this request. Defaults to all. @@ -101,11 +101,13 @@ class Request extends Message { this.requestType = `${type}_request`; this.responseType = `${type}_response`; - if (permission === undefined && links.includes("control-master")) { - throw new Error(`permission is required for ${this.type} request over control-master links`); + if (permission === undefined && links.includes("control-controller")) { + throw new Error(`permission is required for ${this.type} request over control-controller links`); } - if (permission && !links.includes("control-master")) { - throw new Error(`permission is not allowed on ${this.type} request as it is not over control-master link`); + if (permission && !links.includes("control-controller")) { + throw new Error( + `permission is not allowed on ${this.type} request as it is not over control-controller link` + ); } if (!requestRequired) { @@ -119,7 +121,7 @@ class Request extends Message { ...requestProperties, }; - } else if (forwardTo !== "master" && forwardTo !== null) { + } else if (forwardTo !== "controller" && forwardTo !== null) { throw new Error(`Invalid forwardTo value ${forwardTo}`); } @@ -176,7 +178,7 @@ class Request extends Message { * If forwardTo was set to 'instance' the `forwardRequestToInstance` * method on the link is used as the default handler. * - * If forwardTo was set to 'master' the `forwardRequesToMaster` method + * If forwardTo was set to 'controller' the `forwardRequesToController` method * on the link is used as the default handler. * * Does nothing if the link is neither a source nor a target for this @@ -201,8 +203,8 @@ class Request extends Message { if (!handler) { if (this.forwardTo === "instance") { handler = link.forwardRequestToInstance; - } else if (this.forwardTo === "master") { - handler = link.forwardRequestToMaster; + } else if (this.forwardTo === "controller") { + handler = link.forwardRequestToController; } } @@ -210,8 +212,8 @@ class Request extends Message { throw new MissingLinkHandlerError(this.requestType, link.source, link.target); } - // Check permission if this is a handler for a control connection on the master - if (this.permission !== null && `${link.source}-${link.target}` === "master-control") { + // Check permission if this is a handler for a control connection on the controller + if (this.permission !== null && `${link.source}-${link.target}` === "controller-control") { let origHandler = handler; handler = async function(message, request) { // Abuse this binding to get a hold of the ControlConnection instance @@ -276,15 +278,15 @@ class Request extends Message { let messages = {}; // Connection requests -let wsLinks = ["master-control", "control-master", "master-slave", "slave-master"]; +let wsLinks = ["controller-control", "control-controller", "controller-slave", "slave-controller"]; messages.prepareDisconnect = new Request({ type: "prepare_disconnect", links: wsLinks, permission: null, }); -messages.prepareMasterDisconnect = new Request({ - type: "prepare_master_disconnect", +messages.prepareControllerDisconnect = new Request({ + type: "prepare_controller_disconnect", links: ["slave-instance"], }); @@ -296,35 +298,35 @@ messages.ping = new Request({ messages.debugDumpWs = new Request({ type: "debug_dump_ws", - links: ["control-master"], + links: ["control-controller"], permission: "core.debug.dump_ws", }); // Management requests -messages.getMasterConfig = new Request({ - type: "get_master_config", - links: ["control-master"], - permission: "core.master.get_config", +messages.getControllerConfig = new Request({ + type: "get_controller_config", + links: ["control-controller"], + permission: "core.controller.get_config", responseProperties: { "serialized_config": { type: "object" }, }, }); -messages.setMasterConfigField = new Request({ - type: "set_master_config_field", - links: ["control-master"], - permission: "core.master.update_config", +messages.setControllerConfigField = new Request({ + type: "set_controller_config_field", + links: ["control-controller"], + permission: "core.controller.update_config", requestProperties: { "field": { type: "string" }, "value": { type: "string" }, }, }); -messages.setMasterConfigProp = new Request({ - type: "set_master_config_prop", - links: ["control-master"], - permission: "core.master.update_config", +messages.setControllerConfigProp = new Request({ + type: "set_controller_config_prop", + links: ["control-controller"], + permission: "core.controller.update_config", requestRequired: ["field", "prop"], requestProperties: { "field": { type: "string" }, @@ -344,7 +346,7 @@ let slaveProperties = { messages.listSlaves = new Request({ type: "list_slaves", - links: ["control-master"], + links: ["control-controller"], permission: "core.slave.list", responseProperties: { "list": { @@ -360,7 +362,7 @@ messages.listSlaves = new Request({ messages.setSlaveSubscriptions = new Request({ type: "set_slave_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.slave.subscribe", requestProperties: { "all": { type: "boolean" }, @@ -384,7 +386,7 @@ let instanceProperties = { messages.getInstance = new Request({ type: "get_instance", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.get", requestProperties: { "id": { type: "integer" }, @@ -394,7 +396,7 @@ messages.getInstance = new Request({ messages.listInstances = new Request({ type: "list_instances", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.list", responseProperties: { "list": { @@ -410,7 +412,7 @@ messages.listInstances = new Request({ messages.setInstanceSubscriptions = new Request({ type: "set_instance_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.subscribe", requestProperties: { "all": { type: "boolean" }, @@ -423,7 +425,7 @@ messages.setInstanceSubscriptions = new Request({ messages.generateSlaveToken = new Request({ type: "generate_slave_token", - links: ["control-master"], + links: ["control-controller"], permission: "core.slave.generate_token", requestProperties: { "slave_id": { type: ["integer", "null"] }, @@ -435,7 +437,7 @@ messages.generateSlaveToken = new Request({ messages.createSlaveConfig = new Request({ type: "create_slave_config", - links: ["control-master"], + links: ["control-controller"], permission: "core.slave.create_config", requestProperties: { "id": { type: ["integer", "null"] }, @@ -449,7 +451,7 @@ messages.createSlaveConfig = new Request({ messages.createInstance = new Request({ type: "create_instance", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.create", requestProperties: { "serialized_config": { type: "object" }, @@ -458,7 +460,7 @@ messages.createInstance = new Request({ messages.getInstanceConfig = new Request({ type: "get_instance_config", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.get_config", requestProperties: { "instance_id": { type: "integer" }, @@ -470,7 +472,7 @@ messages.getInstanceConfig = new Request({ messages.setInstanceConfigField = new Request({ type: "set_instance_config_field", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.update_config", requestProperties: { "instance_id": { type: "integer" }, @@ -481,7 +483,7 @@ messages.setInstanceConfigField = new Request({ messages.setInstanceConfigProp = new Request({ type: "set_instance_config_prop", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.update_config", requestRequired: ["instance_id", "field", "prop"], requestProperties: { @@ -494,7 +496,7 @@ messages.setInstanceConfigProp = new Request({ messages.assignInstanceCommand = new Request({ type: "assign_instance_command", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.assign", requestProperties: { "instance_id": { type: "integer" }, @@ -504,7 +506,7 @@ messages.assignInstanceCommand = new Request({ messages.startInstance = new Request({ type: "start_instance", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.start", requestProperties: { "save": { type: ["string", "null"] }, @@ -531,7 +533,7 @@ let saveList = { messages.listSaves = new Request({ type: "list_saves", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.save.list", forwardTo: "instance", responseProperties: { @@ -541,7 +543,7 @@ messages.listSaves = new Request({ messages.createSave = new Request({ type: "create_save", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.save.create", forwardTo: "instance", requestProperties: { @@ -554,7 +556,7 @@ messages.createSave = new Request({ messages.renameSave = new Request({ type: "rename_save", - links: ["control-master", "master-slave"], + links: ["control-controller", "controller-slave"], permission: "core.instance.save.rename", forwardTo: "instance", requestProperties: { @@ -565,7 +567,7 @@ messages.renameSave = new Request({ messages.copySave = new Request({ type: "copy_save", - links: ["control-master", "master-slave"], + links: ["control-controller", "controller-slave"], permission: "core.instance.save.copy", forwardTo: "instance", requestProperties: { @@ -576,7 +578,7 @@ messages.copySave = new Request({ messages.deleteSave = new Request({ type: "delete_save", - links: ["control-master", "master-slave"], + links: ["control-controller", "controller-slave"], permission: "core.instance.save.delete", forwardTo: "instance", requestProperties: { @@ -586,7 +588,7 @@ messages.deleteSave = new Request({ messages.downloadSave = new Request({ type: "download_save", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.save.download", requestProperties: { "instance_id": { type: "integer" }, @@ -599,7 +601,7 @@ messages.downloadSave = new Request({ messages.transferSave = new Request({ type: "transfer_save", - links: ["control-master", "master-slave"], + links: ["control-controller", "controller-slave"], permission: "core.instance.save.transfer", requestProperties: { "instance_id": { type: "integer" }, @@ -615,7 +617,7 @@ messages.transferSave = new Request({ messages.pullSave = new Request({ type: "pull_save", - links: ["master-slave"], + links: ["controller-slave"], requestProperties: { "instance_id": { type: "integer" }, "stream_id": { type: "string" }, @@ -628,7 +630,7 @@ messages.pullSave = new Request({ messages.pushSave = new Request({ type: "push_save", - links: ["master-slave"], + links: ["controller-slave"], requestProperties: { "instance_id": { type: "integer" }, "stream_id": { type: "string" }, @@ -638,7 +640,7 @@ messages.pushSave = new Request({ messages.setSaveListSubscriptions = new Request({ type: "set_save_list_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.instance.save.list_subscribe", requestProperties: { "all": { type: "boolean" }, @@ -651,7 +653,7 @@ messages.setSaveListSubscriptions = new Request({ messages.loadScenario = new Request({ type: "load_scenario", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.load_scenario", forwardTo: "instance", requestProperties: { @@ -664,42 +666,42 @@ messages.loadScenario = new Request({ messages.exportData = new Request({ type: "export_data", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.export_data", forwardTo: "instance", }); messages.extractPlayers = new Request({ type: "extract_players", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.extract_players", forwardTo: "instance", }); messages.stopInstance = new Request({ type: "stop_instance", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.stop", forwardTo: "instance", }); messages.killInstance = new Request({ type: "kill_instance", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.kill", forwardTo: "instance", }); messages.deleteInstance = new Request({ type: "delete_instance", - links: ["control-master", "master-slave"], + links: ["control-controller", "controller-slave"], permission: "core.instance.delete", forwardTo: "instance", }); messages.sendRcon = new Request({ type: "send_rcon", - links: ["control-master", "master-slave", "slave-instance"], + links: ["control-controller", "controller-slave", "slave-instance"], permission: "core.instance.send_rcon", forwardTo: "instance", requestProperties: { @@ -712,9 +714,9 @@ messages.sendRcon = new Request({ messages.getModPack = new Request({ type: "get_mod_pack", - links: ["control-master", "instance-slave", "slave-master"], + links: ["control-controller", "instance-slave", "slave-controller"], permission: "core.mod_pack.get", - forwardTo: "master", + forwardTo: "controller", requestProperties: { "id": { type: "integer" }, }, @@ -725,9 +727,9 @@ messages.getModPack = new Request({ messages.getDefaultModPack = new Request({ type: "get_default_mod_pack", - links: ["control-master", "instance-slave", "slave-master"], + links: ["control-controller", "instance-slave", "slave-controller"], permission: "core.mod_pack.get", - forwardTo: "master", + forwardTo: "controller", responseProperties: { "mod_pack": libData.ModPack.jsonSchema, }, @@ -735,7 +737,7 @@ messages.getDefaultModPack = new Request({ messages.listModPacks = new Request({ type: "list_mod_packs", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod_pack.list", responseProperties: { "list": { @@ -747,7 +749,7 @@ messages.listModPacks = new Request({ messages.createModPack = new Request({ type: "create_mod_pack", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod_pack.create", requestProperties: { "mod_pack": libData.ModPack.jsonSchema, @@ -756,7 +758,7 @@ messages.createModPack = new Request({ messages.updateModPack = new Request({ type: "update_mod_pack", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod_pack.update", requestProperties: { "mod_pack": libData.ModPack.jsonSchema, @@ -765,7 +767,7 @@ messages.updateModPack = new Request({ messages.deleteModPack = new Request({ type: "delete_mod_pack", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod_pack.delete", requestProperties: { "id": { type: "integer" }, @@ -774,7 +776,7 @@ messages.deleteModPack = new Request({ messages.setModPackSubscriptions = new Request({ type: "set_mod_pack_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod_pack.subscribe", requestProperties: { "all": { type: "boolean" }, @@ -787,7 +789,7 @@ messages.setModPackSubscriptions = new Request({ messages.getMod = new Request({ type: "get_mod", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod.get", requestProperties: { "name": { type: "string" }, @@ -800,7 +802,7 @@ messages.getMod = new Request({ messages.listMods = new Request({ type: "list_mods", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod.list", responseProperties: { "list": { @@ -812,7 +814,7 @@ messages.listMods = new Request({ messages.searchMods = new Request({ type: "search_mods", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod.search", requestRequired: ["query", "factorio_version", "page"], requestProperties: { @@ -848,7 +850,7 @@ messages.searchMods = new Request({ messages.setModSubscriptions = new Request({ type: "set_mod_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod.subscribe", requestProperties: { "all": { type: "boolean" }, @@ -861,7 +863,7 @@ messages.setModSubscriptions = new Request({ messages.downloadMod = new Request({ type: "download_mod", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod.download", requestProperties: { "name": { type: "string" }, @@ -874,7 +876,7 @@ messages.downloadMod = new Request({ messages.deleteMod = new Request({ type: "delete_mod", - links: ["control-master"], + links: ["control-controller"], permission: "core.mod.delete", requestProperties: { "name": { type: "string" }, @@ -884,7 +886,7 @@ messages.deleteMod = new Request({ messages.listPermissions = new Request({ type: "list_permissions", - links: ["control-master"], + links: ["control-controller"], permission: "core.permission.list", responseProperties: { "list": { @@ -904,7 +906,7 @@ messages.listPermissions = new Request({ messages.listRoles = new Request({ type: "list_roles", - links: ["control-master"], + links: ["control-controller"], permission: "core.role.list", responseProperties: { "list": { @@ -925,7 +927,7 @@ messages.listRoles = new Request({ messages.createRole = new Request({ type: "create_role", - links: ["control-master"], + links: ["control-controller"], permission: "core.role.create", requestProperties: { "name": { type: "string" }, @@ -939,7 +941,7 @@ messages.createRole = new Request({ messages.updateRole = new Request({ type: "update_role", - links: ["control-master"], + links: ["control-controller"], permission: "core.role.update", requestProperties: { "id": { type: "integer" }, @@ -951,7 +953,7 @@ messages.updateRole = new Request({ messages.grantDefaultRolePermissions = new Request({ type: "grant_default_role_permissions", - links: ["control-master"], + links: ["control-controller"], permission: "core.role.update", requestProperties: { "id": { type: "integer" }, @@ -960,7 +962,7 @@ messages.grantDefaultRolePermissions = new Request({ messages.deleteRole = new Request({ type: "delete_role", - links: ["control-master"], + links: ["control-controller"], permission: "core.role.delete", requestProperties: { "id": { type: "integer" }, @@ -989,7 +991,7 @@ const userProperties = { messages.getUser = new Request({ type: "get_user", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.get", requestProperties: { "name": { type: "string" }, @@ -1000,7 +1002,7 @@ messages.getUser = new Request({ messages.listUsers = new Request({ type: "list_users", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.list", responseProperties: { "list": { @@ -1016,7 +1018,7 @@ messages.listUsers = new Request({ messages.setUserSubscriptions = new Request({ type: "set_user_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.subscribe", requestProperties: { "all": { type: "boolean" }, @@ -1029,7 +1031,7 @@ messages.setUserSubscriptions = new Request({ messages.createUser = new Request({ type: "create_user", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.create", requestProperties: { "name": { type: "string" }, @@ -1038,7 +1040,7 @@ messages.createUser = new Request({ messages.revokeUserToken = new Request({ type: "revoke_user_token", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.revoke_token", requestProperties: { "name": { type: "string" }, @@ -1047,7 +1049,7 @@ messages.revokeUserToken = new Request({ messages.updateUserRoles = new Request({ type: "update_user_roles", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.update_roles", requestProperties: { "name": { type: "string" }, @@ -1057,7 +1059,7 @@ messages.updateUserRoles = new Request({ messages.setUserAdmin = new Request({ type: "set_user_admin", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.set_admin", requestProperties: { "name": { type: "string" }, @@ -1068,7 +1070,7 @@ messages.setUserAdmin = new Request({ messages.setUserWhitelisted = new Request({ type: "set_user_whitelisted", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.set_whitelisted", requestProperties: { "name": { type: "string" }, @@ -1079,7 +1081,7 @@ messages.setUserWhitelisted = new Request({ messages.setUserBanned = new Request({ type: "set_user_banned", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.set_banned", requestProperties: { "name": { type: "string" }, @@ -1091,7 +1093,7 @@ messages.setUserBanned = new Request({ messages.deleteUser = new Request({ type: "delete_user", - links: ["control-master"], + links: ["control-controller"], permission: "core.user.delete", requestProperties: { "name": { type: "string" }, @@ -1100,11 +1102,11 @@ messages.deleteUser = new Request({ messages.setLogSubscriptions = new Request({ type: "set_log_subscriptions", - links: ["control-master"], + links: ["control-controller"], permission: "core.log.follow", requestProperties: { "all": { type: "boolean" }, - "master": { type: "boolean" }, + "controller": { type: "boolean" }, "slave_ids": { type: "array", items: { type: "integer" }, @@ -1119,11 +1121,11 @@ messages.setLogSubscriptions = new Request({ messages.queryLog = new Request({ type: "query_log", - links: ["control-master"], + links: ["control-controller"], permission: "core.log.query", requestProperties: { "all": { type: "boolean" }, - "master": { type: "boolean" }, + "controller": { type: "boolean" }, "slave_ids": { type: "array", items: { type: "integer" }, @@ -1148,7 +1150,7 @@ messages.queryLog = new Request({ // Internal requests messages.updateInstances = new Request({ type: "update_instances", - links: ["slave-master"], + links: ["slave-controller"], requestProperties: { "instances": { type: "array", @@ -1169,7 +1171,7 @@ messages.updateInstances = new Request({ messages.assignInstance = new Request({ type: "assign_instance", - links: ["master-slave"], + links: ["controller-slave"], requestProperties: { "serialized_config": { type: "object" }, }, @@ -1178,13 +1180,13 @@ messages.assignInstance = new Request({ messages.unassignInstance = new Request({ type: "unassigne_instance", - links: ["master-slave"], + links: ["controller-slave"], forwardTo: "instance", }); messages.getMetrics = new Request({ type: "get_metrics", - links: ["master-slave", "slave-instance"], + links: ["controller-slave", "slave-instance"], responseProperties: { "results": { type: "array" }, }, @@ -1213,7 +1215,7 @@ class Event extends Message { * containing "-" specifications. * @param {?string} forwardTo - * Optional target to forward this request to. Supported values are - * 'master' and 'instance'. If set to 'instance' an instance_id + * 'controller' and 'instance'. If set to 'instance' an instance_id * property is implicity added to eventProperties. * @param {?string} broadcastTo - * Optional target to broadcast this event to. Only 'instance' is @@ -1247,7 +1249,7 @@ class Event extends Message { ...eventProperties, }; - } else if (forwardTo !== "master" && forwardTo !== null) { + } else if (forwardTo !== "controller" && forwardTo !== null) { throw new Error(`Invalid forwardTo value ${forwardTo}`); } @@ -1275,7 +1277,7 @@ class Event extends Message { * Set a the handler for the event on the given link if it's a target * for the event. * - * If forwardTo was set to 'master' the `forwardEventToMaster` method on + * If forwardTo was set to 'controller' the `forwardEventToController` method on * the link is used as the default handler. If it was set to 'instance' * the `forwardEventToInstance` method on the link is used by default. * @@ -1297,15 +1299,15 @@ class Event extends Message { if (!handler) { if (this.forwardTo === "instance") { handler = link.forwardEventToInstance; - } else if (this.forwardTo === "master") { - handler = link.forwardEventToMaster; + } else if (this.forwardTo === "controller") { + handler = link.forwardEventToController; } } if ( this.broadcastTo === "instance" && [ - "instance-slave", "slave-master", "control-master", "master-slave", + "instance-slave", "slave-controller", "control-controller", "controller-slave", ].includes(`${link.target}-${link.source}`) ) { if (!handler) { @@ -1352,7 +1354,7 @@ class Event extends Message { messages.debugWsMessage = new Event({ type: "debug_ws_message", - links: ["master-control"], + links: ["controller-control"], eventProperties: { "direction": { type: "string" }, "content": { type: "string" }, @@ -1361,7 +1363,7 @@ messages.debugWsMessage = new Event({ messages.accountUpdate = new Event({ type: "account_update", - links: ["master-control"], + links: ["controller-control"], eventRequired: [], eventProperties: { "roles": { @@ -1385,7 +1387,7 @@ messages.accountUpdate = new Event({ messages.logMessage = new Event({ type: "log_message", - links: ["slave-master", "master-control"], + links: ["slave-controller", "controller-control"], eventProperties: { "info": { type: "object", @@ -1400,7 +1402,7 @@ messages.logMessage = new Event({ messages.slaveUpdate = new Event({ type: "slave_update", - links: ["master-control"], + links: ["controller-control"], eventProperties: slaveProperties, }); @@ -1418,7 +1420,7 @@ messages.instanceInitialized = new Event({ }); messages.instanceStatusChanged = new Event({ type: "instance_status_changed", - links: ["instance-slave", "slave-master"], + links: ["instance-slave", "slave-controller"], eventRequired: ["instance_id", "status"], eventProperties: { "instance_id": { type: "integer" }, @@ -1431,14 +1433,14 @@ messages.instanceStatusChanged = new Event({ messages.instanceUpdate = new Event({ type: "instance_update", - links: ["master-control"], + links: ["controller-control"], eventProperties: instanceProperties, }); messages.saveListUpdate = new Event({ type: "save_list_update", - links: ["instance-slave", "slave-master", "master-control"], - forwardTo: "master", + links: ["instance-slave", "slave-controller", "controller-control"], + forwardTo: "controller", eventProperties: { "instance_id": { type: "integer" }, "list": saveList, @@ -1447,7 +1449,7 @@ messages.saveListUpdate = new Event({ messages.modPackUpdate = new Event({ type: "mod_pack_update", - links: ["master-control"], + links: ["controller-control"], eventProperties: { "mod_pack": libData.ModPack.jsonSchema, }, @@ -1455,7 +1457,7 @@ messages.modPackUpdate = new Event({ messages.modUpdate = new Event({ type: "mod_update", - links: ["master-control"], + links: ["controller-control"], eventProperties: { "mod": libData.ModInfo.jsonSchema, }, @@ -1463,13 +1465,13 @@ messages.modUpdate = new Event({ messages.userUpdate = new Event({ type: "user_update", - links: ["master-control"], + links: ["controller-control"], eventRequired: userRequired, eventProperties: userProperties, }); -messages.masterConnectionEvent = new Event({ - type: "master_connection_event", +messages.controllerConnectionEvent = new Event({ + type: "controller_connection_event", links: ["slave-instance"], eventProperties: { "event": { type: "string" }, @@ -1478,7 +1480,7 @@ messages.masterConnectionEvent = new Event({ messages.syncUserLists = new Event({ type: "sync_user_lists", - links: ["master-slave"], + links: ["controller-slave"], eventProperties: { "adminlist": { type: "array", @@ -1501,7 +1503,7 @@ messages.syncUserLists = new Event({ messages.banlistUpdate = new Event({ type: "banlist_update", - links: ["master-slave", "slave-instance"], + links: ["controller-slave", "slave-instance"], broadcastTo: "instance", eventProperties: { "name": { type: "string" }, @@ -1512,7 +1514,7 @@ messages.banlistUpdate = new Event({ messages.adminlistUpdate = new Event({ type: "adminlist_update", - links: ["master-slave", "slave-instance"], + links: ["controller-slave", "slave-instance"], eventProperties: { "name": { type: "string" }, "admin": { type: "boolean" }, @@ -1522,7 +1524,7 @@ messages.adminlistUpdate = new Event({ messages.whitelistUpdate = new Event({ type: "whitelist_update", - links: ["master-slave", "slave-instance"], + links: ["controller-slave", "slave-instance"], eventProperties: { "name": { type: "string" }, "whitelisted": { type: "boolean" }, @@ -1532,8 +1534,8 @@ messages.whitelistUpdate = new Event({ messages.playerEvent = new Event({ type: "player_event", - links: ["instance-slave", "slave-master"], - forwardTo: "master", + links: ["instance-slave", "slave-controller"], + forwardTo: "controller", eventRequired: ["instance_id", "type", "name"], eventProperties: { "instance_id": { type: "integer" }, diff --git a/packages/lib/logging.js b/packages/lib/logging.js index 4c1ecff2..15e93efa 100644 --- a/packages/lib/logging.js +++ b/packages/lib/logging.js @@ -88,9 +88,9 @@ class WebConsoleFormat { * @property {string} [max_level] - * Maximum log level to include. Higher levels are more verbose. * @property {boolean} [all] - - * Include log entries from master, all slaves and all instances. - * @property {boolean} [master] - - * Include log entries from the master server. + * Include log entries from controller, all slaves and all instances. + * @property {boolean} [controller] - + * Include log entries from the controller. * @property {Array} [slave_ids] - * Include log entries for the given slaves and instances of those * slaves by id. @@ -107,7 +107,7 @@ class WebConsoleFormat { * filter returning true for log entries that match it. * @static */ -function logFilter({ all, master, slave_ids, instance_ids, max_level }) { +function logFilter({ all, controller, slave_ids, instance_ids, max_level }) { return info => { // Note: reversed to filter out undefined levels if (max_level && !(levels[info.level] <= levels[max_level])) { @@ -117,7 +117,7 @@ function logFilter({ all, master, slave_ids, instance_ids, max_level }) { if (all) { return true; } - if (master && info.slave_id === undefined) { + if (controller && info.slave_id === undefined) { return true; } if ( diff --git a/packages/lib/logging_utils.js b/packages/lib/logging_utils.js index 5117a421..2417e13c 100644 --- a/packages/lib/logging_utils.js +++ b/packages/lib/logging_utils.js @@ -157,7 +157,7 @@ class LogIndex { for (let [file, serializedEntry] of Object.entries(serialized.files)) { this.index.set(file, { levels: new Set(serializedEntry.levels), - master: serializedEntry.master, + controller: serializedEntry.controller, slave_ids: new Set(serializedEntry.slave_ids), instance_ids: new Set(serializedEntry.instance_ids), }); @@ -173,7 +173,7 @@ class LogIndex { for (let [file, entry] of this.index) { serialized.files[file] = { levels: [...entry.levels], - master: entry.master, + controller: entry.controller, slave_ids: [...entry.slave_ids], instance_ids: [...entry.instance_ids], }; @@ -224,7 +224,7 @@ class LogIndex { fileStream.pipe(lineStream); let entry = { levels: new Set(), - master: false, + controller: false, slave_ids: new Set(), instance_ids: new Set(), }; @@ -234,14 +234,14 @@ class LogIndex { info = JSON.parse(line); } catch (err) { entry.levels.add("info"); - entry.master = true; + entry.controller = true; continue; } if (info.level) { entry.levels.add(info.level); } if (info.slave_id === undefined) { - entry.master = true; + entry.controller = true; } else if (info.instance_id === undefined) { entry.slave_ids.add(info.slave_id); } @@ -279,7 +279,7 @@ class LogIndex { * @returns {boolean} * true if the file may contain entries included by the filter. */ - filterIncludesFile(file, { max_level, all, master, instance_ids, slave_ids }) { + filterIncludesFile(file, { max_level, all, controller, instance_ids, slave_ids }) { let entry = this.index.get(file); if (!entry) { return true; @@ -298,7 +298,7 @@ class LogIndex { if (all) { return true; } - if (master && entry.master) { + if (controller && entry.controller) { return true; } if (slave_ids && slave_ids.some(id => entry.slave_ids.has(id))) { @@ -321,9 +321,9 @@ class LogIndex { * @property {string} [max_level] - * Maximum log level to include. Higher levels are more verbose. * @property {boolean} [all] - - * Include log entries from master, all slaves and all instances. - * @property {boolean} [master] - - * Include log entries from the master server. + * Include log entries from controller, all slaves and all instances. + * @property {boolean} [controller] - + * Include log entries from the controller. * @property {Array} [slave_ids] - * Include log entries for the given slaves and instances of those * slaves by id. diff --git a/packages/lib/plugin.js b/packages/lib/plugin.js index 4b56b976..0f0cf80b 100644 --- a/packages/lib/plugin.js +++ b/packages/lib/plugin.js @@ -7,9 +7,9 @@ const helpers = require("./helpers"); /** - * Conceptual base for master and instance plugins. + * Conceptual base for controller and instance plugins. * @typedef { - * module:lib/plugin.BaseMasterPlugin + * module:lib/plugin.BaseControllerPlugin * |module:lib/plugin.BaseInstancePlugin * |module:lib/plugin.BaseControlPlugin * } module:lib/plugin.BasePlugin @@ -150,22 +150,22 @@ class BaseInstancePlugin { async onOutput(parsed, line) { } /** - * Called when an event on the master connection happens + * Called when an event on the controller connection happens * * The event param may be one of connect, drop, resume and close and has * the following meaning: * * ##### connect * - * Invoked when a new connection to the master has been established. + * Invoked when a new connection to the controller has been established. * * ##### drop * * Invoked when a connection loss is detected between the slave and the - * master. Plugins should respond to this event by throtteling messages - * it is sending to the master to an absolute minimum. + * controller. Plugins should respond to this event by throtteling messages + * it is sending to the controller to an absolute minimum. * - * Messages sent over a dropped master connection will get queued up in + * Messages sent over a dropped controller connection will get queued up in * memory on the slave and sent all in one go when the connection is * re-established again. * @@ -176,29 +176,29 @@ class BaseInstancePlugin { * * ##### close * - * Invoked when the connection to the master has been closed. This - * typically means the master server has shut down. Plugins should not - * send any messages that goes to or via the master server after the + * Invoked when the connection to the controller has been closed. This + * typically means the controller has shut down. Plugins should not + * send any messages that goes to or via the controller after the * connection has been closed and before a new one is established. * * @param {string} event - one of connect, drop, resume and close */ - onMasterConnectionEvent(event) { } + onControllerConnectionEvent(event) { } /** - * Called when the master is preparing to disconnect from the slave + * Called when the controller is preparing to disconnect from the slave * - * Invoked when the master server has requested the disconnection from + * Invoked when the controller has requested the disconnection from * the slave. This typically happens when it is in the process of * shutting down. * - * Plugins must stop sending messages to the master, or are forwarded - * via the master server after the prepare disconnect has been handled. + * Plugins must stop sending messages to the controller, or are forwarded + * via the controller after the prepare disconnect has been handled. * - * @param {module:master/src/SlaveConnection} connection - + * @param {module:controller/src/SlaveConnection} connection - * The connection to the slave preparing to disconnect. */ - async onPrepareMasterDisconnect(connection) { } + async onPrepareControllerDisconnect(connection) { } /** * Called when a player joins or leaves the game @@ -284,25 +284,25 @@ class BaseInstancePlugin { } /** - * Base class for master plugins + * Base class for controller plugins * - * Master plugins are subclasses of this class which get instantiated by - * the master server on startup when the plugin is enabled in the config. - * To be discovered the class must be exported under the name `MasterPlugin` - * in the module specified by the `masterEntrypoint` in the plugin's info.js + * Controller plugins are subclasses of this class which get instantiated by + * the controller on startup when the plugin is enabled in the config. + * To be discovered the class must be exported under the name `ControllerPlugin` + * in the module specified by the `controllerEntrypoint` in the plugin's info.js * file. * * @static */ -class BaseMasterPlugin { - constructor(info, master, metrics, logger) { +class BaseControllerPlugin { + constructor(info, controller, metrics, logger) { this.info = info; /** - * Master server - * @type {module:master/src/Master} + * Controller + * @type {module:controller/src/Controller} */ - this.master = master; + this.controller = controller; this.metrics = metrics; /** @@ -323,7 +323,7 @@ class BaseMasterPlugin { /** * Called when the status of an instance changes * - * Invoked when the master server has changed the status of an instance + * Invoked when the controller has changed the status of an instance * or received notice from a slave that the status of an instance has * changed. The possible statuses that can be notified about are: * - `unassigned:`: Instance is no longer asssigned to a slave. @@ -338,21 +338,21 @@ class BaseMasterPlugin { * icons and locale data. * - `deleted`: Instance was deleted. * - * On master startup all known instances gets the status `unknown` if + * On controller startup all known instances gets the status `unknown` if * they are assigned to a slave, when the slave then connects to the - * master and informs of the current status of its instances this hook + * controller and informs of the current status of its instances this hook * is invoked for all those instances. You can detect this situation by * checking if prev equals `unknown`. If the slave disconnects the * instances will again get the `unknown` status. * - * When instances are created on the master they will notify of a status + * When instances are created on the controller they will notify of a status * change with prev set to null. While the status of new instances is * in most cases `unassigned` it's possible for the created instance to * start with any state in some slave connection corner cases. * * Note that it's possible for status change notification to get lost in * the case of network outages if reconnect fails to re-establish the - * session between the master server and the slave. + * session between the controller and the slave. * * @param {Object} instance - the instance that changed. * @param {?string} prev - the previous status of the instance. @@ -360,17 +360,17 @@ class BaseMasterPlugin { async onInstanceStatusChanged(instance, prev) { } /** - * Called when the value of a master config field changed. + * Called when the value of a controller config field changed. * * Invoked after the value of the config field given by `field` has - * changed on the master. + * changed on the controller. * * @param {module:lib/config.ConfigGroup} group - * The group who's field got changed. * @param {string} field - Name of the field that changed. * @param {*} prev - The previous value of the field. */ - async onMasterConfigFieldChanged(group, field, prev) { } + async onControllerConfigFieldChanged(group, field, prev) { } /** * Called when the value of an instance config field changed. @@ -404,7 +404,7 @@ class BaseMasterPlugin { async onMetrics() { } /** - * Called when the master server is shutting down + * Called when the controller is shutting down */ async onShutdown() { } @@ -420,12 +420,12 @@ class BaseMasterPlugin { * * ##### drop * - * Invoked when a connection loss is detected between the master and a + * Invoked when a connection loss is detected between the controller and a * slave. Plugins should respond to this event by throtteling messages * it is sending to the given slave connection to an absolute minimum. * * Messages sent over a dropped slave connection will get queued up in - * memory on the master and sent all in one go when the connection is + * memory on the controller and sent all in one go when the connection is * re-established again. * * ##### resume @@ -437,7 +437,7 @@ class BaseMasterPlugin { * * Invoked when the connection to the slave has been closed. * - * @param {module:master/src/SlaveConnection} connection - + * @param {module:controller/src/SlaveConnection} connection - * The connection the event occured on. * @param {string} event - one of connect, drop, resume and close */ @@ -455,13 +455,13 @@ class BaseMasterPlugin { * * ##### drop * - * Invoked when a connection loss is detected between the master and a + * Invoked when a connection loss is detected between the controller and a * control. Plugins should respond to this event by throtteling * messages it is sending to the given control connection to an absolute * minimum. * * Messages sent over a dropped control connection will get queued up in - * memory on the master and sent all in one go when the connection is + * memory on the controller and sent all in one go when the connection is * re-established again. * * ##### resume @@ -473,22 +473,22 @@ class BaseMasterPlugin { * * Invoked when the connection to the control has been closed. * - * @param {module:master/src/ControlConnection} connection - + * @param {module:controller/src/ControlConnection} connection - * The connection the event occured on. * @param {string} event - one of connect, drop, resume, and close. */ onControlConnectionEvent(connection, event) { } /** - * Called when a slave is preparing to disconnect from the master + * Called when a slave is preparing to disconnect from the controller * - * Invoked when a slave has requested the disconnection from the master. + * Invoked when a slave has requested the disconnection from the controller. * This typically happens when it is in the process of shutting down. * * Plugins must stop sending messages to the slave in question after the * prepare disconnect has been handled. * - * @param {module:master/src/SlaveConnection} connection - + * @param {module:controller/src/SlaveConnection} connection - * The connection to the slave preparing to disconnect. */ async onPrepareSlaveDisconnect(connection) { } @@ -507,7 +507,7 @@ class BaseMasterPlugin { async onModPackUpdated(modPack) { } /** - * Called when a mod stored on the master server is updated + * Called when a mod stored on the controller is updated * * Invoked when a mod has been added, updated or deleted from the pool * of shared mods stored on the cluster. @@ -538,7 +538,7 @@ class BaseMasterPlugin { /** * Broadcast event to all connected slaves * - * Sends the given event to all slaves connected to the master server. + * Sends the given event to all slaves connected to the controller. * This does not include slaves that are in the process of closing the * connection, which typically happens when they are shutting down. * @@ -546,7 +546,7 @@ class BaseMasterPlugin { * @param {Object} data - Data ta pass with the event. */ broadcastEventToSlaves(event, data={}) { - for (let slaveConnection of this.master.wsServer.slaveConnections.values()) { + for (let slaveConnection of this.controller.wsServer.slaveConnections.values()) { if ( !slaveConnection.connector.closing && (!event.plugin || slaveConnection.plugins.has(event.plugin)) @@ -660,8 +660,8 @@ class BaseWebPlugin { this.info = info; /** - * Control link to the master server, not available until the - * connect event in onMasterConnectionEvent is signaled. + * Control link to the controller, not available until the + * connect event in onControllerConnectionEvent is signaled. * @type {?module:lib/link.Link} */ this.control = null; @@ -700,8 +700,8 @@ class BaseWebPlugin { * component extra. * * @type {object} - * @property {React.ComponentType} MasterPage - - * Placed at the end of the master page. + * @property {React.ComponentType} ControllerPage - + * Placed at the end of the controller page. * @property {React.ComponentType} SlavesPage - * Placed at the end of the slaves list page. * @property {React.ComponentType} SlaveViewPage - @@ -732,22 +732,22 @@ class BaseWebPlugin { async init() { } /** - * Called when an event on the master connection happens + * Called when an event on the controller connection happens * * The event param may be one of connect, drop, resume and close and has * the following meaning: * * ##### connect * - * Invoked when a new connection to the master has been established. + * Invoked when a new connection to the controller has been established. * * ##### drop * * Invoked when a connection loss is detected between the control link - * and the master. Plugins should respond to this event by throtteling - * messages it is sending to the master to an absolute minimum. + * and the controller. Plugins should respond to this event by throtteling + * messages it is sending to the controller to an absolute minimum. * - * Messages sent over a dropped master connection will get queued up in + * Messages sent over a dropped controller connection will get queued up in * memory in the browser and sent all in one go when the connection is * re-established again. * @@ -758,14 +758,14 @@ class BaseWebPlugin { * * ##### close * - * Invoked when the connection to the master has been closed. This - * typically means the master server has shut down. Plugins should not - * send any messages that goes to or via the master server after the + * Invoked when the connection to the controller has been closed. This + * typically means the controller has shut down. Plugins should not + * send any messages that goes to or via the controller after the * connection has been closed and before a new one is established. * * @param {string} event - one of connect, drop, resume and close */ - onMasterConnectionEvent(event) { } + onControllerConnectionEvent(event) { } } /** @@ -840,7 +840,7 @@ async function invokeHook(plugins, hook, ...args) { module.exports = { BaseInstancePlugin, - BaseMasterPlugin, + BaseControllerPlugin, BaseControlPlugin, BaseWebPlugin, diff --git a/packages/lib/plugin_loader.js b/packages/lib/plugin_loader.js index 6ec0310a..e1f03ca0 100644 --- a/packages/lib/plugin_loader.js +++ b/packages/lib/plugin_loader.js @@ -66,7 +66,7 @@ function loadPluginClass(entrypointName, className, pluginClass, pluginInfo) { } /** - * Load master plugin class of a plugin + * Load controller plugin class of a plugin * * @param {Object} pluginInfo - * Plugin info object returned from {@link @@ -74,8 +74,8 @@ function loadPluginClass(entrypointName, className, pluginClass, pluginInfo) { * @returns {Promise} plugin class * @static */ -async function loadMasterPluginClass(pluginInfo) { - return loadPluginClass("masterEntrypoint", "MasterPlugin", libPlugin.BaseMasterPlugin, pluginInfo); +async function loadControllerPluginClass(pluginInfo) { + return loadPluginClass("controllerEntrypoint", "ControllerPlugin", libPlugin.BaseControllerPlugin, pluginInfo); } /** @@ -106,7 +106,7 @@ async function loadControlPluginClass(pluginInfo) { module.exports = { loadPluginInfos, - loadMasterPluginClass, + loadControllerPluginClass, loadInstancePluginClass, loadControlPluginClass, }; diff --git a/packages/lib/shared_commands.js b/packages/lib/shared_commands.js index 8f050ad1..3f2b95ad 100644 --- a/packages/lib/shared_commands.js +++ b/packages/lib/shared_commands.js @@ -1,5 +1,5 @@ /** - * Implementation of commands shared between master/slave/ctl. + * Implementation of commands shared between controller/slave/ctl. * @module lib/shared_commands */ "use strict"; diff --git a/packages/lib/users.js b/packages/lib/users.js index 1e0156cb..a530f223 100644 --- a/packages/lib/users.js +++ b/packages/lib/users.js @@ -350,19 +350,19 @@ definePermission({ definePermission({ name: "core.control.connect", title: "Connect to WebSocket", - description: "Connect to the master's WebSocket control interface.", + description: "Connect to the controller's WebSocket control interface.", grantByDefault: true, }); definePermission({ - name: "core.master.get_config", - title: "Get master config", - description: "Get the config of master.", + name: "core.controller.get_config", + title: "Get controller config", + description: "Get the config of controller.", }); definePermission({ - name: "core.master.update_config", - title: "Modify master config", - description: "Modify the master config or entries of the master config.", + name: "core.controller.update_config", + title: "Modify controller config", + description: "Modify the controller config or entries of the controller config.", }); definePermission({ name: "core.slave.list", @@ -384,7 +384,7 @@ definePermission({ definePermission({ name: "core.slave.create_config", title: "Create slave config", - description: "Create slave configs via the master server.", + description: "Create slave configs via the controller.", }); definePermission({ @@ -408,7 +408,7 @@ definePermission({ definePermission({ name: "core.instance.create", title: "Create instance", - description: "Create new instances on the master server.", + description: "Create new instances on the controller.", }); definePermission({ name: "core.instance.get_config", @@ -473,7 +473,7 @@ definePermission({ definePermission({ name: "core.instance.export_data", title: "Export locale and icons", - description: "Export the the locale and icons from an instance and upload it to the master.", + description: "Export the the locale and icons from an instance and upload it to the controller.", }); definePermission({ name: "core.instance.extract_players", @@ -553,13 +553,13 @@ definePermission({ definePermission({ name: "core.mod.list", title: "List mods", - description: "Get the full list of mods stored on the master.", + description: "Get the full list of mods stored on the controller.", grantByDefault: true, }); definePermission({ name: "core.mod.search", title: "Search mods", - description: "Search through the list of mods stored on the master.", + description: "Search through the list of mods stored on the controller.", grantByDefault: true, }); definePermission({ @@ -571,18 +571,18 @@ definePermission({ definePermission({ name: "core.mod.upload", title: "Upload mod", - description: "Upload mods to the master.", + description: "Upload mods to the controller.", }); definePermission({ name: "core.mod.download", title: "Download mod", - description: "Download mods stored on the master.", + description: "Download mods stored on the controller.", grantByDefault: true, }); definePermission({ name: "core.mod.delete", title: "Delete mod", - description: "Delete mods stored on the master.", + description: "Delete mods stored on the controller.", }); definePermission({ @@ -687,7 +687,7 @@ definePermission({ definePermission({ name: "core.debug.dump_ws", title: "Dump WebSocket", - description: "Dump all WebSocket communicatation from the master.", + description: "Dump all WebSocket communicatation from the controller.", }); module.exports = { diff --git a/packages/slave/README.md b/packages/slave/README.md index a650e3ad..45a489ce 100644 --- a/packages/slave/README.md +++ b/packages/slave/README.md @@ -1,7 +1,7 @@ # Clusterio Slave Node hosting Factorio servers in a Clusterio cluster. -Clusterio slaves connect to the master server and waits for commands from the master server to start up and stop instances. +Clusterio slaves connect to the controller and waits for commands from the controller to start up and stop instances. A cluster can have any number of slaves in it located on different computers, and each slave can host any number of instances each of which is a Factorio server that talks with the rest of the cluster. @@ -36,7 +36,7 @@ For example, installing the Subspace Storage plugin: npm install @clusterio/plugin-subspace_storage npx clusterioslave plugin add @clusterio/plugin-subspace_storage -Since the `plugin-list.json` is shared between master, slave and ctl you usually only need to do this once per machine. +Since the `plugin-list.json` is shared between controller, slave and ctl you usually only need to do this once per machine. #### `plugin remove ` @@ -50,7 +50,7 @@ For example, uninstalling the Subspace Storage plugin: npx clusterioslave plugin remove subspace_storage npm uninstall @clusterio/plugin-subspace_storage -Since the `plugin-list.json` is shared between master, slave and ctl you usually only need to do this once per machine. +Since the `plugin-list.json` is shared between controller, slave and ctl you usually only need to do this once per machine. #### `plugin list` diff --git a/packages/slave/slave.js b/packages/slave/slave.js index c252ded4..8bf9d58e 100755 --- a/packages/slave/slave.js +++ b/packages/slave/slave.js @@ -3,9 +3,9 @@ /** * Clusterio slave * - * Connects to the master server and hosts Factorio servers that can + * Connects to the controller and hosts Factorio servers that can * communicate with the cluster. It is remotely controlled by {@link - * module:master/master}. + * module:controller/controller}. * * @module slave/slave * @author Danielv123, Hornwitser @@ -36,7 +36,7 @@ const Slave = require("./src/Slave"); class SlaveConnector extends libLink.WebSocketClientConnector { constructor(slaveConfig, tlsCa, pluginInfos) { super( - slaveConfig.get("slave.master_url"), + slaveConfig.get("slave.controller_url"), slaveConfig.get("slave.max_reconnect_delay"), tlsCa ); @@ -52,7 +52,7 @@ class SlaveConnector extends libLink.WebSocketClientConnector { } this.sendHandshake("register_slave", { - token: this.slaveConfig.get("slave.master_token"), + token: this.slaveConfig.get("slave.controller_token"), agent: "Clusterio Slave", version, id: this.slaveConfig.get("slave.id"), @@ -187,13 +187,13 @@ async function startSlave() { // and as the process name in ps/top on linux. process.title = "clusterioSlave"; - // make sure we have the master access token - if (slaveConfig.get("slave.master_token") === "enter token here") { + // make sure we have the controller access token + if (slaveConfig.get("slave.controller_token") === "enter token here") { logger.fatal("ERROR invalid config!"); logger.fatal( - "Master server requires an access token for socket operations. As clusterio\n"+ + "Controller requires an access token for socket operations. As clusterio\n"+ "slaves depends upon this, please set your token using the command npx\n"+ - "clusterioslave config set slave.master_token . You can generate an\n"+ + "clusterioslave config set slave.controller_token . You can generate an\n"+ "auth token using npx clusterioctl generate-slave-token." ); process.exitCode = 1; @@ -201,9 +201,9 @@ async function startSlave() { } // make sure url ends with / - if (!slaveConfig.get("slave.master_url").endsWith("/")) { + if (!slaveConfig.get("slave.controller_url").endsWith("/")) { logger.fatal("ERROR invalid config!"); - logger.fatal("slave.master_url must end with '/'"); + logger.fatal("slave.controller_url must end with '/'"); process.exitCode = 1; return; } diff --git a/packages/slave/src/Instance.js b/packages/slave/src/Instance.js index 8f1965b5..726e4f1f 100644 --- a/packages/slave/src/Instance.js +++ b/packages/slave/src/Instance.js @@ -962,12 +962,12 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " "); await this.server.kill(true); } - async masterConnectionEventEventHandler(message) { - await libPlugin.invokeHook(this.plugins, "onMasterConnectionEvent", message.data.event); + async controllerConnectionEventEventHandler(message) { + await libPlugin.invokeHook(this.plugins, "onControllerConnectionEvent", message.data.event); } - async prepareMasterDisconnectRequestHandler() { - await libPlugin.invokeHook(this.plugins, "onPrepareMasterDisconnect"); + async prepareControllerDisconnectRequestHandler() { + await libPlugin.invokeHook(this.plugins, "onPrepareControllerDisconnect"); } async getMetricsRequestHandler() { @@ -1072,7 +1072,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " "); let zip = await libFactorio.exportData(this.server); let content = await zip.generateAsync({ type: "nodebuffer" }); - let url = new URL(this._slave.config.get("slave.master_url")); + let url = new URL(this._slave.config.get("slave.controller_url")); url.pathname += "api/upload-export"; url.searchParams.set("mod_pack_id", this.activeModPack.id); let response = await phin({ @@ -1081,7 +1081,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " "); core: { ca: this._slave.tlsCa }, headers: { "Content-Type": "application/zip", - "x-access-token": this._slave.config.get("slave.master_token"), + "x-access-token": this._slave.config.get("slave.controller_token"), }, }); if (response.statusCode !== 200) { diff --git a/packages/slave/src/InstanceConnection.js b/packages/slave/src/InstanceConnection.js index 74aa12c4..41a6aa7f 100644 --- a/packages/slave/src/InstanceConnection.js +++ b/packages/slave/src/InstanceConnection.js @@ -18,7 +18,7 @@ class InstanceConnection extends libLink.Link { } } - async forwardRequestToMaster(message, request) { + async forwardRequestToController(message, request) { return await request.send(this.slave, message.data); } @@ -27,7 +27,7 @@ class InstanceConnection extends libLink.Link { let instanceConnection = this.slave.instanceConnections.get(instanceId); if (!instanceConnection) { // Instance is probably on another slave - return await this.forwardRequestToMaster(message, request); + return await this.forwardRequestToController(message, request); } if (request.plugin && !instanceConnection.plugins.has(request.plugin)) { @@ -43,7 +43,7 @@ class InstanceConnection extends libLink.Link { let instanceConnection = this.slave.instanceConnections.get(instanceId); if (!instanceConnection) { // Instance is probably on another slave - await this.forwardEventToMaster(message, event); + await this.forwardEventToController(message, event); return; } if (event.plugin && !instanceConnection.plugins.has(event.plugin)) { return; } @@ -51,7 +51,7 @@ class InstanceConnection extends libLink.Link { event.send(instanceConnection, message.data); } - async forwardEventToMaster(message, event) { + async forwardEventToController(message, event) { if (!this.slave.connector.hasSession) { return; } @@ -78,7 +78,7 @@ class InstanceConnection extends libLink.Link { if (this.status === "stopped") { this.slave.instanceConnections.delete(this.instanceId); } - this.forwardEventToMaster(message, event); + this.forwardEventToController(message, event); } } diff --git a/packages/slave/src/Slave.js b/packages/slave/src/Slave.js index e8dd3cc3..306c73ba 100644 --- a/packages/slave/src/Slave.js +++ b/packages/slave/src/Slave.js @@ -83,14 +83,14 @@ async function discoverInstances(instancesDir) { /** * Handles running the slave * - * Connects to the master server over the WebSocket and manages intsances. + * Connects to the controller over the WebSocket and manages intsances. * @alias module:slave/src/Slave */ class Slave extends libLink.Link { // I don't like God classes, but the alternative of putting all this state // into global variables is not much better. constructor(connector, slaveConfig, tlsCa, pluginInfos) { - super("slave", "master", connector); + super("slave", "controller", connector); libLink.attachAllMessages(this); this.pluginInfos = pluginInfos; @@ -101,7 +101,7 @@ class Slave extends libLink.Link { this.config = slaveConfig; /** - * Certificate authority used to validate TLS connections to the master. + * Certificate authority used to validate TLS connections to the controller. * @type {?string} */ this.tlsCa = tlsCa; @@ -146,12 +146,12 @@ class Slave extends libLink.Link { if (this._disconnecting) { this._disconnecting = false; this.connector.connect().catch((err) => { - logger.fatal(`Unexpected error reconnecting to master:\n${err.stack}`); + logger.fatal(`Unexpected error reconnecting to controller:\n${err.stack}`); return this.shutdown(); }); } else { - logger.fatal("Master connection was unexpectedly closed"); + logger.fatal("Controller connection was unexpectedly closed"); this.shutdown(); } }); @@ -159,7 +159,7 @@ class Slave extends libLink.Link { for (let event of ["connect", "drop", "resume", "close"]) { this.connector.on(event, () => { for (let instanceConnection of this.instanceConnections.values()) { - libLink.messages.masterConnectionEvent.send(instanceConnection, { event }); + libLink.messages.controllerConnectionEvent.send(instanceConnection, { event }); } }); } @@ -306,17 +306,17 @@ class Slave extends libLink.Link { let { instance_id, serialized_config } = message.data; let instanceInfo = this.instanceInfos.get(instance_id); if (instanceInfo) { - instanceInfo.config.update(serialized_config, true, "master"); + instanceInfo.config.update(serialized_config, true, "controller"); logger.verbose(`Updated config for ${instanceInfo.path}`, this.instanceLogMeta(instance_id, instanceInfo)); } else { instanceInfo = this.discoveredInstanceInfos.get(instance_id); if (instanceInfo) { - instanceInfo.config.update(serialized_config, true, "master"); + instanceInfo.config.update(serialized_config, true, "controller"); } else { let instanceConfig = new libConfig.InstanceConfig("slave"); - await instanceConfig.load(serialized_config, "master"); + await instanceConfig.load(serialized_config, "controller"); let instanceDir = await this._createNewInstanceDir(instanceConfig.get("instance.name")); @@ -335,7 +335,7 @@ class Slave extends libLink.Link { } // Somewhat hacky, but in the event of a lost session the status is - // resent on assigment since the master server sends an assigment + // resent on assigment since the controller sends an assigment // request for all the instances it knows should be on this slave. let instanceConnection = this.instanceConnections.get(instance_id); libLink.messages.instanceStatusChanged.send(this, { @@ -345,7 +345,7 @@ class Slave extends libLink.Link { // save a copy of the instance config let warnedOutput = { - _warning: "Changes to this file will be overwritten by the master server's copy.", + _warning: "Changes to this file will be overwritten by the controller's copy.", ...instanceInfo.config.serialize(), }; await libFileOps.safeOutputFile( @@ -601,7 +601,7 @@ class Slave extends libLink.Link { checkRequestSaveName(filename); let instanceInfo = this.getRequestInstanceInfo(instance_id); - let url = new URL(this.config.get("slave.master_url")); + let url = new URL(this.config.get("slave.controller_url")); url.pathname += `api/stream/${stream_id}`; let response = await phin({ url, method: "GET", @@ -656,13 +656,15 @@ class Slave extends libLink.Link { throw err; } - let url = new URL(this.config.get("slave.master_url")); + let url = new URL(this.config.get("slave.controller_url")); url.pathname += `api/stream/${stream_id}`; phin({ url, method: "PUT", core: { ca: this.tlsCa }, data: content, - }).catch(err => logger.error(`Error pushing save to master:\n${err.stack}`, this.instanceLogMeta(instance_id))); + }).catch(err => { + logger.error(`Error pushing save to controller:\n${err.stack}`, this.instanceLogMeta(instance_id)); + }); } async exportDataRequestHandler(message, request) { @@ -704,7 +706,7 @@ class Slave extends libLink.Link { * Discover available instances * * Looks through the instances directory for instances and updates - * the slave and master server with the new list of instances. + * the slave and controller with the new list of instances. */ async updateInstances() { this.discoveredInstanceInfos = await discoverInstances(this.config.get("slave.instances_directory")); @@ -712,7 +714,7 @@ class Slave extends libLink.Link { for (let [instanceId, instanceInfo] of this.discoveredInstanceInfos) { let instanceConnection = this.instanceConnections.get(instanceId); list.push({ - serialized_config: instanceInfo.config.serialize("master"), + serialized_config: instanceInfo.config.serialize("controller"), status: instanceConnection ? instanceConnection.status : "stopped", }); } @@ -743,7 +745,7 @@ class Slave extends libLink.Link { async prepareDisconnectRequestHandler(message, request) { for (let instanceConnection of this.instanceConnections.values()) { - await libLink.messages.prepareMasterDisconnect.send(instanceConnection); + await libLink.messages.prepareControllerDisconnect.send(instanceConnection); } this._disconnecting = true; this.connector.setClosing(); @@ -790,7 +792,7 @@ ${err.stack}` } /** - * True if the connection to the master is connected, not in the dropped + * True if the connection to the controller is connected, not in the dropped * state,and not in the process of disconnecting. * @type {boolean} */ diff --git a/packages/web_ui/src/components/App.jsx b/packages/web_ui/src/components/App.jsx index db5f64d0..20981c70 100644 --- a/packages/web_ui/src/components/App.jsx +++ b/packages/web_ui/src/components/App.jsx @@ -25,18 +25,18 @@ function ErrorCard(props) { export default function App(props) { let [connected, setConnected] = useState(false); - let [token, setToken] = useState(localStorage.getItem("master_token") || null); + let [token, setToken] = useState(localStorage.getItem("controller_token") || null); let connector = props.control.connector; function clearToken() { setToken(null); connector.token = null; - localStorage.removeItem("master_token"); + localStorage.removeItem("controller_token"); } useEffect(() => { function onConnect() { - localStorage.setItem("master_token", token); + localStorage.setItem("controller_token", token); setConnected(true); } diff --git a/packages/web_ui/src/components/MasterConfigTree.jsx b/packages/web_ui/src/components/ControllerConfigTree.jsx similarity index 69% rename from packages/web_ui/src/components/MasterConfigTree.jsx rename to packages/web_ui/src/components/ControllerConfigTree.jsx index f5a8508f..5197f8c6 100644 --- a/packages/web_ui/src/components/MasterConfigTree.jsx +++ b/packages/web_ui/src/components/ControllerConfigTree.jsx @@ -6,16 +6,16 @@ import BaseConfigTree from "./BaseConfigTree"; import ControlContext from "./ControlContext"; -export default function MasterConfigTree(props) { +export default function ControllerConfigTree(props) { let control = useContext(ControlContext); async function retrieveConfig() { - let result = await libLink.messages.getMasterConfig.send(control); + let result = await libLink.messages.getControllerConfig.send(control); return result.serialized_config; } async function setField(field, value) { - await libLink.messages.setMasterConfigField.send(control, { + await libLink.messages.setControllerConfigField.send(control, { field, value: String(value), }); @@ -30,11 +30,11 @@ export default function MasterConfigTree(props) { return; } } - await libLink.messages.setMasterConfigProp.send(control, data); + await libLink.messages.setControllerConfigProp.send(control, data); } return -

Master

+ return +

Controller

{account.hasPermission("core.log.follow") && <> Console - + } - {account.hasPermission("core.master.get_config") && } - + {account.hasPermission("core.controller.get_config") && } +
; }; diff --git a/packages/web_ui/src/components/InstanceViewPage.jsx b/packages/web_ui/src/components/InstanceViewPage.jsx index e0eb3ff3..78e7b677 100644 --- a/packages/web_ui/src/components/InstanceViewPage.jsx +++ b/packages/web_ui/src/components/InstanceViewPage.jsx @@ -78,7 +78,7 @@ export default function InstanceViewPage(props) { Instance with id {instanceId} was not found on the master server.} + description={<>Instance with id {instanceId} was not found on the controller.} type="warning" action={