mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a578719fc5 | ||
|
|
72e0b6a3b1 | ||
|
|
90a400b782 | ||
|
|
80eae94fe1 | ||
|
|
5daa492f68 | ||
|
|
b43a181bf4 | ||
|
|
a31ba31567 | ||
|
|
b03b201c20 | ||
|
|
af995428bc | ||
|
|
d79e30f9be | ||
|
|
f5228e6c2e | ||
|
|
ea77e09058 | ||
|
|
5ab4b95e3c | ||
|
|
8dc1415404 | ||
|
|
122bab303d | ||
|
|
160051fc3c | ||
|
|
500baffb2b | ||
|
|
4c77f5ac31 |
No files matched your search
@@ -101,7 +101,7 @@ jobs:
|
||||
name: clusterio_docker_image_testing
|
||||
path: .
|
||||
- name: ls
|
||||
run: ls && ls clusterio_docker_image_testing && ls /home/runner/work/factorioClusterio && ls /home/runner/work/factorioClusterio/factorioClusterio
|
||||
run: ls && ls clusterio_docker_image_testing && ls /home/runner/work/clusterio && ls /home/runner/work/clusterio/clusterio
|
||||
- name: Load docker image
|
||||
run: docker load -i clusterio_docker_image_testing
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ before_install:
|
||||
script:
|
||||
- npx lerna bootstrap --hoist --no-ci
|
||||
- node packages/lib/build_mod --source-dir packages/slave/lua/clusterio_lib --output-dir temp/test/sharedMods
|
||||
- curl -o temp/test/sharedMods/subspace_storage_1.99.8.zip -L https://github.com/clusterio/factorioClusterioMod/releases/download/1.99.6/subspace_storage_1.99.8.zip
|
||||
- curl -o temp/test/sharedMods/subspace_storage_1.99.8.zip -L https://github.com/clusterio/subspace_storage/releases/download/1.99.6/subspace_storage_1.99.8.zip
|
||||
- npx lerna run build
|
||||
- npm run-script ci-cover
|
||||
- codecov -f coverage/lcov.info
|
||||
|
||||
+3
-2
@@ -44,6 +44,7 @@
|
||||
- Added an overview of the installed plugins to the web interface.
|
||||
- Added clusterioctl command to list plugins on the master server.
|
||||
- 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
|
||||
|
||||
@@ -186,8 +187,8 @@
|
||||
- Fixed SIGINT being sent twice to Factorio server when interrupted by CTRL+C on Linux ([#217][#217]).
|
||||
- Fixed package.json incorrectly reporting the license as ISC.
|
||||
|
||||
[#217]: https://github.com/clusterio/factorioClusterio/issues/217
|
||||
[#229]: https://github.com/clusterio/factorioClusterio/issues/229
|
||||
[#217]: https://github.com/clusterio/clusterio/issues/217
|
||||
[#229]: https://github.com/clusterio/clusterio/issues/229
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
FROM node:12 as subspace_storage_builder
|
||||
RUN apt update && apt install -y git
|
||||
WORKDIR /
|
||||
RUN git clone https://github.com/clusterio/factorioClusterioMod.git
|
||||
WORKDIR /factorioClusterioMod
|
||||
RUN git checkout clusterio-2.0 \
|
||||
&& npm install \
|
||||
RUN git clone https://github.com/clusterio/subspace_storage.git
|
||||
WORKDIR /subspace_storage
|
||||
RUN npm install \
|
||||
&& node build
|
||||
|
||||
FROM node:12 as clusterio_builder
|
||||
@@ -24,7 +23,7 @@ RUN npm install \
|
||||
#RUN npm install @clusterio/plugin-subspace_storage
|
||||
#RUN npx clusteriomaster plugin add @clusterio/plugin-subspace_storage
|
||||
|
||||
COPY --from=subspace_storage_builder /factorioClusterioMod/dist/ /clusterio/sharedMods/
|
||||
COPY --from=subspace_storage_builder /subspace_storage/dist/ /clusterio/sharedMods/
|
||||
|
||||
# Build submodules (web UI, libraries, plugins etc)
|
||||
RUN npx lerna run build
|
||||
|
||||
@@ -4,20 +4,16 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
# factorioClusterio
|
||||
# Clusterio
|
||||
|
||||
Discord for development/support/play: https://discord.gg/5XuDkje
|
||||
|
||||
## Important notice
|
||||
|
||||
This is the development branch for factorioClusterio 2.0 which is currently undergoing heavy restructuring and refactoring.
|
||||
Expect plugins and existing installations to frequently break when using this branch.
|
||||
If you don't want to be an alpha tester for 2.0 please use the stable [1.2.x branch][1.2.x] or [latest stable release](https://github.com/clusterio/factorioClusterio/releases/latest).
|
||||
Clusterio 2.0 is still in alpha, however the previous stable has been abandoned and is no longer supported.
|
||||
Despite being alpha it's reasonably stable now and there's no major breakages expected before a stable release of 2.0.
|
||||
If you are starting a new cluster it's highly recommended to use the 2.0 alpha.
|
||||
|
||||
Installation instructions below are for the unstable master branch.
|
||||
Go to the page for the [1.2.x branch][1.2.x] for instructions on how to install the stable version.
|
||||
|
||||
[1.2.x]: https://github.com/clusterio/factorioClusterio/tree/1.2.x
|
||||
|
||||
### Ways to support me/the project:
|
||||
|
||||
@@ -32,17 +28,15 @@ Go to the page for the [1.2.x branch][1.2.x] for instructions on how to install
|
||||
* [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
* [Plugins](#plugins)
|
||||
* [Ubuntu setup](#ubuntu-setup)
|
||||
* [Windows setup](#windows-setup)
|
||||
* [MacOS setup](#macos-setup)
|
||||
* [Installing Plugins](#installing-plugins)
|
||||
* [Installation](#installation)
|
||||
* [Ubuntu setup](#ubuntu-setup)
|
||||
* [Windows setup](#windows-setup)
|
||||
* [MacOS setup](#macos-setup)
|
||||
* [Installing Plugins](#installing-plugins)
|
||||
* [Configure Master Server](#configure-master-server)
|
||||
* [Hosting Behind Proxy](#hosting-behind-proxy)
|
||||
* [Setting up an admin account](#setting-up-an-admin-account)
|
||||
* [Running Clusterio](#running-clusterio)
|
||||
* [Master Server](#master-server)
|
||||
* [Slaves](#slaves)
|
||||
* [Instances](#instances)
|
||||
* [Setting up remote slaves](#setting-up-remote-slaves)
|
||||
* [Setting up clusterioctl](#setting-up-clusterioctl)
|
||||
* [Common problems](#Common-problems)
|
||||
|
||||
|
||||
@@ -50,7 +44,7 @@ Go to the page for the [1.2.x branch][1.2.x] for instructions on how to install
|
||||
|
||||
Clusterio is a clustered Factorio server manager that provides the tooling for implementing cross server interactions in Factorio.
|
||||
It was previously best known for implementing cross server transfer and cloud storage of items via teleporter chests.
|
||||
But this functionality has been pulled out of Clusterio into its own plugin for Clusterio named [Subspace Storage](https://github.com/clusterio/factorioClusterioMod).
|
||||
But this functionality has been pulled out of Clusterio into its own plugin for Clusterio named [Subspace Storage](https://github.com/clusterio/subspace_storage).
|
||||
|
||||
By itself Clusterio doesn't change the gameplay in any way, you could even use Clusterio to manage completely vanilla Factorio servers.
|
||||
Plugins do the work of modding in the visible changes into the game, see the [Plugins section](#plugins) for ready made plugins you can install into a Clusterio cluster.
|
||||
@@ -76,7 +70,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.
|
||||
- [Subspace Storage](https://github.com/clusterio/factorioClusterioMod): Provide shared storage that can transport items between servers via teleport chests.
|
||||
- [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.
|
||||
|
||||
There's also plugins developed and maintained by the community:
|
||||
@@ -90,26 +84,41 @@ Want to make your own plugin?
|
||||
Check out the documentation on [Writing Plugins](/docs/writing-plugins.md) for where to start.
|
||||
|
||||
|
||||
## Ubuntu setup
|
||||
## Installation
|
||||
|
||||
**Warning**: These instructions are for the unstable master version and is not recommended for use, see [the 1.2.x branch][1.2.x] for how to install the stable version.
|
||||
Clusterio runs on Node.js v12 and up, it's distributed via npm and comes with a guided install script.
|
||||
If you alread have a recent Node.js installed you can set it up in a new directory with.
|
||||
|
||||
Clusterio runs on Node.js v12 and up.
|
||||
Node.js itself is not supported on EOL Ubuntu releases so make sure you're on a recent release of Ubuntu.
|
||||
npm init "@clusterio"
|
||||
|
||||
Master and all slaves:
|
||||
Otherwise see below for OS specific instructions.
|
||||
|
||||
wget -qO - https://deb.nodesource.com/setup_12.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
mkdir clusterio
|
||||
cd clusterio
|
||||
npm init -y
|
||||
npm install @clusterio/master @clusterio/slave @clusterio/ctl
|
||||
wget -O factorio.tar.gz https://www.factorio.com/get-download/latest/headless/linux64
|
||||
tar -xf factorio.tar.gz
|
||||
|
||||
downloads and installs nodejs, git and clusterio.
|
||||
To specify a version, change "latest" in the link to a version number like 0.14.21.
|
||||
### Ubuntu setup
|
||||
|
||||
1. Install Node.js v12 or higher.
|
||||
For 20.04 LTS or below the version of Node.js provided by the Ubuntu repos are too old and you will have to use the nodesource PPA, otherwise you may skip the first line.
|
||||
|
||||
wget -qO - https://deb.nodesource.com/setup_14.x | sudo -E bash -
|
||||
sudo apt install nodejs
|
||||
|
||||
2. Create a new directory and run the Clusterio installer:
|
||||
|
||||
mkdir clusterio
|
||||
cd clusterio
|
||||
npm init "@clusterio"
|
||||
|
||||
Make sure to note down the admin authentication token it provides at the end as you will need it later.
|
||||
|
||||
3. If you chose to use local factorio directory for the Factorio installation then download the headless build of Factorio and unpack it:
|
||||
|
||||
wget -O factorio.tar.gz https://www.factorio.com/get-download/latest/headless/linux64
|
||||
tar -xf factorio.tar.gz
|
||||
|
||||
To specify a version of Factorio to download replace "latest" in the URL with a version number like "1.0.0".
|
||||
|
||||
4. Optionally copy the generated systemd service files in `systemd` folder to `/etc/systemd/system/`.
|
||||
|
||||
|
||||
**Ubuntu with Docker**
|
||||
|
||||
@@ -119,80 +128,50 @@ If you need it open an issue about it.
|
||||
<!--
|
||||
Clusterio has *very* limited support for using docker.
|
||||
|
||||
sudo docker build -t clusterio --no-cache --force-rm factorioClusterio
|
||||
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 slave -e MODE=slave -e INSTANCE=world1 -v /srv/clusterio/instances:/factorioClusterio/instances -p 1235:34167 -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
|
||||
|
||||
The -v flag is used to specify the instance directory.
|
||||
Your instances (save files etc) will be stored there.
|
||||
-->
|
||||
|
||||
## Windows setup
|
||||
### Windows setup
|
||||
|
||||
**Warning**: These instructions are for the unstable master version and is not recommended for use, see [the 1.2.x branch][1.2.x] for how to install the stable version.
|
||||
1. Download and install the latest LTS release from http://nodejs.org.
|
||||
|
||||
**Requirements**
|
||||
2. Create a new empty directory for the installation and navigate into it.
|
||||
Open a PowerShell window in this new directory by Shift+Right clicking inside it and choosing "Open PowerShell window here" and then run the following command.
|
||||
|
||||
download and install nodeJS 12 from http://nodejs.org.
|
||||
Clusterio runs on Node.js v12 and up.
|
||||
npm init "@clusterio"
|
||||
|
||||
**Master**
|
||||
Make sure to note down the admin authentication token it provides at the end as you will need it later.
|
||||
|
||||
1. Open PowerShell or Command prompt in the directory you want to install to and run the following commands.
|
||||
3. If you chose to use local factorio directory for the Factorio installation then download the Windows 64-bit zip package from https://www.factorio.com/download and extract it to the `factorio` folder in your clusterio installation folder.
|
||||
|
||||
|
||||
### MacOS Setup
|
||||
|
||||
1. Install the latest Node.js LTS release from http://nodejs.org or use brew (`brew install node`).
|
||||
|
||||
2. Open Terminal or Command prompt in the directory you want to install to and run the following commands.
|
||||
|
||||
mkdir clusterio
|
||||
cd clusterio
|
||||
npm init -y
|
||||
npm install @clusterio/master @clusterio/slave @clusterio/ctl
|
||||
npm init "@clusterio"
|
||||
|
||||
2. Obtain Factorio by either of these two methods:
|
||||
Make sure to note down the admin authentication token it provides at the end as you will need it later.
|
||||
|
||||
- Via the stand alone version on from their website
|
||||
3. If you chose to use local factorio directory for the Factorio installation you will need to obtain and copy a mac version of Factorio and unpack it to to the `factorio` folder in your clusterio installation folder.
|
||||
|
||||
1. Create a new folder named "factorio" in the the factorioClusterio folder.
|
||||
|
||||
2. Download the MS Windows (64-bit zip package) from https://www.factorio.com/download .
|
||||
### Installing Plugins
|
||||
|
||||
3. Open the zip file and drag the folder called "Factorio_x.y.z" into the factorio folder created in step 1.
|
||||
|
||||
- Via steam installation
|
||||
|
||||
1. Create a new folder named "factorio" in the the factorioClusterio folder.
|
||||
|
||||
2. Locate the game files by right clicking the game in steam, selecting properties, then Local Files, then Browse local files.
|
||||
|
||||
3. Go to the parent folder of the folder that Steam opened and copy the Factorio folder into the factorio folder created in step 1.
|
||||
|
||||
## MacOS Setup
|
||||
|
||||
**Requirements**
|
||||
|
||||
Download and install nodeJS 12 from http://nodejs.org or brew (`brew install node`).
|
||||
Clusterio runs on Node.js v12 and up.
|
||||
|
||||
1. Open Terminal or Command prompt in the directory you want to install to and run the following commands.
|
||||
|
||||
```bash
|
||||
mkdir clusterio
|
||||
cd clusterio
|
||||
npm init -y
|
||||
npm install @clusterio/master @clusterio/slave @clusterio/ctl
|
||||
```
|
||||
|
||||
2. Obtain Factorio:
|
||||
|
||||
Install Factorio and copy the factorio.app/Contents in your clusterio install folder as factorio.
|
||||
If you installed factorio on your mac you can run
|
||||
```bash
|
||||
cp -r /Applications/factorio.app/Contents/ factorio
|
||||
```
|
||||
|
||||
## Installing Plugins
|
||||
|
||||
Installing plugins to make them work with Clusterio consists of two steps.
|
||||
First install the package via npm, for example
|
||||
For well known plugins you can select them during installation and no further steps are necessary to make them work.
|
||||
Installing plugins that are not offered by the installer consists of two steps.
|
||||
First install the package the plugin is provided by via npm, for example
|
||||
|
||||
npm install @clusterio/plugin-subspace_storage
|
||||
|
||||
@@ -202,7 +181,7 @@ Then tell clusterio that this plugin exists by adding it as a plugin.
|
||||
|
||||
This adds it to the default `plugin-list.json` file which in the shared folder setup is loaded by master, 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.
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
@@ -214,6 +193,11 @@ You can change the port used with the command
|
||||
|
||||
npx clusteriomaster config set master.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/
|
||||
|
||||
If you plan to make your cluster available externally set the address
|
||||
that it will be accessible under with, for example
|
||||
|
||||
@@ -226,67 +210,30 @@ You can list the config of the master server with the `npx clusteriomaster confi
|
||||
See the [readme for @clusterio/master](/packages/master/README.md) for more information.
|
||||
|
||||
|
||||
### Setting up an admin account
|
||||
|
||||
Before you can manage the cluster you need to bootstrap an admin account for it.
|
||||
Replace `<username>` with your Factorio username (do not make up a new username here).
|
||||
|
||||
npx clusteriomaster bootstrap create-admin <username>
|
||||
npx clusteriomaster bootstrap create-ctl-config <username>
|
||||
|
||||
The first command creates a user account with the given name and promotes it to a cluster admin.
|
||||
The second one sets up a `config-control.json` config for clusterioctl to connect to the master server under the given user account.
|
||||
|
||||
|
||||
## Running Clusterio
|
||||
|
||||
After following the installation and master configuration instructions you can use the following commands to run 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
### Master Server
|
||||
## Setting up remote slaves
|
||||
|
||||
It's necessary to run the master server in order for anything to work.
|
||||
Once you've completed the setup run the following command to start it up:
|
||||
|
||||
npx clusteriomaster run
|
||||
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.
|
||||
The URL is the same as what is needed to connect to the web interface, and the athentication 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.
|
||||
|
||||
|
||||
### Slaves
|
||||
## Setting up clusterioctl
|
||||
|
||||
Slaves connect to the master server and are managed remotely from the master server.
|
||||
In order for slaves to connect to the master server they need a valid authentication token, you can create a slave config with a valid token with the following command.
|
||||
There's a command line interface available for Clusterio which is installed separately with the same installer as for the master 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.
|
||||
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 clusterioctl slave create-config --name Local --generate-token
|
||||
|
||||
This will write a new `config-slave.json` file in the current directory (you can change the location with the `--output` option) with the name, token and url to connect to the master server with.
|
||||
If you are making the config for a remote slave you will need to have set the `master.external_address` option to the URL the master server can be reached on.
|
||||
|
||||
You can list the config of a slave on the slave itself with the `npx clusterioslave config list` command.
|
||||
See the [readme for @clusterio/slave](/packages/slave/README.md) for more information.
|
||||
|
||||
Once the config is set up run the slave with
|
||||
|
||||
npx clusterioslave run
|
||||
|
||||
|
||||
### Instances
|
||||
|
||||
Instances are created, managed and started from the master server.
|
||||
For now the only interface available is the `clusterioctl` command line tool included in Clusterio.
|
||||
You can run this tool from any slave, or the master server without having to set up a config, if you want to manage the cluster from somewhere else you will need to set the `control.master_url` and `control.master_token` options with the `node clusterioctl control-config set` command:
|
||||
|
||||
The basic operations to start a new instance is the following
|
||||
|
||||
npx clusterioctl instance create "My instance"
|
||||
npx clusterioctl instance assign "My instance" "Local"
|
||||
npx clusterioctl instance start "My instance"
|
||||
|
||||
The first line creates the instance configuration on the master server.
|
||||
The second assigns the instance to a slave which creates the instance directory and files needed to run the instance on the given slave.
|
||||
The third line starts the instance, which creates a new save if there are no save games present.
|
||||
|
||||
There are many more commands available with clusterioctl.
|
||||
See the [Managing a Cluster](/docs/managing-a-cluster.md) document or `npx clusterioctl --help` for a full list of them.
|
||||
npx clusteriomaster bootstrap generate-user-token <username>
|
||||
|
||||
|
||||
## Common problems
|
||||
|
||||
+31
-9
@@ -41,7 +41,7 @@ If you already cloned the main GitHub repository you can change your clone to po
|
||||
|
||||
To keep your local repository up to to date with the main repository add the main repository as a remote.
|
||||
|
||||
git remote add upstream https://github.com/clusterio/factorioClusterio
|
||||
git remote add upstream https://github.com/clusterio/clusterio
|
||||
|
||||
After this running `git fetch upstream` will get the updated branches from the main repository.
|
||||
Do not run `git pull upstream` it will mess thing up!
|
||||
@@ -54,25 +54,47 @@ In order to get the development environment up and running you will need to run
|
||||
|
||||
npm install
|
||||
npx lerna bootstrap --hoist
|
||||
npx lerna run build
|
||||
|
||||
This installs dependencies needed by tests and links the packages up so they work from the git work tree.
|
||||
To start a cluster from the repo, substitute the commands in the normal readme as follows:
|
||||
To start a cluster from the repo you will first need to initialize it, this can be done using the installer:
|
||||
|
||||
node packages/create --dev
|
||||
|
||||
To add plugins to use in the development environment use
|
||||
|
||||
node packages/ctl plugin add ./path/to/plugin
|
||||
|
||||
It's important that the path starts with `./`.
|
||||
The `plugins/` directory contains the core plugins for the project and can be added using the above mentioned command.
|
||||
|
||||
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 clusterioslave -> node packages/slave
|
||||
npx clusterioctl -> node packages/ctl
|
||||
|
||||
For web development on the master there are also the following flags:
|
||||
Note that to use `clusterioctl` you will have to create a control config first:
|
||||
|
||||
`--dev` - Start the master with webpack hot reloading of core components
|
||||
node packages/master 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.
|
||||
|
||||
For web development on the master there are also the following flags.
|
||||
|
||||
`--dev` - Recompile the `web_ui` package on the fly providing live reloading of it.
|
||||
|
||||
`--dev-plugin [name]` - Recompile the web module for the given plugin on the fly proving live reloading of it.
|
||||
|
||||
These options can be combined and multiple plugins can be actived for dev mode.
|
||||
Note that webpack is configured to delete the web interface build when using these options, so you will have to run `npx lerna run build` before you start the master without these flags again.
|
||||
|
||||
`--dev-plugin [name]` - Start the master with hot reloading of a plugin
|
||||
|
||||
### Starting a Feature Branch
|
||||
|
||||
Development is done exclusively in feature branches.
|
||||
This means the first thing to do before starting any development at all is to make a new branch starting from the master or 1.2.x branch of the main repository.
|
||||
To do this check out that branch from the main repository (substitute master for 1.2.x if you're working on that branch).
|
||||
This means the first thing to do before starting any development at all is to make a new branch starting from the master branch of the main repository.
|
||||
To do this check out that branch from the main repository.
|
||||
|
||||
git fetch upstream
|
||||
git checkout upstream/master
|
||||
@@ -113,7 +135,7 @@ If there are more changes you want to have merged or mistakes you need to fix yo
|
||||
|
||||
Until your feature branch is merged you can edit it as you see fit by using the rebase tool.
|
||||
If your feature branch has been merged however it's final and you will have to start a new feature branch and submit that in a new pull request.
|
||||
The base usage of rebase assuming you are checked out on your feature branch is the following command (substitute master with 1.2.x if your feature branch is based on that)
|
||||
The base usage of rebase assuming you are checked out on your feature branch is the following command
|
||||
|
||||
git rebase -i upstream/master
|
||||
|
||||
@@ -132,7 +154,7 @@ If you have a pull request that has not yet been merged submitted for this featu
|
||||
### Resolving Merge Conflicts
|
||||
|
||||
The best way to resolve merge conflicts in feature braches is to rebase it on top of the updated upstream.
|
||||
Run the following commands (substitute master with 1.2.x if your feature branch is based on that)
|
||||
Run the following commands
|
||||
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@
|
||||
"plugins/*",
|
||||
"test"
|
||||
],
|
||||
"version": "2.0.0-alpha.7"
|
||||
"version": "2.0.0-alpha.8"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Clusterio installer
|
||||
|
||||
Installer for Clusterio.
|
||||
|
||||
See [the Clusterio README.md](https://github.com/clusterio/clusterio#readme) the for installation guide.
|
||||
Executable
+529
@@ -0,0 +1,529 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
"use strict";
|
||||
const child_process = require("child_process");
|
||||
const fs = require("fs-extra");
|
||||
const inquirer = require("inquirer");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const phin = require("phin");
|
||||
const stream = require("stream");
|
||||
const util = require("util");
|
||||
const yargs = require("yargs");
|
||||
|
||||
const { levels, logger, setLogLevel } = require("./logging");
|
||||
let dev = false;
|
||||
const scriptExt = process.platform === "win32" ? ".cmd" : "";
|
||||
|
||||
|
||||
const availablePlugins = [
|
||||
{ name: "Global Chat", value: "@clusterio/plugin-global_chat" },
|
||||
{ name: "Player Auth", value: "@clusterio/plugin-player_auth" },
|
||||
{ name: "Research Sync", value: "@clusterio/plugin-research_sync" },
|
||||
{ name: "Statistics Exporter", value: "@clusterio/plugin-statistics_exporter" },
|
||||
{ name: "Subspace Storage", value: "@clusterio/plugin-subspace_storage" },
|
||||
|
||||
// Comunity plugins
|
||||
{ name: "Discord Bridge", value: "@hornwitser/discord_bridge" },
|
||||
{ name: "Server Select", value: "@hornwitser/server_select" },
|
||||
];
|
||||
|
||||
const factorioLocations = {
|
||||
win32: [
|
||||
"C:\\Program Files\\Factorio",
|
||||
"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Factorio",
|
||||
],
|
||||
darwin: [
|
||||
"/Applications/factorio.app/Contents",
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
class LineSplitter extends stream.Transform {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this._partial = null;
|
||||
}
|
||||
|
||||
_transform(chunk, encoding, callback) {
|
||||
if (this._partial) {
|
||||
chunk = Buffer.concat([this._partial, chunk]);
|
||||
this._partial = null;
|
||||
}
|
||||
|
||||
while (chunk.length) {
|
||||
let end = chunk.indexOf("\n");
|
||||
if (end === -1) {
|
||||
this._partial = chunk;
|
||||
break;
|
||||
}
|
||||
|
||||
let next = end + 1;
|
||||
// Eat carriage return as well if present
|
||||
if (end >= 1 && chunk[end-1] === "\r".charCodeAt(0)) {
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
let line = chunk.slice(0, end);
|
||||
chunk = chunk.slice(next);
|
||||
this.push(line);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
_flush(callback) {
|
||||
if (this._partial) {
|
||||
this.push(this._partial);
|
||||
this._partial = null;
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
class InstallError extends Error { }
|
||||
|
||||
|
||||
async function execFile(cmd, args) {
|
||||
logger.verbose(`executing ${cmd} ${args.join(" ")}`);
|
||||
const asyncExec = util.promisify(child_process.execFile);
|
||||
return new Promise((resolve, reject) => {
|
||||
let child = child_process.execFile(cmd, args, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({ stdout, stderr });
|
||||
}
|
||||
});
|
||||
let stdout = new LineSplitter({ readableObjectMode: true });
|
||||
stdout.on("data", line => { logger.verbose(line.toString()); });
|
||||
child.stdout.pipe(stdout);
|
||||
let stderr = new LineSplitter({ readableObjectMode: true });
|
||||
stderr.on("data", line => { logger.verbose(`err: ${line.toString()}`); });
|
||||
child.stderr.pipe(stderr);
|
||||
});
|
||||
}
|
||||
|
||||
async function execMaster(args) {
|
||||
if (dev) {
|
||||
return await execFile("node", [path.join("packages", "master"), ...args]);
|
||||
}
|
||||
return await execFile(path.join("node_modules", ".bin", `clusteriomaster${scriptExt}`), args);
|
||||
}
|
||||
|
||||
async function execSlave(args) {
|
||||
if (dev) {
|
||||
return await execFile("node", [path.join("packages", "slave"), ...args]);
|
||||
}
|
||||
return await execFile(path.join("node_modules", ".bin", `clusterioslave${scriptExt}`), args);
|
||||
}
|
||||
|
||||
function validateSlaveToken(token) {
|
||||
let parts = token.split(".");
|
||||
if (parts.length !== 3) {
|
||||
throw new InstallError("Invalid token");
|
||||
}
|
||||
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(Buffer.from(parts[1], "base64"));
|
||||
} catch (err) {
|
||||
throw new InstallError("Invalid token");
|
||||
}
|
||||
|
||||
if (parsed.aud !== "slave" || !Number.isInteger(parsed.slave)) {
|
||||
throw new InstallError("Invalid token");
|
||||
}
|
||||
}
|
||||
|
||||
async function validateInstallDir() {
|
||||
let entries = new Set(await fs.readdir("."));
|
||||
if (entries.size) {
|
||||
if (!entries.has("package.json")) {
|
||||
throw new InstallError("Refusing to install to non-empty directory");
|
||||
}
|
||||
|
||||
let packageData;
|
||||
try {
|
||||
packageData = JSON.parse(await fs.readFile("package.json"));
|
||||
} catch (err) {
|
||||
throw new InstallError(`Failed to read package.json: ${err.message}`);
|
||||
}
|
||||
if (packageData.name !== "clusterio-install" || !packageData.private) {
|
||||
throw new InstallError("Refusing to run on non-clusterio installation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function installClusterio(mode, plugins) {
|
||||
try {
|
||||
await fs.writeFile("package.json", JSON.stringify({
|
||||
name: "clusterio-install",
|
||||
private: true,
|
||||
}, null, 2), { flag: "wx" });
|
||||
} catch (err) {
|
||||
if (err.code !== "EEXIST") {
|
||||
throw new InstallError(`Failed to write package.json: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
let components = [];
|
||||
if (["standalone", "master"].includes(mode)) {
|
||||
components.push("@clusterio/master");
|
||||
}
|
||||
if (["standalone", "slave"].includes(mode)) {
|
||||
components.push("@clusterio/slave");
|
||||
}
|
||||
if (mode === "ctl") {
|
||||
components.push("@clusterio/ctl");
|
||||
}
|
||||
|
||||
logger.info(`Please wait, installing ${mode}`);
|
||||
try {
|
||||
await execFile(`npm${scriptExt}`, ["install", ...components, ...plugins]);
|
||||
} catch (err) {
|
||||
throw new InstallError(`Failed to install: ${err.message}`);
|
||||
}
|
||||
|
||||
if (plugins.length) {
|
||||
logger.info("Setting up plugins");
|
||||
let pluginList;
|
||||
try {
|
||||
pluginList = new Map(JSON.parse(await fs.readFile("plugin-list.json")));
|
||||
} catch (err) {
|
||||
if (err.code === "ENOENT") {
|
||||
pluginList = new Map();
|
||||
} else {
|
||||
throw new InstallError(`Error loading plugin-list.json: ${err.message}`);
|
||||
}
|
||||
}
|
||||
for (let plugin of plugins) {
|
||||
if (!pluginList.has(plugin)) {
|
||||
// eslint-disable-next-line node/global-require
|
||||
let pluginInfo = require(require.resolve(path.posix.join(plugin, "info"), { paths: [process.cwd()] }));
|
||||
pluginList.set(pluginInfo.name, plugin);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await fs.writeFile("plugin-list.json", JSON.stringify([...pluginList], null, 4));
|
||||
} catch (err) {
|
||||
throw new InstallError(`Error writing plugin-list.json: ${err.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeScripts(mode) {
|
||||
if (["standalone", "master"].includes(mode)) {
|
||||
if (process.platform === "win32") {
|
||||
await fs.writeFile(
|
||||
"run-master.cmd",
|
||||
"@echo off\n.\\node_modules\\.bin\\clusteriomaster.cmd run\n"
|
||||
);
|
||||
} else {
|
||||
await fs.writeFile(
|
||||
"run-master.sh",
|
||||
"#!/bin/sh\nexec ./node_modules/.bin/clusteriomaster run\n",
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
await fs.outputFile(
|
||||
"systemd/clusteriomaster.service",
|
||||
`[Unit]
|
||||
Description=Clusterio Master
|
||||
|
||||
[Service]
|
||||
User=${os.userInfo().username}
|
||||
Group=nogroup
|
||||
WorkingDirectory=${process.cwd()}
|
||||
KillMode=mixed
|
||||
KillSignal=SIGINT
|
||||
ExecStart=${process.cwd()}/node_modules/.bin/clusteriomaster run --log-level=warn
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
if (["standalone", "slave"].includes(mode)) {
|
||||
if (process.platform === "win32") {
|
||||
await fs.writeFile(
|
||||
"run-slave.cmd",
|
||||
"@echo off\n.\\node_modules\\.bin\\clusterioslave.cmd run\n"
|
||||
);
|
||||
} else {
|
||||
await fs.writeFile(
|
||||
"run-slave.sh",
|
||||
"#!/bin/sh\nexec ./node_modules/.bin/clusterioslave run\n",
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
await fs.outputFile(
|
||||
"systemd/clusterioslave.service",
|
||||
`[Unit]
|
||||
Description=Clusterio Slave
|
||||
|
||||
[Service]
|
||||
User=${os.userInfo().username}
|
||||
Group=nogroup
|
||||
WorkingDirectory=${process.cwd()}
|
||||
KillMode=mixed
|
||||
KillSignal=SIGINT
|
||||
ExecStart=${process.cwd()}/node_modules/.bin/clusterioslave run --log-level=warn
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function inquirerMissingArgs(args) {
|
||||
let answers = {};
|
||||
if (args.mode) { answers.mode = args.mode; }
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "mode",
|
||||
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: "Slave only", value: "slave" },
|
||||
{ name: "Ctl only", value: "ctl" },
|
||||
{ name: "Plugins only", value: "plugins" },
|
||||
],
|
||||
},
|
||||
], answers);
|
||||
|
||||
if (["standalone", "master"].includes(answers.mode)) {
|
||||
if (args.admin) { answers.admin = args.admin; }
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "admin",
|
||||
message: "Admin account name",
|
||||
validate: input => {
|
||||
if (!input) {
|
||||
return "May not be empty";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
], answers);
|
||||
}
|
||||
|
||||
if (answers.mode === "slave") {
|
||||
if (args.slaveName) { answers.slaveName = args.slaveName; }
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "slaveName",
|
||||
message: "Name of slave",
|
||||
},
|
||||
], answers);
|
||||
}
|
||||
|
||||
if (["slave", "ctl"].includes(answers.mode)) {
|
||||
if (args.masterUrl) { answers.masterUrl = args.masterUrl; }
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "masterUrl",
|
||||
message: "Master server URL",
|
||||
},
|
||||
], answers);
|
||||
|
||||
if (args.masterToken) { answers.masterToken = args.masterToken; }
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "masterToken",
|
||||
message: "Master authentication Token",
|
||||
},
|
||||
], answers);
|
||||
}
|
||||
|
||||
if (answers.mode === "slave") {
|
||||
validateSlaveToken(answers.masterToken);
|
||||
}
|
||||
|
||||
if (["standalone", "slave"].includes(answers.mode)) {
|
||||
let myIp;
|
||||
if (args.publicAddress) {
|
||||
answers.publicAddress = args.publicAddress;
|
||||
} else {
|
||||
try {
|
||||
let result = await phin("https://api.ipify.org/");
|
||||
myIp = result.body.toString();
|
||||
} catch (err) { /* ignore */ }
|
||||
}
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "publicAddress",
|
||||
message: "Public DNS/IP address of this server",
|
||||
default: myIp,
|
||||
},
|
||||
], answers);
|
||||
|
||||
if (args.factorioDir) { answers.factorioDir = args.factorioDir; }
|
||||
let locations = factorioLocations[process.platform] || [];
|
||||
let foundLocations = [];
|
||||
for (let location of locations) {
|
||||
if (await fs.pathExists(path.join(location, "data", "changelog.txt"))) {
|
||||
foundLocations.push(location);
|
||||
}
|
||||
}
|
||||
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "factorioDir",
|
||||
message: "Path to Factorio installation",
|
||||
choices: [
|
||||
...foundLocations.map(location => ({ name: `${location} (auto detected)`, value: location })),
|
||||
{ name: "Use local factorio directory, you must copy an installation to it", value: "factorio" },
|
||||
{ name: "Provide path manually", value: null },
|
||||
],
|
||||
},
|
||||
], answers);
|
||||
|
||||
if (answers.factorioDir === null) {
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "factorioDir",
|
||||
message: "Path to Factorio installation",
|
||||
askAnswered: true,
|
||||
},
|
||||
], answers);
|
||||
} else if (answers.factorioDir === "factorio") {
|
||||
await fs.ensureDir("factorio");
|
||||
}
|
||||
}
|
||||
|
||||
if (dev) { answers.plugins = []; }
|
||||
answers = await inquirer.prompt([
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "plugins",
|
||||
message: "Plugins to install",
|
||||
choices: availablePlugins,
|
||||
pageSize: 20,
|
||||
},
|
||||
], answers);
|
||||
|
||||
return answers;
|
||||
}
|
||||
|
||||
|
||||
async function main() {
|
||||
const args = yargs
|
||||
.option("log-level", {
|
||||
nargs: 1, describe: "Log level to print to stdout", default: "info",
|
||||
choices: ["none"].concat(Object.keys(levels)), type: "string",
|
||||
})
|
||||
.option("dev", {
|
||||
nargs: 0, describe: "Initialize development repository", hidden: true, default: false, type: "boolean",
|
||||
})
|
||||
.option("mode", {
|
||||
nargs: 1, describe: "Operating mode to install",
|
||||
choices: ["standalone", "master", "slave", "ctl", "plugins"],
|
||||
})
|
||||
.option("admin", {
|
||||
nargs: 1, describe: "Admin account name [standalone/master]", 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("master-token", {
|
||||
nargs: 1, describe: "Master authentication token [slave/ctl]", type: "string",
|
||||
})
|
||||
.option("public-address", {
|
||||
nargs: 1, describe: "DNS/IP Address to connect to this server [standalone/slave]", type: "string",
|
||||
})
|
||||
.option("factorio-dir", {
|
||||
nargs: 1, describe: "Path to Factorio installation [standalone/slave]", type: "string",
|
||||
})
|
||||
.option("plugins", {
|
||||
array: true, describe: "Plugins to install", type: "string",
|
||||
})
|
||||
.argv
|
||||
;
|
||||
|
||||
setLogLevel(args.logLevel === "none" ? -1 : levels[args.logLevel]);
|
||||
dev = args.dev;
|
||||
|
||||
if (!dev) {
|
||||
await validateInstallDir();
|
||||
}
|
||||
|
||||
let answers = await inquirerMissingArgs(args);
|
||||
logger.verbose(JSON.stringify(answers));
|
||||
|
||||
if (!dev) {
|
||||
await installClusterio(answers.mode, answers.plugins);
|
||||
}
|
||||
|
||||
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]);
|
||||
adminToken = result.stdout.split("\n").slice(-2)[0];
|
||||
}
|
||||
|
||||
if (answers.mode === "standalone") {
|
||||
logger.info("Setting up slave");
|
||||
await execSlave(["config", "set", "slave.name", "local"]);
|
||||
|
||||
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]);
|
||||
let slaveToken = result.stdout.split("\n").slice(-2)[0];
|
||||
|
||||
await execSlave(["config", "set", "slave.master_token", slaveToken]);
|
||||
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;
|
||||
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.factorio_directory", answers.factorioDir]);
|
||||
}
|
||||
|
||||
if (!dev && ["standalone", "master", "slave"].includes(answers.mode)) {
|
||||
logger.info("Writing run scripts");
|
||||
await writeScripts(answers.mode);
|
||||
}
|
||||
|
||||
/* eslint-disable no-console */
|
||||
console.log(`Successfully installed ${answers.mode}`);
|
||||
if (adminToken) {
|
||||
console.log(`Admin authentication token: ${adminToken}`);
|
||||
}
|
||||
/* eslint-enable no-console */
|
||||
}
|
||||
|
||||
if (module === require.main) {
|
||||
main().catch(err => {
|
||||
if (err instanceof InstallError) {
|
||||
logger.error(err.message);
|
||||
} else {
|
||||
logger.fatal(`
|
||||
+------------------------------------------------------------+
|
||||
| Unexpected error occured installing clusterio, please |
|
||||
| report it to https://github.com/clusterio/clusterio/issues |
|
||||
+------------------------------------------------------------+
|
||||
${err.stack}`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* eslint-disable no-console */
|
||||
"use strict";
|
||||
const chalk = require("chalk");
|
||||
|
||||
const levels = Object.freeze({
|
||||
fatal: 0,
|
||||
error: 1,
|
||||
warn: 2,
|
||||
audit: 3,
|
||||
info: 4,
|
||||
verbose: 6,
|
||||
});
|
||||
|
||||
const colors = {
|
||||
fatal: "inverse red",
|
||||
error: "bold redBright",
|
||||
warn: "bold yellowBright",
|
||||
audit: "bold greenBright",
|
||||
info: "bold blueBright",
|
||||
verbose: "bold grey",
|
||||
};
|
||||
|
||||
let maxLogLevel = levels.info;
|
||||
const logger = {};
|
||||
for (let [name, level] of Object.entries(levels)) {
|
||||
// eslint-disable-next-line no-loop-func
|
||||
logger[name] = message => {
|
||||
if (level > maxLogLevel) {
|
||||
return;
|
||||
}
|
||||
let style = chalk;
|
||||
for (let part of colors[name].split(" ")) {
|
||||
style = style[part];
|
||||
}
|
||||
if (["fatal", "error"].includes(name)) {
|
||||
console.error(`${style(name)} ${message}`);
|
||||
} else if (["warn"].includes(name)) {
|
||||
console.warn(`${style(name)} ${message}`);
|
||||
} else {
|
||||
console.log(`${style(name)} ${message}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
colors,
|
||||
levels,
|
||||
setLogLevel: (level) => { maxLogLevel = level; },
|
||||
logger,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@clusterio/create",
|
||||
"description": "Installer for clusterio",
|
||||
"author": "Hornwitser",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"main": "create.js",
|
||||
"bin": {
|
||||
"clusteriocreate": "./create.js"
|
||||
},
|
||||
"keywords": [
|
||||
"factorio",
|
||||
"clusterio"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"inquirer": "^8.1.0",
|
||||
"phin": "^3.5.1",
|
||||
"yargs": "^14.2.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
@@ -88,4 +88,4 @@ Lists up all configuration entries with their currently configured values.
|
||||
|
||||
[Managing a cluster](/docs/managing-a-cluster.md) for the available commands used for managing a cluster.
|
||||
|
||||
[The Clusterio repository](https://github.com/clusterio/factorioClusterio) for instructions on how to set up a cluster.
|
||||
[The Clusterio repository](https://github.com/clusterio/clusterio) for instructions on how to set up a cluster.
|
||||
+4
-4
@@ -1185,10 +1185,10 @@ I version of clusterio. Expect things to break. I
|
||||
startControl().catch(err => {
|
||||
if (!(err instanceof libErrors.StartupError)) {
|
||||
logger.fatal(`
|
||||
+----------------------------------------------------------------+
|
||||
| Unexpected error occured while starting control, please report |
|
||||
| it to https://github.com/clusterio/factorioClusterio/issues |
|
||||
+----------------------------------------------------------------+
|
||||
+------------------------------------------------------------+
|
||||
| Unexpected error occured while starting control, please |
|
||||
| report it to https://github.com/clusterio/clusterio/issues |
|
||||
+------------------------------------------------------------+
|
||||
${err.stack}`
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Clusterio command line management tool",
|
||||
"author": "Hornwitser",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"main": "ctl.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
@@ -18,7 +18,7 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"as-table": "^1.0.31",
|
||||
"fs-extra": "^8.1.0",
|
||||
"phin": "^3.5.1",
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
This package contains functionality shared between master, slave, ctl and/or plugins of Clusterio.
|
||||
|
||||
See [the Clusterio repository](https://github.com/clusterio/factorioClusterio) for more information on Clusterio.
|
||||
See [the Clusterio repository](https://github.com/clusterio/clusterio) for more information on Clusterio.
|
||||
@@ -90,7 +90,16 @@ async function loadFile(server, modVersions, modPath) {
|
||||
}
|
||||
}
|
||||
|
||||
let zip = await loadZip(server, modVersions, mod);
|
||||
let zip;
|
||||
try {
|
||||
zip = await loadZip(server, modVersions, mod);
|
||||
} catch (err) {
|
||||
if (err.code === "ENOENT") {
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
let file = zip.file(filePath);
|
||||
if (!file) {
|
||||
return null;
|
||||
@@ -310,7 +319,15 @@ async function exportLocale(server, modVersions, modOrder, languageCode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let zip = await loadZip(server, modVersions, mod);
|
||||
let zip;
|
||||
try {
|
||||
zip = await loadZip(server, modVersions, mod);
|
||||
} catch (err) {
|
||||
if (err.code === "ENOENT") {
|
||||
continue;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
for (let file of zip.file(new RegExp(`locale\\/${languageCode}\\/.*\\.cfg`))) {
|
||||
let content = await file.async("nodebuffer");
|
||||
mergeLocale(ini.parse(content.toString("utf8")));
|
||||
@@ -357,6 +374,28 @@ async function exportData(server) {
|
||||
throw new Error("No items got exported");
|
||||
}
|
||||
|
||||
// Some mod authors put leading zeros into the versions of their zip files.
|
||||
let splitter = /^(.*)_(\d+)\.(\d+)\.(\d+)\.zip?$/;
|
||||
for (let entry of await fs.readdir(server.writePath("mods"))) {
|
||||
let match = splitter.exec(entry);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let modVersion = `${match[2]}.${match[3]}.${match[4]}`;
|
||||
let normalizedVersion =
|
||||
`${Number.parseInt(match[2], 10)}.${Number.parseInt(match[3], 10)}.${Number.parseInt(match[4], 10)}`
|
||||
;
|
||||
|
||||
if (modVersion === normalizedVersion) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (modVersions.get(match[1]) === normalizedVersion) {
|
||||
modVersions.set(match[1], modVersion);
|
||||
}
|
||||
}
|
||||
|
||||
let { iconSheet, itemData } = await exportItems(server, modVersions, items);
|
||||
let locale = await exportLocale(server, modVersions, modOrder, "en");
|
||||
|
||||
|
||||
@@ -605,7 +605,11 @@ class FactorioServer extends events.EventEmitter {
|
||||
let type = line.slice(channelEnd + 1, channelEnd + 2).toString("utf-8");
|
||||
let content;
|
||||
if (type === "j") {
|
||||
content = JSON.parse(line.slice(channelEnd + 2).toString("utf-8"));
|
||||
try {
|
||||
content = JSON.parse(line.slice(channelEnd + 2).toString("utf-8"));
|
||||
} catch (err) {
|
||||
throw new Error(`Malformed JSON to ${channel}: ${line.slice(channelEnd + 2).toString("utf-8")}`);
|
||||
}
|
||||
|
||||
} else if (type === "f") {
|
||||
let fileName = line.slice(channelEnd + 2).toString("utf-8");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@clusterio/lib",
|
||||
"description": "Shared library for Clusterio",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"repository": "https://github.com/clusterio/factorioClusterio",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"repository": "https://github.com/clusterio/clusterio",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"factorio"
|
||||
|
||||
@@ -111,4 +111,4 @@ Runs the master server.
|
||||
|
||||
## See Also
|
||||
|
||||
[The Clusterio repository](https://github.com/clusterio/factorioClusterio) for instructions on how to set up a cluster.
|
||||
[The Clusterio repository](https://github.com/clusterio/clusterio) for instructions on how to set up a cluster.
|
||||
@@ -389,10 +389,10 @@ ${err.original.stack}`
|
||||
);
|
||||
} else {
|
||||
logger.fatal(`
|
||||
+---------------------------------------------------------------+
|
||||
| Unexpected error occured while starting master, please report |
|
||||
| it to https://github.com/clusterio/factorioClusterio/issues |
|
||||
+---------------------------------------------------------------+
|
||||
+------------------------------------------------------------+
|
||||
| Unexpected error occured while starting master, please |
|
||||
| report it to https://github.com/clusterio/clusterio/issues |
|
||||
+------------------------------------------------------------+
|
||||
${err.stack}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Implementation of Clusterio master server",
|
||||
"author": "Hornwitser",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"main": "master.js",
|
||||
"scripts": {
|
||||
"build": "webpack-cli --env production",
|
||||
@@ -19,7 +19,7 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"busboy": "^0.3.1",
|
||||
"compression": "^1.7.2",
|
||||
"express": "^4.16.2",
|
||||
@@ -33,7 +33,7 @@
|
||||
"yargs": "^14.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.7",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.8",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
||||
@@ -148,10 +148,10 @@ class WsServer {
|
||||
message, socket, req
|
||||
).catch(err => {
|
||||
logger.error(`
|
||||
+----------------------------------------------------------------+
|
||||
| Unexpected error occured in WebSocket handshake, please report |
|
||||
| it to https://github.com/clusterio/factorioClusterio/issues |
|
||||
+----------------------------------------------------------------+
|
||||
+------------------------------------------------------------+
|
||||
| Unexpected error occured in WebSocket handshake, please |
|
||||
| report it to https://github.com/clusterio/clusterio/issues |
|
||||
+------------------------------------------------------------+
|
||||
${err.stack}`
|
||||
);
|
||||
wsRejectedConnectionsCounter.inc();
|
||||
|
||||
@@ -259,6 +259,11 @@ async function getStream(req, res) {
|
||||
}
|
||||
|
||||
|
||||
const zipMimes = [
|
||||
"application/zip",
|
||||
"application/x-zip-compressed",
|
||||
];
|
||||
|
||||
async function uploadSave(req, res) {
|
||||
try {
|
||||
res.locals.user.checkPermission("core.instance.save.upload");
|
||||
@@ -319,7 +324,7 @@ async function uploadSave(req, res) {
|
||||
requestErrors.push("instance_id must come before files uploaded");
|
||||
}
|
||||
|
||||
if (fileMime !== "application/zip") {
|
||||
if (!zipMimes.includes(fileMime)) {
|
||||
requestErrors.push("invalid file Content-Type");
|
||||
}
|
||||
|
||||
@@ -350,7 +355,7 @@ async function uploadSave(req, res) {
|
||||
req.pipe(busboy);
|
||||
});
|
||||
|
||||
} else if (mimeType === "application/zip") {
|
||||
} else if (zipMimes.includes(mimeType)) {
|
||||
let filename = req.query.filename;
|
||||
if (typeof filename !== "string") {
|
||||
requestErrors.push("Missing or invalid filename parameter");
|
||||
|
||||
@@ -90,4 +90,4 @@ Runs the slave.
|
||||
|
||||
## See Also
|
||||
|
||||
[The Clusterio repository](https://github.com/clusterio/factorioClusterio) for instructions on how to set up a cluster.
|
||||
[The Clusterio repository](https://github.com/clusterio/clusterio) for instructions on how to set up a cluster.
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"title": "Clusterio Library (Alpha)",
|
||||
"author": "Clusterio Team",
|
||||
"homepage": "https://github.com/clusterio/factorioClusterio",
|
||||
"homepage": "https://github.com/clusterio/clusterio",
|
||||
"description": "Library for interfacing with Clusterio. Warning: work in progress alpha.",
|
||||
"additional_files": {
|
||||
"serialize.lua": ["..", "..", "modules", "clusterio", "serialize.lua"]
|
||||
|
||||
@@ -46,11 +46,14 @@ end
|
||||
-- no game.table_to_json here :(
|
||||
local function table_to_json(data)
|
||||
if type(data) == "number" then
|
||||
if data == math.huge then return "1e500" end -- Inf is not representable in JSON, but 1e500 will overflow to it.
|
||||
if data == -math.huge then return "-1e500" end
|
||||
if data ~= data then return "0" end -- NaN is not representable in JSON, treat as 0 instead.
|
||||
return string.format("%.17g", data)
|
||||
|
||||
elseif type(data) == "string" then
|
||||
data = data:gsub('([\x00-\x1f\\"])', function(match)
|
||||
return "\\x" .. string.format("%02x", match:byte())
|
||||
return "\\u00" .. string.format("%02x", match:byte())
|
||||
end)
|
||||
return '"' .. data .. '"'
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"version": "0.0.0",
|
||||
"title": "Icon exporter",
|
||||
"author": "Clusterio Team",
|
||||
"homepage": "https://github.com/clusterio/factorioClusterio",
|
||||
"homepage": "https://github.com/clusterio/clusterio",
|
||||
"description": "Exports item prototypes on stdout during the data stage."
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Implementation of Clusterio slave server",
|
||||
"author": "Hornwitser",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"main": "slave.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
@@ -18,7 +18,7 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"fs-extra": "^8.1.0",
|
||||
"phin": "^3.5.1",
|
||||
"pidusage": "^2.0.18",
|
||||
|
||||
@@ -1620,10 +1620,10 @@ class Slave extends libLink.Link {
|
||||
} catch (err) {
|
||||
setBlocking(true);
|
||||
logger.error(`
|
||||
+--------------------------------------------------------------------+
|
||||
| Unexpected error occured while shutting down slave, please report |
|
||||
| it to https://github.com/clusterio/factorioClusterio/issues |
|
||||
+--------------------------------------------------------------------+
|
||||
+------------------------------------------------------------+
|
||||
| Unexpected error occured while shutting down slave, please |
|
||||
| report it to https://github.com/clusterio/clusterio/issues |
|
||||
+------------------------------------------------------------+
|
||||
${err.stack}`
|
||||
);
|
||||
// eslint-disable-next-line node/no-process-exit
|
||||
@@ -1905,10 +1905,10 @@ ${err.original.stack}`
|
||||
|
||||
} else {
|
||||
logger.fatal(`
|
||||
+--------------------------------------------------------------+
|
||||
| Unexpected error occured while starting slave, please report |
|
||||
| it to https://github.com/clusterio/factorioClusterio/issues |
|
||||
+--------------------------------------------------------------+
|
||||
+------------------------------------------------------------+
|
||||
| Unexpected error occured while starting slave, please |
|
||||
| report it to https://github.com/clusterio/clusterio/issues |
|
||||
+------------------------------------------------------------+
|
||||
${err.stack}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Clusterio web interface implementation",
|
||||
"author": "Hornwitser",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"browser": "src/index.jsx",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
@@ -18,7 +18,7 @@
|
||||
"@ant-design/icons": "^4.2.2",
|
||||
"@babel/core": "^7.13.8",
|
||||
"@babel/preset-react": "^7.12.13",
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"antd": "^4.16.0",
|
||||
"assert": "^2.0.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import { Button, Popconfirm, Space, Table, Tooltip, Upload } from "antd";
|
||||
import { Button, List, Popconfirm, Progress, Space, Table, Tooltip, Upload } from "antd";
|
||||
import CaretLeftOutlined from "@ant-design/icons/CaretLeftOutlined";
|
||||
import LeftOutlined from "@ant-design/icons/LeftOutlined";
|
||||
|
||||
@@ -27,6 +27,7 @@ export default function SavesList(props) {
|
||||
let control = useContext(ControlContext);
|
||||
let saves = useSaves(props.instance.id);
|
||||
let [starting, setStarting] = useState(false);
|
||||
let [uploadingFiles, setUploadingFiles] = useState([]);
|
||||
|
||||
const saveTable = <Table
|
||||
size="small"
|
||||
@@ -107,6 +108,38 @@ export default function SavesList(props) {
|
||||
}}
|
||||
/>;
|
||||
|
||||
function onChange(changeEvent) {
|
||||
if (["done", "error"].includes(changeEvent.file.status)) {
|
||||
if (changeEvent.file.status === "error") {
|
||||
notifyErrorHandler("Error uploading file")(changeEvent.file.error);
|
||||
}
|
||||
|
||||
let newUploadingFiles = [...uploadingFiles];
|
||||
let index = newUploadingFiles.findIndex(f => f.uid === changeEvent.file.uid);
|
||||
if (index !== -1) {
|
||||
newUploadingFiles.splice(index, 1);
|
||||
setUploadingFiles(newUploadingFiles);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let file = {
|
||||
uid: changeEvent.file.uid,
|
||||
name: changeEvent.file.name,
|
||||
percent: changeEvent.file.percent,
|
||||
status: changeEvent.file.status,
|
||||
};
|
||||
|
||||
let newUploadingFiles = [...uploadingFiles];
|
||||
let index = newUploadingFiles.findIndex(f => f.uid === changeEvent.file.uid);
|
||||
if (index !== -1) {
|
||||
newUploadingFiles[index] = file;
|
||||
} else {
|
||||
newUploadingFiles.push(file);
|
||||
}
|
||||
setUploadingFiles(newUploadingFiles);
|
||||
}
|
||||
|
||||
let uploadProps = {
|
||||
name: "file",
|
||||
accept: ".zip",
|
||||
@@ -118,7 +151,7 @@ export default function SavesList(props) {
|
||||
},
|
||||
showUploadList: false,
|
||||
action: `${webRoot}api/upload-save`,
|
||||
// TODO: show progress to user.
|
||||
onChange,
|
||||
};
|
||||
|
||||
return <div>
|
||||
@@ -131,5 +164,15 @@ export default function SavesList(props) {
|
||||
<Upload.Dragger className="save-list-dragger" openFileDialogOnClick={false} {...uploadProps}>
|
||||
{saveTable}
|
||||
</Upload.Dragger>
|
||||
{uploadingFiles.length ? <List>
|
||||
{uploadingFiles.map(file => <List.Item key={file.uid}>
|
||||
{file.name}
|
||||
<Progress
|
||||
percent={file.percent}
|
||||
format={percent => `${Math.floor(percent)}%`}
|
||||
status={file.status === "error" ? "exception" : "normal"}
|
||||
/>
|
||||
</List.Item>)}
|
||||
</List> : null}
|
||||
</div>;
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@clusterio/plugin-global_chat",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"description": "Clusterio plugin forwarding between Factorio servers",
|
||||
"author": "Hornwitser <github@hornwitser.no>",
|
||||
"homepage": "https://github.com/clusterio/factorioClusterio#readme",
|
||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||
"license": "MIT",
|
||||
"repository": "clusterio/factorioClusterio",
|
||||
"repository": "clusterio/clusterio",
|
||||
"scripts": {
|
||||
"build": "webpack-cli --env production",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/clusterio/factorioClusterio/issues"
|
||||
"url": "https://github.com/clusterio/clusterio/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -20,8 +20,8 @@
|
||||
"@clusterio/lib": "^2.0.0-alpha.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.8",
|
||||
"webpack": "^5.36.2",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webpack-merge": "^5.2.0"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@clusterio/plugin-player_auth",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"description": "Clusterio plugin authenticating logged in players to the web interface",
|
||||
"author": "Hornwitser <github@hornwitser.no>",
|
||||
"homepage": "https://github.com/clusterio/factorioClusterio#readme",
|
||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||
"license": "MIT",
|
||||
"repository": "clusterio/factorioClusterio",
|
||||
"repository": "clusterio/clusterio",
|
||||
"scripts": {
|
||||
"build": "webpack-cli --env production",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/clusterio/factorioClusterio/issues"
|
||||
"url": "https://github.com/clusterio/clusterio/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -24,8 +24,8 @@
|
||||
"jsonwebtoken": "^8.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.8",
|
||||
"antd": "^4.16.0",
|
||||
"phin": "^3.5.1",
|
||||
"react": "^16.13.1",
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@clusterio/plugin-research_sync",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"description": "Clusterio plugin for synchronizing research between Factorio servers",
|
||||
"author": "Hornwitser <github@hornwitser.no>",
|
||||
"homepage": "https://github.com/clusterio/factorioClusterio#readme",
|
||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||
"license": "MIT",
|
||||
"repository": "clusterio/factorioClusterio",
|
||||
"repository": "clusterio/clusterio",
|
||||
"scripts": {
|
||||
"build": "webpack-cli --env production",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/clusterio/factorioClusterio/issues"
|
||||
"url": "https://github.com/clusterio/clusterio/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -23,8 +23,8 @@
|
||||
"fs-extra": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.8",
|
||||
"webpack": "^5.36.2",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webpack-merge": "^5.2.0"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@clusterio/plugin-statistics_exporter",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"description": "Clusterio plugin for gathering statistics from Factorio servers",
|
||||
"author": "Hornwitser <github@hornwitser.no>",
|
||||
"homepage": "https://github.com/clusterio/factorioClusterio#readme",
|
||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||
"license": "MIT",
|
||||
"repository": "clusterio/factorioClusterio",
|
||||
"repository": "clusterio/clusterio",
|
||||
"scripts": {
|
||||
"build": "webpack-cli --env production",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/clusterio/factorioClusterio/issues"
|
||||
"url": "https://github.com/clusterio/clusterio/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -20,8 +20,8 @@
|
||||
"@clusterio/lib": "^2.0.0-alpha.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.8",
|
||||
"webpack": "^5.36.2",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webpack-merge": "^5.2.0"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@clusterio/plugin-subspace_storage",
|
||||
"version": "2.0.0-alpha.7",
|
||||
"version": "2.0.0-alpha.8",
|
||||
"description": "Clusterio plugin for sharing storage between Factorio servers",
|
||||
"author": "Hornwitser <github@hornwitser.no>",
|
||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||
"license": "MIT",
|
||||
"repository": "clusterio/factorioClusterio",
|
||||
"repository": "clusterio/clusterio",
|
||||
"scripts": {
|
||||
"build": "webpack-cli --env production",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/clusterio/factorioClusterio/issues"
|
||||
"url": "https://github.com/clusterio/clusterio/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -23,8 +23,8 @@
|
||||
"fs-extra": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.7",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.7",
|
||||
"@clusterio/lib": "^2.0.0-alpha.8",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.8",
|
||||
"antd": "^4.16.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
||||
@@ -65,6 +65,12 @@ describe("Integration of Clusterio", function() {
|
||||
describe("clusterioslave", function() {
|
||||
describe("slaveUpdateEventHandler()", function() {
|
||||
it("should trigger when a new slave is added", async function() {
|
||||
// On windows there's currently no way to automate graceful shutdown of the slave
|
||||
// process as CTRL+C is some weird terminal thing and SIGINT isn't a thing.
|
||||
if (process.platform === "win32") {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
slowTest(this);
|
||||
getControl().slaveUpdates = [];
|
||||
let config = "alt-slave-config.json";
|
||||
|
||||
@@ -325,5 +325,25 @@ describe("master/src/routes", function() {
|
||||
assert.deepEqual(JSON.parse(response.body), { saves: ["test.zip"] });
|
||||
assert.equal(response.statusCode, 200);
|
||||
});
|
||||
it("should complete a valid transfer with non-standerd mime type", async function() {
|
||||
master.forwardRequestToInstance = async (request, data) => {
|
||||
let stream = await phin({
|
||||
url: `http://localhost:${port}/api/stream/${data.stream_id}`,
|
||||
});
|
||||
assert.equal(stream.body.toString(), "totally a zip file");
|
||||
return { save: data.filename };
|
||||
};
|
||||
let response;
|
||||
response = await phin({
|
||||
url: `http://localhost:${port}/api/upload-save?instance_id=123&filename=test.zip`, method: "POST",
|
||||
headers: {
|
||||
"X-Access-Token": testToken,
|
||||
"Content-Type": "application/x-zip-compressed",
|
||||
},
|
||||
data: "totally a zip file",
|
||||
});
|
||||
assert.deepEqual(JSON.parse(response.body), { saves: ["test.zip"] });
|
||||
assert.equal(response.statusCode, 200);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user