mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-11-11 15:54:52 +09:00
Merge branch 'explosivegaming:main' into aperx
This commit is contained in:
69 files changed
+218
-571
No files matched your search
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
webpack.config.js
|
vite.config.js
|
||||||
dist/web/build
|
dist/web/build
|
||||||
dist/browser
|
dist/browser
|
||||||
@@ -197,7 +197,7 @@ export class AutoRestart {
|
|||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.pending.delete(host.id);
|
this.pending.delete(host.id);
|
||||||
// The host refusing is final for this process, anything else is retried
|
// The host refusing is final for this process, anything else is retried
|
||||||
if (!(err instanceof lib.RequestError)) {
|
if (!(err instanceof lib.ClientError)) {
|
||||||
this.requested.delete(host.id);
|
this.requested.delete(host.id);
|
||||||
}
|
}
|
||||||
this.logger.error(`Failed to restart host ${host.name}: ${err.message}`);
|
this.logger.error(`Failed to restart host ${host.name}: ${err.message}`);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ export const plugin: lib.PluginDeclaration = {
|
|||||||
name: "exp_auto_restart",
|
name: "exp_auto_restart",
|
||||||
title: "ExpGaming - Auto Restart",
|
title: "ExpGaming - Auto Restart",
|
||||||
description: "Clusterio plugin restarting hosts and the controller once no players are online",
|
description: "Clusterio plugin restarting hosts and the controller once no players are online",
|
||||||
webEntrypoint: "./web",
|
|
||||||
|
|
||||||
controllerEntrypoint: "./dist/node/controller.js",
|
controllerEntrypoint: "./dist/node/controller.js",
|
||||||
controllerConfigFields: {
|
controllerConfigFields: {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -27,12 +27,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clusterio/controller": "workspace:^",
|
"@clusterio/controller": "workspace:^",
|
||||||
"@clusterio/lib": "workspace:^",
|
"@clusterio/lib": "workspace:^",
|
||||||
|
"@clusterio/web_ui": "workspace:^",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ t.test("class AutoRestart", t2 => {
|
|||||||
addInstance(controller, 10, 1);
|
addInstance(controller, 10, 1);
|
||||||
addSystem(controller, 1);
|
addSystem(controller, 1);
|
||||||
|
|
||||||
controller.sendTo = async () => { throw new lib.RequestError("Cannot restart"); };
|
controller.sendTo = async () => { throw new lib.ConflictError("Cannot restart"); };
|
||||||
await plugin.check(now);
|
await plugin.check(now);
|
||||||
await plugin.check(now + 10_000);
|
await plugin.check(now + 10_000);
|
||||||
t3.strictSame(logs.filter(([level]) => level === "error").length, 1, "a refusal is logged once");
|
t3.strictSame(logs.filter(([level]) => level === "error").length, 1, "a refusal is logged once");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.browser.json",
|
"extends": "../tsconfig.browser.json",
|
||||||
"include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ],
|
"include": [ "index.ts", "package.json" ],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default function() {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_auto_restart",
|
|
||||||
library: { type: "window", name: "plugin_exp_auto_restart" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -5,5 +5,4 @@ export const plugin: lib.PluginDeclaration = {
|
|||||||
title: "ExpGaming - Commands",
|
title: "ExpGaming - Commands",
|
||||||
description: "Clusterio plugin providing a Lua command processing library.",
|
description: "Clusterio plugin providing a Lua command processing library.",
|
||||||
instanceEntrypoint: "./dist/node/instance.js",
|
instanceEntrypoint: "./dist/node/instance.js",
|
||||||
webEntrypoint: "./web",
|
|
||||||
};
|
};
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production"
|
"prepare": "tsc --build && vite build"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -25,11 +25,10 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clusterio/host": "workspace:^",
|
"@clusterio/host": "workspace:^",
|
||||||
"@clusterio/lib": "workspace:^",
|
"@clusterio/lib": "workspace:^",
|
||||||
|
"@clusterio/web_ui": "workspace:^",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expcluster/lib_util": "workspace:^",
|
"@expcluster/lib_util": "workspace:^",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.browser.json",
|
"extends": "../tsconfig.browser.json",
|
||||||
"include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ],
|
"include": [ "index.ts", "package.json" ],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default function() {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_commands",
|
|
||||||
library: { type: "window", name: "plugin_exp_commands" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -95,12 +95,10 @@ export class ControllerPlugin {
|
|||||||
const controller = context.controller;
|
const controller = context.controller;
|
||||||
const databaseDirectory = controller.config.get("controller.database_directory");
|
const databaseDirectory = controller.config.get("controller.database_directory");
|
||||||
|
|
||||||
const accounts = new lib.SubscribableDatastore(
|
const accounts = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_discord_auth", "accounts.json"),
|
||||||
path.join(databaseDirectory, "exp_discord_auth", "accounts.json"),
|
messages.DiscordAccountRecord.fromJSON.bind(messages.DiscordAccountRecord),
|
||||||
messages.DiscordAccountRecord.fromJSON.bind(messages.DiscordAccountRecord),
|
));
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
return new ControllerPlugin(controller, context.logger, context.plugin.name, accounts);
|
return new ControllerPlugin(controller, context.logger, context.plugin.name, accounts);
|
||||||
}
|
}
|
||||||
@@ -387,7 +385,7 @@ export class ControllerPlugin {
|
|||||||
const entry = this.codes.get(code);
|
const entry = this.codes.get(code);
|
||||||
const session = entry ? this.sessions.get(entry.sessionId) : undefined;
|
const session = entry ? this.sessions.get(entry.sessionId) : undefined;
|
||||||
if (!entry || !session || entry.expiresMs < Date.now()) {
|
if (!entry || !session || entry.expiresMs < Date.now()) {
|
||||||
throw new lib.RequestError(
|
throw new lib.ValidationError(
|
||||||
`This code is invalid or has expired, get a new one from ${this.controller.getControllerUrl()}`
|
`This code is invalid or has expired, get a new one from ${this.controller.getControllerUrl()}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -405,7 +403,7 @@ export class ControllerPlugin {
|
|||||||
const alreadyLinked = existing?.factorioNames.some(linked => linked.toLowerCase() === name);
|
const alreadyLinked = existing?.factorioNames.some(linked => linked.toLowerCase() === name);
|
||||||
const maxAccounts = this.controller.config.get("exp_discord_auth.max_accounts");
|
const maxAccounts = this.controller.config.get("exp_discord_auth.max_accounts");
|
||||||
if (!alreadyLinked && (existing?.factorioNames.length ?? 0) >= maxAccounts) {
|
if (!alreadyLinked && (existing?.factorioNames.length ?? 0) >= maxAccounts) {
|
||||||
throw new lib.RequestError(
|
throw new lib.ConflictError(
|
||||||
`${discordUser.name} already has ${maxAccounts} Factorio accounts linked, unlink one first`
|
`${discordUser.name} already has ${maxAccounts} Factorio accounts linked, unlink one first`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -40,11 +40,9 @@
|
|||||||
"react": "catalog:",
|
"react": "catalog:",
|
||||||
"react-dom": "catalog:",
|
"react-dom": "catalog:",
|
||||||
"react-router-dom": "catalog:",
|
"react-router-dom": "catalog:",
|
||||||
"typescript": "catalog:",
|
|
||||||
"webpack": "catalog:",
|
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"webpack-cli": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack-merge": "catalog:"
|
"vite": "catalog:"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:",
|
"@sinclair/typebox": "catalog:",
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_discord_auth",
|
|
||||||
library: { type: "window", name: "plugin_exp_discord_auth" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
"antd": { import: false },
|
|
||||||
"react": { import: false },
|
|
||||||
"react-dom": { import: false },
|
|
||||||
"react-router": { import: false },
|
|
||||||
"react-router-dom": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
+23
-29
@@ -26,26 +26,20 @@ export class ControllerPlugin {
|
|||||||
const controller = context.controller;
|
const controller = context.controller;
|
||||||
const databaseDirectory = controller.config.get("controller.database_directory");
|
const databaseDirectory = controller.config.get("controller.database_directory");
|
||||||
|
|
||||||
const groups = new lib.SubscribableDatastore(
|
const groups = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_groups", "groups.json"),
|
||||||
path.join(databaseDirectory, "exp_groups", "groups.json"),
|
messages.GroupRecord.fromJSON.bind(messages.GroupRecord),
|
||||||
messages.GroupRecord.fromJSON.bind(messages.GroupRecord),
|
));
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
const roleMappings = new lib.SubscribableDatastore(
|
const roleMappings = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_groups", "role_mappings.json"),
|
||||||
path.join(databaseDirectory, "exp_groups", "role_mappings.json"),
|
messages.RoleMappingRecord.fromJSON.bind(messages.RoleMappingRecord),
|
||||||
messages.RoleMappingRecord.fromJSON.bind(messages.RoleMappingRecord),
|
));
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
const manualAssignments = new lib.SubscribableDatastore(
|
const manualAssignments = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_groups", "assignments.json"),
|
||||||
path.join(databaseDirectory, "exp_groups", "assignments.json"),
|
messages.AssignmentRecord.fromJSON.bind(messages.AssignmentRecord),
|
||||||
messages.AssignmentRecord.fromJSON.bind(messages.AssignmentRecord),
|
));
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
const plugin = new ControllerPlugin(
|
const plugin = new ControllerPlugin(
|
||||||
controller, context.logger, context.plugin.name, groups, roleMappings, manualAssignments,
|
controller, context.logger, context.plugin.name, groups, roleMappings, manualAssignments,
|
||||||
@@ -239,7 +233,7 @@ export class ControllerPlugin {
|
|||||||
|
|
||||||
async handleGroupCreateRequest(request: messages.GroupCreateRequest) {
|
async handleGroupCreateRequest(request: messages.GroupCreateRequest) {
|
||||||
if ([...this.groups.values()].some(g => g.name === request.name)) {
|
if ([...this.groups.values()].some(g => g.name === request.name)) {
|
||||||
throw new lib.RequestError(`Group with name '${request.name}' already exists`);
|
throw new lib.ConflictError(`Group with name '${request.name}' already exists`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = Math.random() * 2**31 | 0;
|
let id = Math.random() * 2**31 | 0;
|
||||||
@@ -255,7 +249,7 @@ export class ControllerPlugin {
|
|||||||
async handleGroupUpdateRequest(request: messages.GroupUpdateRequest) {
|
async handleGroupUpdateRequest(request: messages.GroupUpdateRequest) {
|
||||||
const group = request.group;
|
const group = request.group;
|
||||||
if (group.id === undefined || !this.groups.has(group.id)) {
|
if (group.id === undefined || !this.groups.has(group.id)) {
|
||||||
throw new lib.RequestError(`Group with ID ${group.id} does not exist`);
|
throw new lib.NotFoundError(`Group with ID ${group.id} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.groups.set(group);
|
this.groups.set(group);
|
||||||
@@ -266,7 +260,7 @@ export class ControllerPlugin {
|
|||||||
|
|
||||||
const group = this.groups.getMutable(groupId);
|
const group = this.groups.getMutable(groupId);
|
||||||
if (!group) {
|
if (!group) {
|
||||||
throw new lib.RequestError(`Group with ID ${groupId} does not exist`);
|
throw new lib.NotFoundError(`Group with ID ${groupId} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.groups.delete(group);
|
this.groups.delete(group);
|
||||||
@@ -275,7 +269,7 @@ export class ControllerPlugin {
|
|||||||
async handleGroupGetRequest(request: messages.GroupGetRequest) {
|
async handleGroupGetRequest(request: messages.GroupGetRequest) {
|
||||||
const group = this.groups.get(request.groupId);
|
const group = this.groups.get(request.groupId);
|
||||||
if (!group) {
|
if (!group) {
|
||||||
throw new lib.RequestError(`Group with ID ${request.groupId} does not exist`);
|
throw new lib.NotFoundError(`Group with ID ${request.groupId} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return group;
|
return group;
|
||||||
@@ -292,7 +286,7 @@ export class ControllerPlugin {
|
|||||||
async handleAssignmentCreateRequest(request: messages.AssignmentCreateRequest) {
|
async handleAssignmentCreateRequest(request: messages.AssignmentCreateRequest) {
|
||||||
const { name, groupId } = request;
|
const { name, groupId } = request;
|
||||||
if (this.manualAssignments.has(name)) {
|
if (this.manualAssignments.has(name)) {
|
||||||
throw new lib.RequestError(`Assignment for '${name}' already exists`);
|
throw new lib.ConflictError(`Assignment for '${name}' already exists`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const assignment = new messages.AssignmentRecord(name, groupId);
|
const assignment = new messages.AssignmentRecord(name, groupId);
|
||||||
@@ -303,7 +297,7 @@ export class ControllerPlugin {
|
|||||||
async handleAssignmentUpdateRequest(request: messages.AssignmentUpdateRequest) {
|
async handleAssignmentUpdateRequest(request: messages.AssignmentUpdateRequest) {
|
||||||
const assignment = request.assignment;
|
const assignment = request.assignment;
|
||||||
if (!this.manualAssignments.has(assignment.name)) {
|
if (!this.manualAssignments.has(assignment.name)) {
|
||||||
throw new lib.RequestError(`Assignment for '${assignment.name}' does not exist`);
|
throw new lib.NotFoundError(`Assignment for '${assignment.name}' does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.manualAssignments.set(assignment);
|
this.manualAssignments.set(assignment);
|
||||||
@@ -314,7 +308,7 @@ export class ControllerPlugin {
|
|||||||
|
|
||||||
const assignment = this.manualAssignments.getMutable(name);
|
const assignment = this.manualAssignments.getMutable(name);
|
||||||
if (!assignment) {
|
if (!assignment) {
|
||||||
throw new lib.RequestError(`Assignment for '${name}' does not exist`);
|
throw new lib.NotFoundError(`Assignment for '${name}' does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.manualAssignments.delete(assignment);
|
this.manualAssignments.delete(assignment);
|
||||||
@@ -333,7 +327,7 @@ export class ControllerPlugin {
|
|||||||
|
|
||||||
const assignment = this.manualAssignments.get(request.name);
|
const assignment = this.manualAssignments.get(request.name);
|
||||||
if (!assignment) {
|
if (!assignment) {
|
||||||
throw new lib.RequestError(`Assignment for '${request.name}' does not exist`);
|
throw new lib.NotFoundError(`Assignment for '${request.name}' does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return assignment;
|
return assignment;
|
||||||
@@ -370,7 +364,7 @@ export class ControllerPlugin {
|
|||||||
async handleRoleMappingUpdateRequest(request: messages.RoleMappingUpdateRequest) {
|
async handleRoleMappingUpdateRequest(request: messages.RoleMappingUpdateRequest) {
|
||||||
const roleMapping = request.roleMapping;
|
const roleMapping = request.roleMapping;
|
||||||
if (roleMapping.id === undefined || !this.roleMappings.has(roleMapping.id)) {
|
if (roleMapping.id === undefined || !this.roleMappings.has(roleMapping.id)) {
|
||||||
throw new lib.RequestError(`Role mapping with ID ${roleMapping.id} does not exist`);
|
throw new lib.NotFoundError(`Role mapping with ID ${roleMapping.id} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = new Set(
|
const existing = new Set(
|
||||||
@@ -392,7 +386,7 @@ export class ControllerPlugin {
|
|||||||
|
|
||||||
const mapping = this.roleMappings.getMutable(id);
|
const mapping = this.roleMappings.getMutable(id);
|
||||||
if (!mapping) {
|
if (!mapping) {
|
||||||
throw new lib.RequestError(`Role mapping with ID ${id} does not exist`);
|
throw new lib.NotFoundError(`Role mapping with ID ${id} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.roleMappings.delete(mapping);
|
this.roleMappings.delete(mapping);
|
||||||
@@ -401,7 +395,7 @@ export class ControllerPlugin {
|
|||||||
async handleRoleMappingGetRequest(request: messages.RoleMappingGetRequest) {
|
async handleRoleMappingGetRequest(request: messages.RoleMappingGetRequest) {
|
||||||
const mapping = this.roleMappings.get(request.id);
|
const mapping = this.roleMappings.get(request.id);
|
||||||
if (!mapping) {
|
if (!mapping) {
|
||||||
throw new lib.RequestError(`Role mapping with ID ${request.id} does not exist`);
|
throw new lib.NotFoundError(`Role mapping with ID ${request.id} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production"
|
"prepare": "tsc --build && vite build"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -39,9 +39,7 @@
|
|||||||
"react-dom": "catalog:",
|
"react-dom": "catalog:",
|
||||||
"react-router-dom": "catalog:",
|
"react-router-dom": "catalog:",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:"
|
"@sinclair/typebox": "catalog:"
|
||||||
@@ -54,4 +52,4 @@
|
|||||||
"clusterio-plugin",
|
"clusterio-plugin",
|
||||||
"factorio"
|
"factorio"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_groups",
|
|
||||||
library: { type: "window", name: "plugin_exp_groups" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
"antd": { import: false },
|
|
||||||
"react": { import: false },
|
|
||||||
"react-dom": { import: false },
|
|
||||||
"react-router": { import: false },
|
|
||||||
"react-router-dom": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -5,5 +5,4 @@ export const plugin: lib.PluginDeclaration = {
|
|||||||
title: "ExpGaming - GUI",
|
title: "ExpGaming - GUI",
|
||||||
description: "Clusterio plugin providing a Lua GUI definition library.",
|
description: "Clusterio plugin providing a Lua GUI definition library.",
|
||||||
instanceEntrypoint: "./dist/node/instance.js",
|
instanceEntrypoint: "./dist/node/instance.js",
|
||||||
webEntrypoint: "./web",
|
|
||||||
};
|
};
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production"
|
"prepare": "tsc --build && vite build"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -25,11 +25,10 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clusterio/host": "workspace:^",
|
"@clusterio/host": "workspace:^",
|
||||||
"@clusterio/lib": "workspace:^",
|
"@clusterio/lib": "workspace:^",
|
||||||
|
"@clusterio/web_ui": "workspace:^",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expcluster/lib_util": "workspace:^",
|
"@expcluster/lib_util": "workspace:^",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.browser.json",
|
"extends": "../tsconfig.browser.json",
|
||||||
"include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ],
|
"include": [ "index.ts", "package.json" ],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default function() {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_gui",
|
|
||||||
library: { type: "window", name: "plugin_exp_gui" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -7,12 +7,10 @@ import * as path from "node:path";
|
|||||||
export default async function (context: ControllerPluginContext) {
|
export default async function (context: ControllerPluginContext) {
|
||||||
const { controller, plugin } = context;
|
const { controller, plugin } = context;
|
||||||
const databaseDirectory = controller.config.get("controller.database_directory");
|
const databaseDirectory = controller.config.get("controller.database_directory");
|
||||||
const players = new lib.SubscribableDatastore(
|
const players = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_player_statistics", "players.json"),
|
||||||
path.join(databaseDirectory, "exp_player_statistics", "players.json"),
|
messages.PlayerStatistics.fromJSON.bind(messages.PlayerStatistics),
|
||||||
messages.PlayerStatistics.fromJSON.bind(messages.PlayerStatistics),
|
));
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
function addDeltas(deltas: messages.StatisticsDelta[]) {
|
function addDeltas(deltas: messages.StatisticsDelta[]) {
|
||||||
const changed = new Map<string, messages.PlayerStatistics>();
|
const changed = new Map<string, messages.PlayerStatistics>();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -42,9 +42,7 @@
|
|||||||
"react-router-dom": "catalog:",
|
"react-router-dom": "catalog:",
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:",
|
"@sinclair/typebox": "catalog:",
|
||||||
|
|||||||
@@ -29,15 +29,16 @@ async function startPlugin(t2, { status = "running", stats = { Kills: 3 } } = {}
|
|||||||
instanceConfig.set("instance.id", 1);
|
instanceConfig.set("instance.id", 1);
|
||||||
instanceConfig.set("instance.name", "test");
|
instanceConfig.set("instance.name", "test");
|
||||||
|
|
||||||
const instance = new Instance(
|
|
||||||
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), "factorioDir", instanceConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
const state = { sent: [], rcons: [], warnings: [] };
|
const state = { sent: [], rcons: [], warnings: [] };
|
||||||
const ipc = new Map();
|
const ipc = new Map();
|
||||||
instance.server = {
|
const server = {
|
||||||
|
on: () => {},
|
||||||
handle: (name, handler) => ipc.set(name, handler),
|
handle: (name, handler) => ipc.set(name, handler),
|
||||||
};
|
};
|
||||||
|
const instance = new Instance(
|
||||||
|
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), instanceConfig, server
|
||||||
|
);
|
||||||
instance.sendRcon = async command => {
|
instance.sendRcon = async command => {
|
||||||
state.rcons.push(command);
|
state.rcons.push(command);
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -47,7 +47,7 @@ export default function StatisticsPage() {
|
|||||||
|
|
||||||
const rows = useMemo(() => [...players.values()].map(player => new PlayerStatistics(
|
const rows = useMemo(() => [...players.values()].map(player => new PlayerStatistics(
|
||||||
player.id,
|
player.id,
|
||||||
{ ...player.stats, ...userStatistics(users.get(player.id.toLowerCase())) },
|
{ ...player.stats, ...userStatistics(users.get(player.id.toLowerCase()), player.stats) },
|
||||||
player.updatedAtMs,
|
player.updatedAtMs,
|
||||||
)), [players, users]);
|
)), [players, users]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_player_statistics",
|
|
||||||
library: { type: "window", name: "plugin_exp_player_statistics" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
"antd": { import: false },
|
|
||||||
"react": { import: false },
|
|
||||||
"react-dom": { import: false },
|
|
||||||
"react-router": { import: false },
|
|
||||||
"react-router-dom": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
+19
-23
@@ -11,19 +11,15 @@ function migrateReports(rawJson: unknown[]) {
|
|||||||
export default async function (context: ControllerPluginContext) {
|
export default async function (context: ControllerPluginContext) {
|
||||||
const { controller, logger, plugin } = context;
|
const { controller, logger, plugin } = context;
|
||||||
const databaseDirectory = controller.config.get("controller.database_directory");
|
const databaseDirectory = controller.config.get("controller.database_directory");
|
||||||
const reports = new lib.SubscribableDatastore(
|
const reports = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_reports", "reports.json"),
|
||||||
path.join(databaseDirectory, "exp_reports", "reports.json"),
|
messages.ReportRecord.fromJSON.bind(messages.ReportRecord),
|
||||||
messages.ReportRecord.fromJSON.bind(messages.ReportRecord),
|
migrateReports,
|
||||||
migrateReports,
|
));
|
||||||
).bootstrap()
|
const watchList = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
);
|
path.join(databaseDirectory, "exp_reports", "watch_list.json"),
|
||||||
const watchList = new lib.SubscribableDatastore(
|
messages.WatchListRecord.fromJSON.bind(messages.WatchListRecord),
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
));
|
||||||
path.join(databaseDirectory, "exp_reports", "watch_list.json"),
|
|
||||||
messages.WatchListRecord.fromJSON.bind(messages.WatchListRecord),
|
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
/** Every report, or only those against one player. */
|
/** Every report, or only those against one player. */
|
||||||
function listReports(playerName?: string) {
|
function listReports(playerName?: string) {
|
||||||
@@ -162,7 +158,7 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
controller.handle(messages.ReportGetRequest, async (request: messages.ReportGetRequest) => {
|
controller.handle(messages.ReportGetRequest, async (request: messages.ReportGetRequest) => {
|
||||||
const report = reports.get(request.id);
|
const report = reports.get(request.id);
|
||||||
if (!report) {
|
if (!report) {
|
||||||
throw new lib.RequestError(`Report with ID ${request.id} does not exist`);
|
throw new lib.NotFoundError(`Report with ID ${request.id} does not exist`);
|
||||||
}
|
}
|
||||||
return report;
|
return report;
|
||||||
});
|
});
|
||||||
@@ -178,13 +174,13 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!byPlayerName) {
|
if (!byPlayerName) {
|
||||||
throw new lib.RequestError("A report needs the name of the player making it");
|
throw new lib.ValidationError("A report needs the name of the player making it");
|
||||||
}
|
}
|
||||||
if (!request.reason.trim()) {
|
if (!request.reason.trim()) {
|
||||||
throw new lib.RequestError("A report needs a reason");
|
throw new lib.ValidationError("A report needs a reason");
|
||||||
}
|
}
|
||||||
if (listReports(request.playerName).some(report => report.byPlayerName === byPlayerName)) {
|
if (listReports(request.playerName).some(report => report.byPlayerName === byPlayerName)) {
|
||||||
throw new lib.RequestError(`${byPlayerName} has already reported ${request.playerName}`);
|
throw new lib.ConflictError(`${byPlayerName} has already reported ${request.playerName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = Math.random() * 2 ** 31 | 0;
|
let id = Math.random() * 2 ** 31 | 0;
|
||||||
@@ -203,7 +199,7 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
controller.handle(messages.ReportDeleteRequest, async (request: messages.ReportDeleteRequest) => {
|
controller.handle(messages.ReportDeleteRequest, async (request: messages.ReportDeleteRequest) => {
|
||||||
const report = reports.getMutable(request.id);
|
const report = reports.getMutable(request.id);
|
||||||
if (!report) {
|
if (!report) {
|
||||||
throw new lib.RequestError(`Report with ID ${request.id} does not exist`);
|
throw new lib.NotFoundError(`Report with ID ${request.id} does not exist`);
|
||||||
}
|
}
|
||||||
reports.delete(report);
|
reports.delete(report);
|
||||||
});
|
});
|
||||||
@@ -211,7 +207,7 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
controller.handle(messages.ReportSetReadRequest, async (request: messages.ReportSetReadRequest) => {
|
controller.handle(messages.ReportSetReadRequest, async (request: messages.ReportSetReadRequest) => {
|
||||||
const report = reports.getMutable(request.id);
|
const report = reports.getMutable(request.id);
|
||||||
if (!report) {
|
if (!report) {
|
||||||
throw new lib.RequestError(`Report with ID ${request.id} does not exist`);
|
throw new lib.NotFoundError(`Report with ID ${request.id} does not exist`);
|
||||||
}
|
}
|
||||||
report.isRead = request.isRead;
|
report.isRead = request.isRead;
|
||||||
reports.set(report);
|
reports.set(report);
|
||||||
@@ -220,14 +216,14 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
controller.handle(messages.WatchListAddRequest, async (request: messages.WatchListAddRequest, src: lib.Address) => {
|
controller.handle(messages.WatchListAddRequest, async (request: messages.WatchListAddRequest, src: lib.Address) => {
|
||||||
const playerName = request.playerName.trim();
|
const playerName = request.playerName.trim();
|
||||||
if (!playerName) {
|
if (!playerName) {
|
||||||
throw new lib.RequestError("A player name is required");
|
throw new lib.ValidationError("A player name is required");
|
||||||
}
|
}
|
||||||
if (!request.reason.trim()) {
|
if (!request.reason.trim()) {
|
||||||
throw new lib.RequestError("A reason is required");
|
throw new lib.ValidationError("A reason is required");
|
||||||
}
|
}
|
||||||
const existing = watchList.get(playerName.toLowerCase());
|
const existing = watchList.get(playerName.toLowerCase());
|
||||||
if (existing) {
|
if (existing) {
|
||||||
throw new lib.RequestError(`${existing.playerName} is already on the watch list`);
|
throw new lib.ConflictError(`${existing.playerName} is already on the watch list`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const entry = new messages.WatchListRecord(playerName, request.reason.trim(), controlUserName(src), Date.now());
|
const entry = new messages.WatchListRecord(playerName, request.reason.trim(), controlUserName(src), Date.now());
|
||||||
@@ -238,7 +234,7 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
controller.handle(messages.WatchListRemoveRequest, async (request: messages.WatchListRemoveRequest) => {
|
controller.handle(messages.WatchListRemoveRequest, async (request: messages.WatchListRemoveRequest) => {
|
||||||
const entry = watchList.getMutable(request.playerName.toLowerCase());
|
const entry = watchList.getMutable(request.playerName.toLowerCase());
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
throw new lib.RequestError(`${request.playerName} is not on the watch list`);
|
throw new lib.NotFoundError(`${request.playerName} is not on the watch list`);
|
||||||
}
|
}
|
||||||
watchList.delete(entry);
|
watchList.delete(entry);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -37,15 +37,13 @@
|
|||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"antd": "catalog:",
|
"antd": "catalog:",
|
||||||
|
"fengari": "^0.1.5",
|
||||||
"react": "catalog:",
|
"react": "catalog:",
|
||||||
"react-dom": "catalog:",
|
"react-dom": "catalog:",
|
||||||
"react-router-dom": "catalog:",
|
"react-router-dom": "catalog:",
|
||||||
"typescript": "catalog:",
|
|
||||||
"webpack": "catalog:",
|
|
||||||
"fengari": "^0.1.5",
|
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"webpack-cli": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack-merge": "catalog:"
|
"vite": "catalog:"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:",
|
"@sinclair/typebox": "catalog:",
|
||||||
|
|||||||
@@ -31,20 +31,20 @@ async function startPlugin(t2, { reports = [report(1, "bob", "alice"), report(2,
|
|||||||
instanceConfig.set("instance.id", 1);
|
instanceConfig.set("instance.id", 1);
|
||||||
instanceConfig.set("instance.name", "test");
|
instanceConfig.set("instance.name", "test");
|
||||||
|
|
||||||
const instance = new Instance(
|
|
||||||
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), "factorioDir", instanceConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
// Spies which record the messages and commands leaving the instance
|
// Spies which record the messages and commands leaving the instance
|
||||||
const state = { sent: [], rcons: [], failNext: null };
|
const state = { sent: [], rcons: [], failNext: null };
|
||||||
const ipc = new Map();
|
const ipc = new Map();
|
||||||
instance.server = {
|
const server = {
|
||||||
|
on: () => {},
|
||||||
handle: (name, handler) => ipc.set(name, handler),
|
handle: (name, handler) => ipc.set(name, handler),
|
||||||
sendRcon: async command => {
|
sendRcon: async command => {
|
||||||
state.rcons.push(command);
|
state.rcons.push(command);
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const instance = new Instance(
|
||||||
|
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), instanceConfig, server
|
||||||
|
);
|
||||||
instance.sendTo = async (dst, request) => {
|
instance.sendTo = async (dst, request) => {
|
||||||
state.sent.push(request);
|
state.sent.push(request);
|
||||||
if (state.failNext) {
|
if (state.failNext) {
|
||||||
@@ -102,7 +102,7 @@ t.test("instance plugin", t2 => {
|
|||||||
|
|
||||||
t2.test("exp_reports:create prints a refusal to the reporter", async t3 => {
|
t2.test("exp_reports:create prints a refusal to the reporter", async t3 => {
|
||||||
const { state, createIPC } = await startPlugin(t3);
|
const { state, createIPC } = await startPlugin(t3);
|
||||||
state.failNext = new lib.RequestError("dave has already reported bob");
|
state.failNext = new lib.ConflictError("dave has already reported bob");
|
||||||
await createIPC({ player_name: "bob", by_player_name: "dave", reason: "griefing" });
|
await createIPC({ player_name: "bob", by_player_name: "dave", reason: "griefing" });
|
||||||
|
|
||||||
const { receiver, payload } = decodeRcon(state.rcons[0]);
|
const { receiver, payload } = decodeRcon(state.rcons[0]);
|
||||||
@@ -113,7 +113,7 @@ t.test("instance plugin", t2 => {
|
|||||||
t2.test("text that closes a long bracket stays inside the json", async t3 => {
|
t2.test("text that closes a long bracket stays inside the json", async t3 => {
|
||||||
const { state, createIPC } = await startPlugin(t3);
|
const { state, createIPC } = await startPlugin(t3);
|
||||||
const message = "]=]) game.print(1) --[==[ ]==] ]===]";
|
const message = "]=]) game.print(1) --[==[ ]==] ]===]";
|
||||||
state.failNext = new lib.RequestError(message);
|
state.failNext = new lib.ConflictError(message);
|
||||||
await createIPC({ player_name: "bob", by_player_name: "dave", reason: message });
|
await createIPC({ player_name: "bob", by_player_name: "dave", reason: message });
|
||||||
|
|
||||||
const { payload } = decodeRcon(state.rcons[0]);
|
const { payload } = decodeRcon(state.rcons[0]);
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_reports",
|
|
||||||
library: { type: "window", name: "plugin_exp_reports" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
"antd": { import: false },
|
|
||||||
"react": { import: false },
|
|
||||||
"react-dom": { import: false },
|
|
||||||
"react-router": { import: false },
|
|
||||||
"react-router-dom": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -22,12 +22,10 @@ export class ControllerPlugin {
|
|||||||
const controller = context.controller;
|
const controller = context.controller;
|
||||||
const databaseDirectory = controller.config.get("controller.database_directory");
|
const databaseDirectory = controller.config.get("controller.database_directory");
|
||||||
|
|
||||||
const roleMeta = new lib.SubscribableDatastore(
|
const roleMeta = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_roles", "role_meta.json"),
|
||||||
path.join(databaseDirectory, "exp_roles", "role_meta.json"),
|
messages.RoleMetaRecord.fromJSON.bind(messages.RoleMetaRecord),
|
||||||
messages.RoleMetaRecord.fromJSON.bind(messages.RoleMetaRecord),
|
));
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
const plugin = new ControllerPlugin(controller, context.logger, context.plugin.name, roleMeta);
|
const plugin = new ControllerPlugin(controller, context.logger, context.plugin.name, roleMeta);
|
||||||
loaded.set(controller, plugin);
|
loaded.set(controller, plugin);
|
||||||
@@ -149,7 +147,7 @@ export class ControllerPlugin {
|
|||||||
async handleRoleMetaUpdateRequest(request: messages.RoleMetaUpdateRequest) {
|
async handleRoleMetaUpdateRequest(request: messages.RoleMetaUpdateRequest) {
|
||||||
const meta = request.meta;
|
const meta = request.meta;
|
||||||
if (!this.controller.roles.has(meta.id)) {
|
if (!this.controller.roles.has(meta.id)) {
|
||||||
throw new lib.RequestError(`Role with ID ${meta.id} does not exist`);
|
throw new lib.NotFoundError(`Role with ID ${meta.id} does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.roleMeta.set(meta);
|
this.roleMeta.set(meta);
|
||||||
@@ -250,12 +248,12 @@ export class ControllerPlugin {
|
|||||||
async handleAssignmentUpdateRequest(request: messages.AssignmentUpdateRequest) {
|
async handleAssignmentUpdateRequest(request: messages.AssignmentUpdateRequest) {
|
||||||
const user = this.controller.users.getByNameMutable(request.name);
|
const user = this.controller.users.getByNameMutable(request.name);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new lib.RequestError(`User '${request.name}' does not exist`);
|
throw new lib.NotFoundError(`User '${request.name}' does not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const roleId of [...request.assign, ...request.unassign]) {
|
for (const roleId of [...request.assign, ...request.unassign]) {
|
||||||
if (!this.controller.roles.has(roleId)) {
|
if (!this.controller.roles.has(roleId)) {
|
||||||
throw new lib.RequestError(`Role with ID ${roleId} does not exist`);
|
throw new lib.NotFoundError(`Role with ID ${roleId} does not exist`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -37,15 +37,13 @@
|
|||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"antd": "catalog:",
|
"antd": "catalog:",
|
||||||
|
"fengari": "^0.1.5",
|
||||||
"react": "catalog:",
|
"react": "catalog:",
|
||||||
"react-dom": "catalog:",
|
"react-dom": "catalog:",
|
||||||
"react-router-dom": "catalog:",
|
"react-router-dom": "catalog:",
|
||||||
"typescript": "catalog:",
|
|
||||||
"webpack": "catalog:",
|
|
||||||
"fengari": "^0.1.5",
|
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"webpack-cli": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack-merge": "catalog:"
|
"vite": "catalog:"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:"
|
"@sinclair/typebox": "catalog:"
|
||||||
|
|||||||
@@ -40,21 +40,21 @@ async function startPlugin(t2, { syncMode = "bidirectional", roles = sampleRoles
|
|||||||
instanceConfig.set("instance.name", "test");
|
instanceConfig.set("instance.name", "test");
|
||||||
instanceConfig.set("exp_roles.sync_mode", syncMode);
|
instanceConfig.set("exp_roles.sync_mode", syncMode);
|
||||||
|
|
||||||
const instance = new Instance(
|
|
||||||
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), "factorioDir", instanceConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
// Spies which record the messages and commands leaving the instance
|
// Spies which record the messages and commands leaving the instance
|
||||||
const state = { sent: [], rcons: [], warnings: [], failNext: null };
|
const state = { sent: [], rcons: [], warnings: [], failNext: null };
|
||||||
const handlers = new Map();
|
const handlers = new Map();
|
||||||
instance.handle = (Event, handler) => handlers.set(Event, handler);
|
const server = {
|
||||||
instance.server = {
|
on: () => {},
|
||||||
handle: (name, handler) => handlers.set(name, handler),
|
handle: (name, handler) => handlers.set(name, handler),
|
||||||
sendRcon: async command => {
|
sendRcon: async command => {
|
||||||
state.rcons.push(command);
|
state.rcons.push(command);
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const instance = new Instance(
|
||||||
|
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), instanceConfig, server
|
||||||
|
);
|
||||||
|
instance.handle = (Event, handler) => handlers.set(Event, handler);
|
||||||
instance.sendTo = async (dst, request) => {
|
instance.sendTo = async (dst, request) => {
|
||||||
state.sent.push(request);
|
state.sent.push(request);
|
||||||
if (state.failNext) {
|
if (state.failNext) {
|
||||||
@@ -96,10 +96,10 @@ t.test("entrypoint", async t2 => {
|
|||||||
const instanceConfig = new lib.InstanceConfig("host");
|
const instanceConfig = new lib.InstanceConfig("host");
|
||||||
instanceConfig.set("instance.id", 1);
|
instanceConfig.set("instance.id", 1);
|
||||||
instanceConfig.set("instance.name", "test");
|
instanceConfig.set("instance.name", "test");
|
||||||
|
const server = { on: () => {}, handle: () => {} };
|
||||||
const instance = new Instance(
|
const instance = new Instance(
|
||||||
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), "factorioDir", instanceConfig
|
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), instanceConfig, server
|
||||||
);
|
);
|
||||||
instance.server = { handle: () => {} };
|
|
||||||
await entrypoint({ instance, host: {}, logger, plugin: { name: "exp_roles" } });
|
await entrypoint({ instance, host: {}, logger, plugin: { name: "exp_roles" } });
|
||||||
for (const hook of ["instanceConfigFieldChanged", "start"]) {
|
for (const hook of ["instanceConfigFieldChanged", "start"]) {
|
||||||
t2.ok([...instance.hooks[hook].attached].includes("exp_roles"), `attached to ${hook}`);
|
t2.ok([...instance.hooks[hook].attached].includes("exp_roles"), `attached to ${hook}`);
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_roles",
|
|
||||||
library: { type: "window", name: "plugin_exp_roles" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
"antd": { import: false },
|
|
||||||
"react": { import: false },
|
|
||||||
"react-dom": { import: false },
|
|
||||||
"react-router": { import: false },
|
|
||||||
"react-router-dom": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
+10
-14
@@ -12,18 +12,14 @@ import { SeedRole, SeedGroup, seedRoles, seedGroups, flattenSeedPermissions } fr
|
|||||||
export default async function (context: ControllerPluginContext) {
|
export default async function (context: ControllerPluginContext) {
|
||||||
const { controller, logger, plugin } = context;
|
const { controller, logger, plugin } = context;
|
||||||
const databaseDirectory = controller.config.get("controller.database_directory");
|
const databaseDirectory = controller.config.get("controller.database_directory");
|
||||||
const featureStore = new lib.SubscribableDatastore(
|
const featureStore = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
path.join(databaseDirectory, "exp_scenario", "features.json"),
|
||||||
path.join(databaseDirectory, "exp_scenario", "features.json"),
|
messages.FeatureRecord.fromJSON.bind(messages.FeatureRecord),
|
||||||
messages.FeatureRecord.fromJSON.bind(messages.FeatureRecord),
|
));
|
||||||
).bootstrap()
|
const playerStore = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||||
);
|
path.join(databaseDirectory, "exp_scenario", "players.json"),
|
||||||
const playerStore = new lib.SubscribableDatastore(
|
messages.PlayerRecord.fromJSON.bind(messages.PlayerRecord),
|
||||||
...await new lib.JsonIdDatastoreProvider(
|
));
|
||||||
path.join(databaseDirectory, "exp_scenario", "players.json"),
|
|
||||||
messages.PlayerRecord.fromJSON.bind(messages.PlayerRecord),
|
|
||||||
).bootstrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
type PlayerSettings = Pick<messages.PlayerRecord, "joinMessage" | "toolbar">;
|
type PlayerSettings = Pick<messages.PlayerRecord, "joinMessage" | "toolbar">;
|
||||||
|
|
||||||
@@ -179,7 +175,7 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
const rolesPlugin = RolesPlugin.get(controller);
|
const rolesPlugin = RolesPlugin.get(controller);
|
||||||
const groupsPlugin = GroupsPlugin.get(controller);
|
const groupsPlugin = GroupsPlugin.get(controller);
|
||||||
if (!rolesPlugin || !groupsPlugin) {
|
if (!rolesPlugin || !groupsPlugin) {
|
||||||
throw new lib.RequestError("Seeding requires the exp_roles and exp_groups plugins");
|
throw new lib.UnavailableError("Seeding requires the exp_roles and exp_groups plugins");
|
||||||
}
|
}
|
||||||
|
|
||||||
const roleIds = new Map<string, number>();
|
const roleIds = new Map<string, number>();
|
||||||
@@ -218,7 +214,7 @@ export default async function (context: ControllerPluginContext) {
|
|||||||
try {
|
try {
|
||||||
values = validateFeatureValues(request.id, request.values);
|
values = validateFeatureValues(request.id, request.values);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
throw new lib.RequestError(err.message);
|
throw new lib.ValidationError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
const feature = new messages.FeatureRecord(request.id, request.enabled, values);
|
const feature = new messages.FeatureRecord(request.id, request.enabled, values);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -41,9 +41,7 @@
|
|||||||
"react-dom": "catalog:",
|
"react-dom": "catalog:",
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expcluster/lib_commands": "workspace:^",
|
"@expcluster/lib_commands": "workspace:^",
|
||||||
|
|||||||
@@ -32,19 +32,19 @@ async function startPlugin(
|
|||||||
instanceConfig.set("instance.id", 1);
|
instanceConfig.set("instance.id", 1);
|
||||||
instanceConfig.set("instance.name", "test");
|
instanceConfig.set("instance.name", "test");
|
||||||
|
|
||||||
const instance = new Instance(
|
|
||||||
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), "factorioDir", instanceConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
const state = { sent: [], rcons: [] };
|
const state = { sent: [], rcons: [] };
|
||||||
const ipcHandlers = new Map();
|
const ipcHandlers = new Map();
|
||||||
instance.server = {
|
const server = {
|
||||||
|
on: () => {},
|
||||||
handle: (channel, handler) => ipcHandlers.set(channel, handler),
|
handle: (channel, handler) => ipcHandlers.set(channel, handler),
|
||||||
sendRcon: async command => {
|
sendRcon: async command => {
|
||||||
state.rcons.push(command);
|
state.rcons.push(command);
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const instance = new Instance(
|
||||||
|
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), instanceConfig, server
|
||||||
|
);
|
||||||
instance.sendTo = async (dst, request) => {
|
instance.sendTo = async (dst, request) => {
|
||||||
state.sent.push(request);
|
state.sent.push(request);
|
||||||
if (request instanceof messages.PlayerGetRequest) {
|
if (request instanceof messages.PlayerGetRequest) {
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_scenario",
|
|
||||||
library: { type: "window", name: "plugin_exp_scenario" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
"antd": { import: false },
|
|
||||||
"react": { import: false },
|
|
||||||
"react-dom": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -24,7 +24,6 @@ export const plugin: lib.PluginDeclaration = {
|
|||||||
name: "exp_server_list",
|
name: "exp_server_list",
|
||||||
title: "ExpGaming - Server List",
|
title: "ExpGaming - Server List",
|
||||||
description: "Clusterio plugin sharing the details of every instance with the others",
|
description: "Clusterio plugin sharing the details of every instance with the others",
|
||||||
webEntrypoint: "./web",
|
|
||||||
|
|
||||||
controllerEntrypoint: "./dist/node/controller.js",
|
controllerEntrypoint: "./dist/node/controller.js",
|
||||||
instanceEntrypoint: "./dist/node/instance.js",
|
instanceEntrypoint: "./dist/node/instance.js",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production",
|
"prepare": "tsc --build && vite build",
|
||||||
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
"test": "tap --type-strip-only --disable-coverage --allow-empty-coverage test/*.test.js",
|
||||||
"coverage": "tap --coverage-report=text test/*.test.js"
|
"coverage": "tap --coverage-report=text test/*.test.js"
|
||||||
},
|
},
|
||||||
@@ -37,9 +37,7 @@
|
|||||||
"fengari": "^0.1.5",
|
"fengari": "^0.1.5",
|
||||||
"tap": "^21.1.0",
|
"tap": "^21.1.0",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:",
|
"@sinclair/typebox": "catalog:",
|
||||||
|
|||||||
@@ -35,18 +35,19 @@ async function startPlugin(t2, servers = [server(1), server(2)]) {
|
|||||||
instanceConfig.set("instance.id", 1);
|
instanceConfig.set("instance.id", 1);
|
||||||
instanceConfig.set("instance.name", "test");
|
instanceConfig.set("instance.name", "test");
|
||||||
|
|
||||||
const instance = new Instance(
|
|
||||||
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), "factorioDir", instanceConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
const state = { sent: [], rcons: [] };
|
const state = { sent: [], rcons: [] };
|
||||||
instance.server = {
|
const server = {
|
||||||
|
on: () => {},
|
||||||
handle: () => {},
|
handle: () => {},
|
||||||
sendRcon: async command => {
|
sendRcon: async command => {
|
||||||
state.rcons.push(command);
|
state.rcons.push(command);
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const instance = new Instance(
|
||||||
|
{ assignGamePort: () => 1 }, new TestConnector(), t2.testdir(), instanceConfig, server
|
||||||
|
);
|
||||||
instance.sendTo = async (dst, request) => {
|
instance.sendTo = async (dst, request) => {
|
||||||
if (request instanceof lib.InstanceStatusChangedEvent) {
|
if (request instanceof lib.InstanceStatusChangedEvent) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.browser.json",
|
"extends": "../tsconfig.browser.json",
|
||||||
"include": [ "web/**/*.tsx", "web/**/*.ts", "index.ts", "messages.ts", "package.json" ],
|
"include": [ "index.ts", "messages.ts", "package.json" ],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default function() {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_server_list",
|
|
||||||
library: { type: "window", name: "plugin_exp_server_list" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -11,7 +11,6 @@ export const plugin: lib.PluginDeclaration = {
|
|||||||
name: "exp_server_ups",
|
name: "exp_server_ups",
|
||||||
title: "ExpGaming - Server UPS",
|
title: "ExpGaming - Server UPS",
|
||||||
description: "Clusterio plugin providing in game server ups counter",
|
description: "Clusterio plugin providing in game server ups counter",
|
||||||
webEntrypoint: "./web",
|
|
||||||
|
|
||||||
instanceEntrypoint: "./dist/node/instance.js",
|
instanceEntrypoint: "./dist/node/instance.js",
|
||||||
instanceConfigFields: {
|
instanceConfigFields: {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production"
|
"prepare": "tsc --build && vite build"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -25,11 +25,10 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clusterio/host": "workspace:^",
|
"@clusterio/host": "workspace:^",
|
||||||
"@clusterio/lib": "workspace:^",
|
"@clusterio/lib": "workspace:^",
|
||||||
"typescript": "catalog:",
|
"@clusterio/web_ui": "workspace:^",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"webpack": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack-cli": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:",
|
"@sinclair/typebox": "catalog:",
|
||||||
@@ -45,4 +44,4 @@
|
|||||||
"clusterio-plugin",
|
"clusterio-plugin",
|
||||||
"factorio"
|
"factorio"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.browser.json",
|
"extends": "../tsconfig.browser.json",
|
||||||
"include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ],
|
"include": [ "index.ts", "package.json" ],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default function() {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_server_ups",
|
|
||||||
library: { type: "window", name: "plugin_exp_server_ups" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -5,5 +5,4 @@ export const plugin: lib.PluginDeclaration = {
|
|||||||
title: "ExpGaming - Module Utilities",
|
title: "ExpGaming - Module Utilities",
|
||||||
description: "Provides extensions and overrides of base Lua library functions, and provides utility modules for improved module compatibly",
|
description: "Provides extensions and overrides of base Lua library functions, and provides utility modules for improved module compatibly",
|
||||||
instanceEntrypoint: "./dist/node/instance.js",
|
instanceEntrypoint: "./dist/node/instance.js",
|
||||||
webEntrypoint: "./web",
|
|
||||||
};
|
};
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/node/index.js",
|
"main": "dist/node/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "tsc --build && webpack-cli --env production"
|
"prepare": "tsc --build && vite build"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -25,11 +25,10 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clusterio/host": "workspace:^",
|
"@clusterio/host": "workspace:^",
|
||||||
"@clusterio/lib": "workspace:^",
|
"@clusterio/lib": "workspace:^",
|
||||||
|
"@clusterio/web_ui": "workspace:^",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"webpack": "catalog:",
|
"vite": "catalog:"
|
||||||
"webpack-cli": "catalog:",
|
|
||||||
"webpack-merge": "catalog:"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "catalog:"
|
"@sinclair/typebox": "catalog:"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.browser.json",
|
"extends": "../tsconfig.browser.json",
|
||||||
"include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ],
|
"include": [ "index.ts", "package.json" ],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { clusterioPlugin } from "@clusterio/web_ui/vite.mjs";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [clusterioPlugin()],
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default function() {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
|
|
||||||
const common = require("@clusterio/web_ui/webpack.common");
|
|
||||||
|
|
||||||
module.exports = (env = {}) => merge(common(env), {
|
|
||||||
context: __dirname,
|
|
||||||
entry: "./web/index.tsx",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist", "web"),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.container.ModuleFederationPlugin({
|
|
||||||
name: "exp_util",
|
|
||||||
library: { type: "window", name: "plugin_exp_util" },
|
|
||||||
exposes: {
|
|
||||||
"./": "./index.ts",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
"./web": "./web/index.tsx",
|
|
||||||
},
|
|
||||||
shared: {
|
|
||||||
"@clusterio/lib": { import: false },
|
|
||||||
"@clusterio/web_ui": { import: false },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
Reference in new issue
Block a user