mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-15 23:24:52 +09:00
Compare commits
12
Commits
v2.0.0-alpha.22b
...
2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e39b587df | ||
|
|
e28789c1c0 | ||
|
|
4caf06aafc | ||
|
|
6b0dd4e9cf | ||
|
|
a2c38ad4e8 | ||
|
|
3a823bee01 | ||
|
|
98650b9bfb | ||
|
|
a781af5b6a | ||
|
|
f202a0975a | ||
|
|
ea4280d184 | ||
|
|
c519ee1389 | ||
|
|
c61b9dbe60 |
No files matched your search
@@ -120,7 +120,7 @@ There's also the `add_libraries` function exported by event_handler, which accep
|
|||||||
## Communicating with Clusterio
|
## Communicating with Clusterio
|
||||||
|
|
||||||
Clusterio uses a homebrew protocol based on sending JSON payloads over a WebSocket connection.
|
Clusterio uses a homebrew protocol based on sending JSON payloads over a WebSocket connection.
|
||||||
See [socket.md](socket.md) for the implementation details of it.
|
See [protocol.md](devs/protocol.md) for the implementation details of it.
|
||||||
|
|
||||||
It's also possible to write a plugin for Clusterio that exposes a custom interface over HTTP, WebSocket or any other technology supported by Node.js.
|
It's also possible to write a plugin for Clusterio that exposes a custom interface over HTTP, WebSocket or any other technology supported by Node.js.
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,12 @@ function getPlugins(req: Request, res: Response) {
|
|||||||
res.send(plugins);
|
res.send(plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getClusterName(req: Request, res: Response) {
|
||||||
|
const controller: Controller = req.app.locals.controller;
|
||||||
|
const clusterName = controller.config.get("controller.name");
|
||||||
|
res.json({ name: clusterName });
|
||||||
|
}
|
||||||
|
|
||||||
function validateHostToken(req: Request, res: Response, next: any) {
|
function validateHostToken(req: Request, res: Response, next: any) {
|
||||||
let token = req.header("x-access-token");
|
let token = req.header("x-access-token");
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -662,6 +668,7 @@ async function uploadMod(req: Request, res: Response) {
|
|||||||
export function addRouteHandlers(app: Application) {
|
export function addRouteHandlers(app: Application) {
|
||||||
app.get("/metrics", (req:Request, res:Response, next:any) => getMetrics(req, res, next).catch(next));
|
app.get("/metrics", (req:Request, res:Response, next:any) => getMetrics(req, res, next).catch(next));
|
||||||
app.get("/api/plugins", getPlugins);
|
app.get("/api/plugins", getPlugins);
|
||||||
|
app.get("/api/cluster-name", getClusterName);
|
||||||
app.put("/api/upload-export",
|
app.put("/api/upload-export",
|
||||||
validateHostToken,
|
validateHostToken,
|
||||||
(req:Request, res:Response, next:any) => uploadExport(req, res).catch(next)
|
(req:Request, res:Response, next:any) => uploadExport(req, res).catch(next)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "Installer for clusterio",
|
"description": "Installer for clusterio",
|
||||||
"author": "Hornwitser",
|
"author": "Hornwitser",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"main": "create.js",
|
"main": "create.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"clusteriocreate": "./create.js"
|
"clusteriocreate": "./create.js"
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ function serialize.serialize_equipment_grid(grid)
|
|||||||
if equipment.to_be_removed then
|
if equipment.to_be_removed then
|
||||||
entry.t = equipment.to_be_removed
|
entry.t = equipment.to_be_removed
|
||||||
end
|
end
|
||||||
log(entry)
|
|
||||||
table.insert(serialized, entry)
|
table.insert(serialized, entry)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import zlib from "zlib";
|
import zlib from "zlib";
|
||||||
|
|
||||||
|
type FactorioVersion = [number, number, number, number];
|
||||||
|
|
||||||
class MapReaderState {
|
class MapReaderState {
|
||||||
pos = 0;
|
pos = 0;
|
||||||
last_position = { x: 0, y: 0 };
|
last_position = { x: 0, y: 0 };
|
||||||
/** True when a version greater than 2.0.0 is detected */
|
/** True when a version greater than 2.0.0 is detected */
|
||||||
v2 = false;
|
v2 = false;
|
||||||
|
version: FactorioVersion | null = null;
|
||||||
constructor(
|
constructor(
|
||||||
public buf: Buffer
|
public buf: Buffer
|
||||||
) { }
|
) { }
|
||||||
@@ -110,7 +113,7 @@ function readDict<K, V>(
|
|||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readVersion(state: MapReaderState) {
|
function readVersion(state: MapReaderState): FactorioVersion {
|
||||||
let major = readUInt16(state);
|
let major = readUInt16(state);
|
||||||
let minor = readUInt16(state);
|
let minor = readUInt16(state);
|
||||||
let patch = readUInt16(state);
|
let patch = readUInt16(state);
|
||||||
@@ -118,6 +121,24 @@ function readVersion(state: MapReaderState) {
|
|||||||
return [major, minor, patch, developer];
|
return [major, minor, patch, developer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isVersionAtLeast(state: MapReaderState, major: number, minor: number, patch: number, developer: number) {
|
||||||
|
if (!state.version) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [vMajor, vMinor, vPatch, vDeveloper] = state.version;
|
||||||
|
if (vMajor !== major) {
|
||||||
|
return vMajor > major;
|
||||||
|
}
|
||||||
|
if (vMinor !== minor) {
|
||||||
|
return vMinor > minor;
|
||||||
|
}
|
||||||
|
if (vPatch !== patch) {
|
||||||
|
return vPatch > patch;
|
||||||
|
}
|
||||||
|
return vDeveloper >= developer;
|
||||||
|
}
|
||||||
|
|
||||||
function readFrequencySizeRichness(state: MapReaderState) {
|
function readFrequencySizeRichness(state: MapReaderState) {
|
||||||
return {
|
return {
|
||||||
frequency: readFloat(state),
|
frequency: readFloat(state),
|
||||||
@@ -262,7 +283,8 @@ function readEnemyEvolution(state: MapReaderState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readEnemyExpansion(state: MapReaderState) {
|
function readEnemyExpansion(state: MapReaderState) {
|
||||||
return {
|
let evolutionGroupSizeFactor: number | null | undefined;
|
||||||
|
const settings = {
|
||||||
enabled: readOptional(state, readBool),
|
enabled: readOptional(state, readBool),
|
||||||
max_expansion_distance: readOptional(state, readUInt32),
|
max_expansion_distance: readOptional(state, readUInt32),
|
||||||
friendly_base_influence_radius: readOptional(state, readUInt32),
|
friendly_base_influence_radius: readOptional(state, readUInt32),
|
||||||
@@ -274,9 +296,36 @@ function readEnemyExpansion(state: MapReaderState) {
|
|||||||
max_colliding_tiles_coefficient: readOptional(state, readDouble),
|
max_colliding_tiles_coefficient: readOptional(state, readDouble),
|
||||||
settler_group_min_size: readOptional(state, readUInt32),
|
settler_group_min_size: readOptional(state, readUInt32),
|
||||||
settler_group_max_size: readOptional(state, readUInt32),
|
settler_group_max_size: readOptional(state, readUInt32),
|
||||||
min_expansion_cooldown: readOptional(state, readUInt32),
|
min_expansion_cooldown: null,
|
||||||
max_expansion_cooldown: readOptional(state, readUInt32),
|
max_expansion_cooldown: null,
|
||||||
|
} as {
|
||||||
|
enabled: boolean | null;
|
||||||
|
max_expansion_distance: number | null;
|
||||||
|
friendly_base_influence_radius: number | null;
|
||||||
|
enemy_building_influence_radius: number | null;
|
||||||
|
building_coefficient: number | null;
|
||||||
|
other_base_coefficient: number | null;
|
||||||
|
neighbouring_chunk_coefficient: number | null;
|
||||||
|
neighbouring_base_chunk_coefficient: number | null;
|
||||||
|
max_colliding_tiles_coefficient: number | null;
|
||||||
|
settler_group_min_size: number | null;
|
||||||
|
settler_group_max_size: number | null;
|
||||||
|
min_expansion_cooldown: number | null;
|
||||||
|
max_expansion_cooldown: number | null;
|
||||||
|
evolution_group_size_factor?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isVersionAtLeast(state, 2, 1, 0, 0)) {
|
||||||
|
evolutionGroupSizeFactor = readOptional(state, readDouble);
|
||||||
|
}
|
||||||
|
settings.min_expansion_cooldown = readOptional(state, readUInt32);
|
||||||
|
settings.max_expansion_cooldown = readOptional(state, readUInt32);
|
||||||
|
|
||||||
|
if (evolutionGroupSizeFactor !== undefined) {
|
||||||
|
settings.evolution_group_size_factor = evolutionGroupSizeFactor ?? 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readUnitGroup(state: MapReaderState) {
|
function readUnitGroup(state: MapReaderState) {
|
||||||
@@ -427,6 +476,7 @@ export function readMapExchangeString(exchangeString: string) {
|
|||||||
try {
|
try {
|
||||||
const version = readVersion(state);
|
const version = readVersion(state);
|
||||||
state.v2 = version[0] >= 2;
|
state.v2 = version[0] >= 2;
|
||||||
|
state.version = version;
|
||||||
data = {
|
data = {
|
||||||
version: version,
|
version: version,
|
||||||
unknown: readUInt8(state),
|
unknown: readUInt8(state),
|
||||||
|
|||||||
@@ -275,6 +275,9 @@ function keyToLabels(key: string) {
|
|||||||
if (key !== "") {
|
if (key !== "") {
|
||||||
for (let pair of key.split(",")) {
|
for (let pair of key.split(",")) {
|
||||||
let [name, value] = pair.split("=", 2);
|
let [name, value] = pair.split("=", 2);
|
||||||
|
if (!name || value === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
labels.set(name, value
|
labels.set(name, value
|
||||||
.slice(1, -1)
|
.slice(1, -1)
|
||||||
.replace(/\\"/g, "\"")
|
.replace(/\\"/g, "\"")
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export default function HostViewPage() {
|
|||||||
</PageLayout>;
|
</PageLayout>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hostButtons = <Space>
|
let hostButtons = <Space wrap>
|
||||||
<HostControlButton hostId={hostId} canRestart={system?.canRestart} restartRequired={system?.restartRequired}/>
|
<HostControlButton hostId={hostId} canRestart={system?.canRestart} restartRequired={system?.restartRequired}/>
|
||||||
{
|
{
|
||||||
account.hasPermission("core.host.revoke_token")
|
account.hasPermission("core.host.revoke_token")
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ function InstanceButtons(props: { instance: lib.InstanceDetails }) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return <Space>
|
return <Space wrap>
|
||||||
{
|
{
|
||||||
account.hasAnyPermission(...InstanceControlButtonPermissions)
|
account.hasAnyPermission(...InstanceControlButtonPermissions)
|
||||||
&& <InstanceControlButton instance={instance} />
|
&& <InstanceControlButton instance={instance} />
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { Fragment, useContext } from "react";
|
import React, { Fragment, useContext, useEffect, useState } from "react";
|
||||||
import { Button, Card, Divider, Form, Image, Input, Space, Typography } from "antd";
|
import { Button, Card, Divider, Form, Image, Input, Space, Typography } from "antd";
|
||||||
import LockOutlined from "@ant-design/icons/LockOutlined";
|
import LockOutlined from "@ant-design/icons/LockOutlined";
|
||||||
|
|
||||||
|
import notify from "../util/notify";
|
||||||
import logo from "../images/logo.png";
|
import logo from "../images/logo.png";
|
||||||
import ControlContext from "./ControlContext";
|
import ControlContext from "./ControlContext";
|
||||||
|
|
||||||
@@ -36,6 +37,23 @@ function TokenAuth(props: SetTokenProps) {
|
|||||||
|
|
||||||
export default function LoginForm(props: SetTokenProps) {
|
export default function LoginForm(props: SetTokenProps) {
|
||||||
let plugins = useContext(ControlContext).plugins;
|
let plugins = useContext(ControlContext).plugins;
|
||||||
|
const [clusterName, setClusterName] = useState<string>("Clusterio");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
let response = await fetch(`${webRoot}api/cluster-name`);
|
||||||
|
if (response.ok) {
|
||||||
|
let data = await response.json();
|
||||||
|
if (data.name) {
|
||||||
|
setClusterName(data.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
notify("Failed to load cluster name");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
let loginForms = [];
|
let loginForms = [];
|
||||||
for (let plugin of plugins.values()) {
|
for (let plugin of plugins.values()) {
|
||||||
@@ -50,7 +68,7 @@ export default function LoginForm(props: SetTokenProps) {
|
|||||||
|
|
||||||
return <Card style={{ maxWidth: "30em" }}>
|
return <Card style={{ maxWidth: "30em" }}>
|
||||||
<Space style={{ width: "100%" }} direction="vertical" align="center">
|
<Space style={{ width: "100%" }} direction="vertical" align="center">
|
||||||
<h1>Clusterio</h1>
|
<h1>{clusterName}</h1>
|
||||||
<Image width={128} height={123} src={logo} />
|
<Image width={128} height={123} src={logo} />
|
||||||
Log in to the cluster using one of the methods below.
|
Log in to the cluster using one of the methods below.
|
||||||
</Space>
|
</Space>
|
||||||
@@ -60,4 +78,3 @@ export default function LoginForm(props: SetTokenProps) {
|
|||||||
</Fragment>)}
|
</Fragment>)}
|
||||||
</Card>;
|
</Card>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,7 +664,7 @@ function ModsTable(props: ModsTableProps) {
|
|||||||
return <>
|
return <>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Mods"
|
title="Mods"
|
||||||
extra={<Space>
|
extra={<Space wrap>
|
||||||
<Button
|
<Button
|
||||||
icon={<ToolOutlined />}
|
icon={<ToolOutlined />}
|
||||||
disabled={!mods.some(m => m.enabled && m.warning && m.warning !== "wrong_factorio_version")}
|
disabled={!mods.some(m => m.enabled && m.warning && m.warning !== "wrong_factorio_version")}
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ export default function ModsPage() {
|
|||||||
<PageHeader title="Mods" />
|
<PageHeader title="Mods" />
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Mod Packs"
|
title="Mod Packs"
|
||||||
extra={<Space>
|
extra={<Space wrap>
|
||||||
{account.hasPermission("core.mod_pack.create") && <ImportModPackButton />}
|
{account.hasPermission("core.mod_pack.create") && <ImportModPackButton />}
|
||||||
{account.hasPermission("core.mod_pack.create") && <CreateModPackButton />}
|
{account.hasPermission("core.mod_pack.create") && <CreateModPackButton />}
|
||||||
</Space>}
|
</Space>}
|
||||||
@@ -594,7 +594,7 @@ export default function ModsPage() {
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<SectionHeader title="Stored Mods" extra={<Space>
|
<SectionHeader title="Stored Mods" extra={<Space wrap>
|
||||||
<SearchModsButton />
|
<SearchModsButton />
|
||||||
{uploadButton}
|
{uploadButton}
|
||||||
</Space>} />
|
</Space>} />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useContext, useState } from "react";
|
import React, { useEffect, useContext, useState } from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { Button, Checkbox, Form, Input, Popconfirm, Spin } from "antd";
|
import { Button, Checkbox, Form, Input, Popconfirm, Space, Spin } from "antd";
|
||||||
import DeleteOutlined from "@ant-design/icons/DeleteOutlined";
|
import DeleteOutlined from "@ant-design/icons/DeleteOutlined";
|
||||||
|
|
||||||
import * as lib from "@clusterio/lib";
|
import * as lib from "@clusterio/lib";
|
||||||
@@ -71,7 +71,7 @@ export default function RoleViewPage() {
|
|||||||
>
|
>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={role.name}
|
title={role.name}
|
||||||
extra={<>
|
extra={<Space wrap>
|
||||||
{canUpdate && <Button type={edited ? "primary" : "default"} htmlType="submit">Apply</Button>}
|
{canUpdate && <Button type={edited ? "primary" : "default"} htmlType="submit">Apply</Button>}
|
||||||
{account.hasPermission("core.role.delete") && <Popconfirm
|
{account.hasPermission("core.role.delete") && <Popconfirm
|
||||||
title="Delete role?"
|
title="Delete role?"
|
||||||
@@ -90,7 +90,7 @@ export default function RoleViewPage() {
|
|||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>}
|
</Popconfirm>}
|
||||||
</>}
|
</Space>}
|
||||||
/>
|
/>
|
||||||
<Form.Item name="name" label="Name">
|
<Form.Item name="name" label="Name">
|
||||||
<Input disabled={!canUpdate}/>
|
<Input disabled={!canUpdate}/>
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<SectionHeader title="Saves" extra={<Space>
|
<SectionHeader title="Saves" extra={<Space wrap>
|
||||||
{account.hasPermission("core.instance.save.upload") && <Upload {...uploadProps} >
|
{account.hasPermission("core.instance.save.upload") && <Upload {...uploadProps} >
|
||||||
<UploadButton disabled={hostOffline}>
|
<UploadButton disabled={hostOffline}>
|
||||||
Upload save
|
Upload save
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export default function UserViewPage() {
|
|||||||
{user.isBanned && <Tag color="red">Banned</Tag>}
|
{user.isBanned && <Tag color="red">Banned</Tag>}
|
||||||
</span>
|
</span>
|
||||||
</Space>}
|
</Space>}
|
||||||
extra={<>
|
extra={<Space wrap>
|
||||||
{account.hasPermission("core.user.revoke_token") && (
|
{account.hasPermission("core.user.revoke_token") && (
|
||||||
account.name === userName || account.hasPermission("core.user.revoke_other_token")
|
account.name === userName || account.hasPermission("core.user.revoke_other_token")
|
||||||
) && <Button
|
) && <Button
|
||||||
@@ -146,7 +146,7 @@ export default function UserViewPage() {
|
|||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>}
|
</Popconfirm>}
|
||||||
</>}
|
</Space>}
|
||||||
/>
|
/>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ export default function UsersTable({ instanceId, onlyOnline = false, pagination,
|
|||||||
rowKey={(user) => user.name}
|
rowKey={(user) => user.name}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
size={size}
|
size={size}
|
||||||
|
scroll={{ x: "max-content" }}
|
||||||
onRow={(user) => ({
|
onRow={(user) => ({
|
||||||
onClick: (event) => {
|
onClick: (event) => {
|
||||||
if ((event.target as HTMLElement).closest("a")) {
|
if ((event.target as HTMLElement).closest("a")) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clusterio/plugin-global_chat",
|
"name": "@clusterio/plugin-global_chat",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"description": "Clusterio plugin forwarding between Factorio servers",
|
"description": "Clusterio plugin forwarding between Factorio servers",
|
||||||
"author": "Hornwitser <github@hornwitser.no>",
|
"author": "Hornwitser <github@hornwitser.no>",
|
||||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clusterio/plugin-inventory_sync",
|
"name": "@clusterio/plugin-inventory_sync",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"description": "Clusterio plugin forwarding between Factorio servers",
|
"description": "Clusterio plugin forwarding between Factorio servers",
|
||||||
"author": "Danielv <danielv@danielv.no>",
|
"author": "Danielv <danielv@danielv.no>",
|
||||||
"homepage": "https://github.com/clusterio/factorioClusterio#readme",
|
"homepage": "https://github.com/clusterio/factorioClusterio#readme",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clusterio/plugin-player_auth",
|
"name": "@clusterio/plugin-player_auth",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"description": "Clusterio plugin authenticating logged in players to the web interface",
|
"description": "Clusterio plugin authenticating logged in players to the web interface",
|
||||||
"author": "Hornwitser <github@hornwitser.no>",
|
"author": "Hornwitser <github@hornwitser.no>",
|
||||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clusterio/plugin-research_sync",
|
"name": "@clusterio/plugin-research_sync",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"description": "Clusterio plugin for synchronizing research between Factorio servers",
|
"description": "Clusterio plugin for synchronizing research between Factorio servers",
|
||||||
"author": "Hornwitser <github@hornwitser.no>",
|
"author": "Hornwitser <github@hornwitser.no>",
|
||||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clusterio/plugin-statistics_exporter",
|
"name": "@clusterio/plugin-statistics_exporter",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"description": "Clusterio plugin for gathering statistics from Factorio servers",
|
"description": "Clusterio plugin for gathering statistics from Factorio servers",
|
||||||
"author": "Hornwitser <github@hornwitser.no>",
|
"author": "Hornwitser <github@hornwitser.no>",
|
||||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clusterio/plugin-subspace_storage",
|
"name": "@clusterio/plugin-subspace_storage",
|
||||||
"version": "2.0.0-alpha.22",
|
"version": "2.0.0-alpha.22b",
|
||||||
"description": "Clusterio plugin for sharing storage between Factorio servers",
|
"description": "Clusterio plugin for sharing storage between Factorio servers",
|
||||||
"author": "Hornwitser <github@hornwitser.no>",
|
"author": "Hornwitser <github@hornwitser.no>",
|
||||||
"homepage": "https://github.com/clusterio/clusterio#readme",
|
"homepage": "https://github.com/clusterio/clusterio#readme",
|
||||||
|
|||||||
@@ -74,6 +74,19 @@ describe("controller/src/routes", function() {
|
|||||||
assert.equal(await responses[1].text(), "test content");
|
assert.equal(await responses[1].text(), "test content");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe("/api/cluster-name", function() {
|
||||||
|
let endpoint;
|
||||||
|
beforeEach(function() {
|
||||||
|
endpoint = `http://localhost:${port}/api/cluster-name`;
|
||||||
|
});
|
||||||
|
it("should return the cluster name from config", async function() {
|
||||||
|
controller.mockConfigEntries.set("controller.name", "Test Cluster");
|
||||||
|
let response = await fetch(endpoint);
|
||||||
|
assert.equal(response.status, 200);
|
||||||
|
let data = await response.json();
|
||||||
|
assert.deepEqual(data, { name: "Test Cluster" });
|
||||||
|
});
|
||||||
|
});
|
||||||
describe("/api/upload-save", function() {
|
describe("/api/upload-save", function() {
|
||||||
let endpoint;
|
let endpoint;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
|||||||
Reference in new issue
Block a user