mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Prefix clusterio/lib imports with lib
Use lib* prefix for the modules impored from the lib package to help distinguish them more from ordinary variables. Fix up the naming convention for files to be consistently lowercase_underscore for JavaScript files.
This commit is contained in:
1 parent
fbbaf3dd3a
commit
24397b75cc
55 files changed
+692
-668
No files matched your search
@@ -20,6 +20,7 @@ Contents
|
||||
- [Changelog](#changelog)
|
||||
- [Supported Node.js and Factorio Version](#supported-node.js-and-factorio-version)
|
||||
- [Code Style](#code-style)
|
||||
- [Naming Style](#naming-style)
|
||||
- [Indenting](#indenting)
|
||||
- [Line Length](#line-length)
|
||||
|
||||
@@ -206,6 +207,29 @@ The style of the code is a bit of a mixed bag at the moment. But there
|
||||
are at least a few things that have been agreed upon.
|
||||
|
||||
|
||||
### Naming style
|
||||
|
||||
JavaScript variables in general uses camelCase. The exception is for
|
||||
classes/constructors which use PascalCase and variables destructured
|
||||
from over the wire objects.
|
||||
|
||||
Fields in configs and messages sent over links uses
|
||||
lowercase_underscore.
|
||||
|
||||
JavaScript files are named using lowercase_underscore for files that
|
||||
export multiple items. Files containing and exporting a single class
|
||||
should be named the same as the class in PascalCase.
|
||||
|
||||
Imported modules from the lib package are prefixed with lib to make them
|
||||
easier to distinguish, as the names tend to be very generic. E.g.:
|
||||
|
||||
const libLink = require("lib/link");
|
||||
const libLuaTools = require("lib/lua_tools");
|
||||
|
||||
|
||||
For lua code lowercase_underscore is used for everything.
|
||||
|
||||
|
||||
### Strings
|
||||
|
||||
JavaScript and Lua code should use double quoted strings (`"string"`)
|
||||
|
||||
@@ -55,7 +55,7 @@ clusterioctl. Note that it's important that the path starts with ./ or
|
||||
For a plugin the most important file is the `info.js` file. Without it
|
||||
the plugin will not recognized by Clusterio. Here's an example of it:
|
||||
|
||||
const link = require('@clusterio/lib/link'); // For messages
|
||||
const libLink = require('@clusterio/lib/link'); // For messages
|
||||
|
||||
module.exports = {
|
||||
name: "foo_frobber",
|
||||
@@ -136,9 +136,9 @@ The plugin class should derive from its respective base class defined in
|
||||
`lib/plugin`. For example, to define a MasterPlugin class the following
|
||||
code can be used:
|
||||
|
||||
const plugin = require('@clusterio/lib/plugin');
|
||||
const libPlugin = require('@clusterio/lib/plugin');
|
||||
|
||||
class MasterPlugin extends plugin.BaseMasterPlugin {
|
||||
class MasterPlugin extends libPlugin.BaseMasterPlugin {
|
||||
async init() {
|
||||
this.foo = 42;
|
||||
await this.startFrobnication();
|
||||
@@ -180,9 +180,9 @@ take advantage of it by subclassing `PluginConfigGroup`, setting the
|
||||
and passing it as either `MasterConfigGroup` or `InstanceConfigGroup` in
|
||||
the `info.js` export. For example in info.js:
|
||||
|
||||
const config = require("@clusterio/lib/config");
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
|
||||
class MasterConfigGroup extends config.PluginConfigGroup { }
|
||||
class MasterConfigGroup extends libConfig.PluginConfigGroup { }
|
||||
MasterConfigGroup.groupName = "foo_frobber";
|
||||
MasterConfigGroup.define({
|
||||
name: "level",
|
||||
@@ -323,7 +323,7 @@ class. The Event constructor takes an object of properties that define
|
||||
the event, for example the following could be defined in `info.js`:
|
||||
|
||||
messages: {
|
||||
startFrobnication: new link.Event({
|
||||
startFrobnication: new libLink.Event({
|
||||
type: 'foo_frobber:start_frobnication',
|
||||
links: ['master-slave', 'slave-instance'],
|
||||
forwardTo: 'instance',
|
||||
@@ -408,7 +408,7 @@ class. The Request constructor takes an object of properties that define
|
||||
the event. For example, the following could be defined in `info.js`:
|
||||
|
||||
messages: {
|
||||
reportFrobnication: new link.Request({
|
||||
reportFrobnication: new libLink.Request({
|
||||
type: 'foo_frobber:report_frobnication',
|
||||
links: ['master-slave', 'slave-instance'],
|
||||
forwardTo: 'instance',
|
||||
@@ -648,9 +648,9 @@ for how to define the messages that can be sent to the master.
|
||||
To have the command tree become part of clusterioctl it needs to be added
|
||||
to the rootCommand tree in `addCommands` callback of the Control plugin:
|
||||
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
|
||||
class ControlPlugin extends plugin.BaseControlPlugin {
|
||||
class ControlPlugin extends libPlugin.BaseControlPlugin {
|
||||
async addCommands(rootCommand) {
|
||||
rootCommand.add(fooFrobberCommands);
|
||||
}
|
||||
|
||||
+115
-115
@@ -13,12 +13,12 @@ const chalk = require("chalk");
|
||||
const events = require("events");
|
||||
const path = require("path");
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const config = require("@clusterio/lib/config");
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const command = require("@clusterio/lib/command");
|
||||
const sharedCommands = require("@clusterio/lib/shared_commands");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libCommand = require("@clusterio/lib/command");
|
||||
const libSharedCommands = require("@clusterio/lib/shared_commands");
|
||||
|
||||
|
||||
/**
|
||||
@@ -59,16 +59,16 @@ function formatOutputColored(output) {
|
||||
return time + info + output.message;
|
||||
}
|
||||
|
||||
const slaveCommands = new command.CommandTree({ name: "slave", description: "Slave management" });
|
||||
slaveCommands.add(new command.Command({
|
||||
const slaveCommands = new libCommand.CommandTree({ name: "slave", description: "Slave management" });
|
||||
slaveCommands.add(new libCommand.Command({
|
||||
definition: [["list", "l"], "List slaves connected to the master"],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.listSlaves.send(control);
|
||||
let response = await libLink.messages.listSlaves.send(control);
|
||||
console.log(asTable(response.list));
|
||||
},
|
||||
}));
|
||||
|
||||
slaveCommands.add(new command.Command({
|
||||
slaveCommands.add(new libCommand.Command({
|
||||
definition: ["generate-token", "Generate token for a slave", (yargs) => {
|
||||
yargs.option("id", { type: "number", nargs: 1, describe: "Slave id", demandOption: true });
|
||||
}],
|
||||
@@ -78,7 +78,7 @@ slaveCommands.add(new command.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
slaveCommands.add(new command.Command({
|
||||
slaveCommands.add(new libCommand.Command({
|
||||
definition: ["create-config", "Create slave config", (yargs) => {
|
||||
yargs.option("id", { type: "number", nargs: 1, describe: "Slave id", default: null });
|
||||
yargs.option("name", { type: "string", nargs: 1, describe: "Slave name", default: null });
|
||||
@@ -90,7 +90,7 @@ slaveCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.createSlaveConfig.send(control, {
|
||||
let response = await libLink.messages.createSlaveConfig.send(control, {
|
||||
id: args.id, name: args.name, generate_token: args.generateToken,
|
||||
});
|
||||
|
||||
@@ -103,7 +103,7 @@ slaveCommands.add(new command.Command({
|
||||
await fs.outputFile(args.output, content, { flag: "wx" });
|
||||
} catch (err) {
|
||||
if (err.code === "EEXIST") {
|
||||
throw new errors.CommandError(`File ${args.output} already exists`);
|
||||
throw new libErrors.CommandError(`File ${args.output} already exists`);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@@ -112,18 +112,18 @@ slaveCommands.add(new command.Command({
|
||||
}));
|
||||
|
||||
|
||||
const instanceCommands = new command.CommandTree({
|
||||
const instanceCommands = new libCommand.CommandTree({
|
||||
name: "instance", alias: ["i"], description: "Instance management",
|
||||
});
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: [["list", "l"], "List instances known to the master"],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.listInstances.send(control);
|
||||
let response = await libLink.messages.listInstances.send(control);
|
||||
console.log(asTable(response.list));
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["create <name>", "Create an instance", (yargs) => {
|
||||
// XXX TODO: set any specific options?
|
||||
yargs.positional("name", { describe: "Instance name", type: "string" });
|
||||
@@ -132,27 +132,27 @@ instanceCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.init();
|
||||
if (args.id) {
|
||||
instanceConfig.set("instance.id", args.id);
|
||||
}
|
||||
instanceConfig.set("instance.name", args.name);
|
||||
let serialized_config = instanceConfig.serialize();
|
||||
let response = await link.messages.createInstance.send(control, { serialized_config });
|
||||
let response = await libLink.messages.createInstance.send(control, { serialized_config });
|
||||
},
|
||||
}));
|
||||
|
||||
const instanceConfigCommands = new command.CommandTree({
|
||||
const instanceConfigCommands = new libCommand.CommandTree({
|
||||
name: "config", alias: ["c"], description: "Instance config management",
|
||||
});
|
||||
instanceConfigCommands.add(new command.Command({
|
||||
instanceConfigCommands.add(new libCommand.Command({
|
||||
definition: ["list <instance>", "List configuration for an instance", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to list config for", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
let response = await link.messages.getInstanceConfig.send(control, { instance_id: instanceId });
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
let response = await libLink.messages.getInstanceConfig.send(control, { instance_id: instanceId });
|
||||
|
||||
for (let group of response.serialized_config.groups) {
|
||||
for (let [name, value] of Object.entries(group.fields)) {
|
||||
@@ -162,15 +162,15 @@ instanceConfigCommands.add(new command.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
instanceConfigCommands.add(new command.Command({
|
||||
instanceConfigCommands.add(new libCommand.Command({
|
||||
definition: ["set <instance> <field> <value>", "Set field in instance config", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to set config on", type: "string" });
|
||||
yargs.positional("field", { describe: "Field to set", type: "string" });
|
||||
yargs.positional("value", { describe: "Value to set", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceConfigField.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceConfigField.send(control, {
|
||||
instance_id: instanceId,
|
||||
field: args.field,
|
||||
value: args.value,
|
||||
@@ -178,7 +178,7 @@ instanceConfigCommands.add(new command.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
instanceConfigCommands.add(new command.Command({
|
||||
instanceConfigCommands.add(new libCommand.Command({
|
||||
definition: ["set-prop <instance> <field> <prop> <value>", "Set property of field in instance config", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to set config on", type: "string" });
|
||||
yargs.positional("field", { describe: "Field to set", type: "string" });
|
||||
@@ -186,8 +186,8 @@ instanceConfigCommands.add(new command.Command({
|
||||
yargs.positional("value", { describe: "JSON parsed value to set", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceConfigProp.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceConfigProp.send(control, {
|
||||
instance_id: instanceId,
|
||||
field: args.field,
|
||||
prop: args.prop,
|
||||
@@ -197,48 +197,48 @@ instanceConfigCommands.add(new command.Command({
|
||||
}));
|
||||
instanceCommands.add(instanceConfigCommands);
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["assign <instance> <slave>", "Assign instance to a slave", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to assign", type: "string" });
|
||||
yargs.positional("slave", { describe: "Slave to assign to", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
let slaveId = await command.resolveSlave(control, args.slave);
|
||||
await link.messages.assignInstanceCommand.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
let slaveId = await libCommand.resolveSlave(control, args.slave);
|
||||
await libLink.messages.assignInstanceCommand.send(control, {
|
||||
instance_id: instanceId,
|
||||
slave_id: slaveId,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["create-save <instance>", "Create a new save on an instance", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to create on", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await link.messages.createSave.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await libLink.messages.createSave.send(control, {
|
||||
instance_id: instanceId,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["export-data <instance>", "Export item icons and locale from instance", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to export from", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await link.messages.exportData.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await libLink.messages.exportData.send(control, {
|
||||
instance_id: instanceId,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["start <instance>", "Start instance", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to start", type: "string" });
|
||||
yargs.options({
|
||||
@@ -247,16 +247,16 @@ instanceCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await link.messages.startInstance.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await libLink.messages.startInstance.send(control, {
|
||||
instance_id: instanceId,
|
||||
save: args.save || null,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["load-scenario <instance> <scenario>", "Start instance by loading a scenario", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to start", type: "string" });
|
||||
yargs.positional("scenario", { describe: "Scenario to load", type: "string" });
|
||||
@@ -265,47 +265,47 @@ instanceCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await link.messages.loadScenario.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await libLink.messages.loadScenario.send(control, {
|
||||
instance_id: instanceId,
|
||||
scenario: args.scenario || null,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["stop <instance>", "Stop instance", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to stop", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let instanceId = await command.resolveInstance(control, args.instance);
|
||||
await link.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await link.messages.stopInstance.send(control, {
|
||||
let instanceId = await libCommand.resolveInstance(control, args.instance);
|
||||
await libLink.messages.setInstanceOutputSubscriptions.send(control, { instance_ids: [instanceId] });
|
||||
let response = await libLink.messages.stopInstance.send(control, {
|
||||
instance_id: instanceId,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["delete <instance>", "Delete instance", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to delete", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.deleteInstance.send(control, {
|
||||
instance_id: await command.resolveInstance(control, args.instance),
|
||||
let response = await libLink.messages.deleteInstance.send(control, {
|
||||
instance_id: await libCommand.resolveInstance(control, args.instance),
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
instanceCommands.add(new command.Command({
|
||||
instanceCommands.add(new libCommand.Command({
|
||||
definition: ["send-rcon <instance> <command>", "Send RCON command", (yargs) => {
|
||||
yargs.positional("instance", { describe: "Instance to send to", type: "string" });
|
||||
yargs.positional("command", { describe: "command to send", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.sendRcon.send(control, {
|
||||
instance_id: await command.resolveInstance(control, args.instance),
|
||||
let response = await libLink.messages.sendRcon.send(control, {
|
||||
instance_id: await libCommand.resolveInstance(control, args.instance),
|
||||
command: args.command,
|
||||
});
|
||||
|
||||
@@ -314,26 +314,26 @@ instanceCommands.add(new command.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
const permissionCommands = new command.CommandTree({ name: "permission", description: "Permission inspection" });
|
||||
permissionCommands.add(new command.Command({
|
||||
const permissionCommands = new libCommand.CommandTree({ name: "permission", description: "Permission inspection" });
|
||||
permissionCommands.add(new libCommand.Command({
|
||||
definition: [["list", "l"], "List permissions in the cluster"],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.listPermissions.send(control);
|
||||
let response = await libLink.messages.listPermissions.send(control);
|
||||
console.log(asTable(response.list));
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const roleCommands = new command.CommandTree({ name: "role", description: "Role management" });
|
||||
roleCommands.add(new command.Command({
|
||||
const roleCommands = new libCommand.CommandTree({ name: "role", description: "Role management" });
|
||||
roleCommands.add(new libCommand.Command({
|
||||
definition: [["list", "l"], "List roles in the cluster"],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.listRoles.send(control);
|
||||
let response = await libLink.messages.listRoles.send(control);
|
||||
console.log(asTable(response.list));
|
||||
},
|
||||
}));
|
||||
|
||||
roleCommands.add(new command.Command({
|
||||
roleCommands.add(new libCommand.Command({
|
||||
definition: ["create <name>", "Create a new role", (yargs) => {
|
||||
yargs.positional("name", { describe: "Name of role to create", type: "string" });
|
||||
yargs.options({
|
||||
@@ -342,7 +342,7 @@ roleCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.createRole.send(control, {
|
||||
let response = await libLink.messages.createRole.send(control, {
|
||||
name: args.name,
|
||||
description: args.description,
|
||||
permissions: args.permissions,
|
||||
@@ -351,7 +351,7 @@ roleCommands.add(new command.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
roleCommands.add(new command.Command({
|
||||
roleCommands.add(new libCommand.Command({
|
||||
definition: ["edit <role>", "Edit existing role", (yargs) => {
|
||||
yargs.positional("role", { describe: "Role to edit", type: "string" });
|
||||
yargs.options({
|
||||
@@ -362,7 +362,7 @@ roleCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let role = await command.retrieveRole(control, args.role);
|
||||
let role = await libCommand.retrieveRole(control, args.role);
|
||||
|
||||
if (args.name !== undefined) {
|
||||
role.name = args.name;
|
||||
@@ -373,44 +373,44 @@ roleCommands.add(new command.Command({
|
||||
if (args.permissions !== undefined) {
|
||||
role.permissions = args.permissions;
|
||||
}
|
||||
await link.messages.updateRole.send(control, role);
|
||||
await libLink.messages.updateRole.send(control, role);
|
||||
|
||||
if (args.grantDefault) {
|
||||
await link.messages.grantDefaultRolePermissions.send(control, { id: role.id });
|
||||
await libLink.messages.grantDefaultRolePermissions.send(control, { id: role.id });
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
roleCommands.add(new command.Command({
|
||||
roleCommands.add(new libCommand.Command({
|
||||
definition: ["delete <role>", "Delete role", (yargs) => {
|
||||
yargs.positional("role", { describe: "Role to delete", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let role = await command.retrieveRole(control, args.role);
|
||||
await link.messages.deleteRole.send(control, { id: role.id });
|
||||
let role = await libCommand.retrieveRole(control, args.role);
|
||||
await libLink.messages.deleteRole.send(control, { id: role.id });
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const userCommands = new command.CommandTree({ name: "user", alias: ["u"], description: "User management" });
|
||||
userCommands.add(new command.Command({
|
||||
const userCommands = new libCommand.CommandTree({ name: "user", alias: ["u"], description: "User management" });
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: [["list", "l"], "List user in the cluster"],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.listUsers.send(control);
|
||||
let response = await libLink.messages.listUsers.send(control);
|
||||
console.log(asTable(response.list));
|
||||
},
|
||||
}));
|
||||
|
||||
userCommands.add(new command.Command({
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: ["create <name>", "Create a user", (yargs) => {
|
||||
yargs.positional("name", { describe: "Name of user to create", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
await link.messages.createUser.send(control, { name: args.name });
|
||||
await libLink.messages.createUser.send(control, { name: args.name });
|
||||
},
|
||||
}));
|
||||
|
||||
userCommands.add(new command.Command({
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: ["set-admin <user>", "Promote or demote a user to admin", (yargs) => {
|
||||
yargs.positional("user", { describe: "Name of user set admin status for", type: "string" });
|
||||
yargs.options({
|
||||
@@ -419,13 +419,13 @@ userCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
await link.messages.setUserAdmin.send(control, {
|
||||
await libLink.messages.setUserAdmin.send(control, {
|
||||
name: args.user, create: args.create, admin: !args.revoke,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
userCommands.add(new command.Command({
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: ["set-whitelisted <user>", "Add or remove user from the whitelist", (yargs) => {
|
||||
yargs.positional("user", { describe: "Name of user to set whitelist status for", type: "string" });
|
||||
yargs.options({
|
||||
@@ -434,13 +434,13 @@ userCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
await link.messages.setUserWhitelisted.send(control, {
|
||||
await libLink.messages.setUserWhitelisted.send(control, {
|
||||
name: args.user, create: args.create, whitelisted: !args.remove,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
userCommands.add(new command.Command({
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: ["set-banned <user>", "Ban or pardon user from banlist", (yargs) => {
|
||||
yargs.positional("user", { describe: "Name of user to set ban status for", type: "string" });
|
||||
yargs.options({
|
||||
@@ -450,19 +450,19 @@ userCommands.add(new command.Command({
|
||||
});
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
await link.messages.setUserBanned.send(control, {
|
||||
await libLink.messages.setUserBanned.send(control, {
|
||||
name: args.user, create: args.create, banned: !args.pardon, reason: args.reason,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
userCommands.add(new command.Command({
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: ["set-roles <user> [roles...]", "Replace user roles", (yargs) => {
|
||||
yargs.positional("user", { describe: "Name of user to change roles for", type: "string" });
|
||||
yargs.positional("roles", { describe: "roles to assign", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
let response = await link.messages.listRoles.send(control);
|
||||
let response = await libLink.messages.listRoles.send(control);
|
||||
|
||||
let resolvedRoles = [];
|
||||
for (let roleName of args.roles) {
|
||||
@@ -481,29 +481,29 @@ userCommands.add(new command.Command({
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw new errors.CommandError(`No role named ${roleName}`);
|
||||
throw new libErrors.CommandError(`No role named ${roleName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await link.messages.updateUserRoles.send(control, { name: args.user, roles: resolvedRoles });
|
||||
await libLink.messages.updateUserRoles.send(control, { name: args.user, roles: resolvedRoles });
|
||||
},
|
||||
}));
|
||||
|
||||
userCommands.add(new command.Command({
|
||||
userCommands.add(new libCommand.Command({
|
||||
definition: ["delete <user>", "Delete user", (yargs) => {
|
||||
yargs.positional("user", { describe: "Name of user to delete", type: "string" });
|
||||
}],
|
||||
handler: async function(args, control) {
|
||||
await link.messages.deleteUser.send(control, { name: args.user });
|
||||
await libLink.messages.deleteUser.send(control, { name: args.user });
|
||||
},
|
||||
}));
|
||||
|
||||
const debugCommands = new command.CommandTree({ name: "debug", description: "Debugging utilities" });
|
||||
debugCommands.add(new command.Command({
|
||||
const debugCommands = new libCommand.CommandTree({ name: "debug", description: "Debugging utilities" });
|
||||
debugCommands.add(new libCommand.Command({
|
||||
definition: ["dump-ws", "Dump WebSocket messages sent and received by master", (yargs) => { }],
|
||||
handler: async function(args, control) {
|
||||
await link.messages.debugDumpWs.send(control);
|
||||
await libLink.messages.debugDumpWs.send(control);
|
||||
return new Promise(() => {});
|
||||
},
|
||||
}));
|
||||
@@ -513,7 +513,7 @@ debugCommands.add(new command.Command({
|
||||
* Connector for control connection to master server
|
||||
* @private
|
||||
*/
|
||||
class ControlConnector extends link.WebSocketClientConnector {
|
||||
class ControlConnector extends libLink.WebSocketClientConnector {
|
||||
constructor(url, reconnectDelay, token) {
|
||||
super(url, reconnectDelay);
|
||||
this._token = token;
|
||||
@@ -535,11 +535,11 @@ class ControlConnector extends link.WebSocketClientConnector {
|
||||
* Connects to the master server over WebSocket and sends commands to it.
|
||||
* @static
|
||||
*/
|
||||
class Control extends link.Link {
|
||||
class Control extends libLink.Link {
|
||||
|
||||
constructor(connector, controlPlugins) {
|
||||
super("control", "master", connector);
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
|
||||
/**
|
||||
* Mapping of plugin names to their instance for loaded plugins.
|
||||
@@ -547,7 +547,7 @@ class Control extends link.Link {
|
||||
*/
|
||||
this.plugins = controlPlugins;
|
||||
for (let controlPlugin of controlPlugins.values()) {
|
||||
plugin.attachPluginMessages(this, controlPlugin.info, controlPlugin);
|
||||
libPlugin.attachPluginMessages(this, controlPlugin.info, controlPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,9 +564,9 @@ class Control extends link.Link {
|
||||
this.connector.setTimeout(30);
|
||||
|
||||
try {
|
||||
await link.messages.prepareDisconnect.send(this);
|
||||
await libLink.messages.prepareDisconnect.send(this);
|
||||
} catch (err) {
|
||||
if (!(err instanceof errors.SessionLost)) {
|
||||
if (!(err instanceof libErrors.SessionLost)) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -593,8 +593,8 @@ async function startControl() {
|
||||
default: "plugin-list.json",
|
||||
type: "string",
|
||||
})
|
||||
.command("plugin", "Manage available plugins", sharedCommands.pluginCommand)
|
||||
.command("control-config", "Manage Control config", config.configCommand)
|
||||
.command("plugin", "Manage available plugins", libSharedCommands.pluginCommand)
|
||||
.command("control-config", "Manage Control config", libConfig.configCommand)
|
||||
.wrap(yargs.terminalWidth())
|
||||
.help(false) // Disable help to avoid triggering it on the first parse.
|
||||
;
|
||||
@@ -614,12 +614,12 @@ async function startControl() {
|
||||
|
||||
// If the command is plugin management we don't try to load plugins
|
||||
if (args._[0] === "plugin") {
|
||||
await sharedCommands.handlePluginCommand(args, pluginList, args.pluginList);
|
||||
await libSharedCommands.handlePluginCommand(args, pluginList, args.pluginList);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add all cluster management commands including ones from plugins
|
||||
const rootCommands = new command.CommandTree({ name: "clusterioctl", description: "Manage cluster" });
|
||||
const rootCommands = new libCommand.CommandTree({ name: "clusterioctl", description: "Manage cluster" });
|
||||
rootCommands.add(slaveCommands);
|
||||
rootCommands.add(instanceCommands);
|
||||
rootCommands.add(permissionCommands);
|
||||
@@ -628,9 +628,9 @@ async function startControl() {
|
||||
rootCommands.add(debugCommands);
|
||||
|
||||
console.log("Loading Plugin info");
|
||||
let pluginInfos = await plugin.loadPluginInfos(pluginList);
|
||||
config.registerPluginConfigGroups(pluginInfos);
|
||||
config.finalizeConfigs();
|
||||
let pluginInfos = await libPlugin.loadPluginInfos(pluginList);
|
||||
libConfig.registerPluginConfigGroups(pluginInfos);
|
||||
libConfig.finalizeConfigs();
|
||||
|
||||
let controlPlugins = new Map();
|
||||
for (let pluginInfo of pluginInfos) {
|
||||
@@ -659,7 +659,7 @@ async function startControl() {
|
||||
;
|
||||
|
||||
console.log(`Loading config from ${args.config}`);
|
||||
let controlConfig = new config.ControlConfig();
|
||||
let controlConfig = new libConfig.ControlConfig();
|
||||
try {
|
||||
await controlConfig.load(JSON.parse(await fs.readFile(args.config)));
|
||||
|
||||
@@ -680,14 +680,14 @@ async function startControl() {
|
||||
|
||||
// Handle the control-config command before trying to connect.
|
||||
if (args._[0] === "control-config") {
|
||||
await config.handleConfigCommand(args, controlConfig, args.config);
|
||||
await libConfig.handleConfigCommand(args, controlConfig, args.config);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine which command is being executed.
|
||||
let commandPath = [...args._];
|
||||
let targetCommand = rootCommands;
|
||||
while (commandPath.length && targetCommand instanceof command.CommandTree) {
|
||||
while (commandPath.length && targetCommand instanceof libCommand.CommandTree) {
|
||||
targetCommand = targetCommand.get(commandPath.shift());
|
||||
}
|
||||
|
||||
@@ -707,8 +707,8 @@ async function startControl() {
|
||||
try {
|
||||
await controlConnector.connect();
|
||||
} catch(err) {
|
||||
if (err instanceof errors.AuthenticationFailed) {
|
||||
throw new errors.StartupError(err.message);
|
||||
if (err instanceof libErrors.AuthenticationFailed) {
|
||||
throw new libErrors.StartupError(err.message);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@@ -727,11 +727,11 @@ async function startControl() {
|
||||
|
||||
} catch (err) {
|
||||
keepOpen = false;
|
||||
if (err instanceof errors.CommandError) {
|
||||
if (err instanceof libErrors.CommandError) {
|
||||
console.error(`Error running command: ${err.message}`);
|
||||
process.exitCode = 1;
|
||||
|
||||
} else if (err instanceof errors.RequestError) {
|
||||
} else if (err instanceof libErrors.RequestError) {
|
||||
console.error(`Error sending request: ${err.message}`);
|
||||
process.exitCode = 1;
|
||||
|
||||
@@ -763,7 +763,7 @@ I version of clusterio. Expect things to break. I
|
||||
`
|
||||
);
|
||||
startControl().catch(err => {
|
||||
if (!(err instanceof errors.StartupError)) {
|
||||
if (!(err instanceof libErrors.StartupError)) {
|
||||
console.error(`
|
||||
+----------------------------------------------------------------+
|
||||
| Unexpected error occured while starting control, please report |
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
* @module lib/command
|
||||
*/
|
||||
"use strict";
|
||||
const link = require("@clusterio/lib/link");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
/**
|
||||
* Represents a command that can be runned by clusterioctl
|
||||
@@ -150,7 +150,7 @@ async function resolveSlave(client, slaveName) {
|
||||
if (/^-?\d+$/.test(slaveName)) {
|
||||
slaveId = parseInt(slaveName, 10);
|
||||
} else {
|
||||
let response = await link.messages.listSlaves.send(client);
|
||||
let response = await libLink.messages.listSlaves.send(client);
|
||||
for (let slave of response.list) {
|
||||
if (slave.name === slaveName) {
|
||||
slaveId = slave.id;
|
||||
@@ -159,7 +159,7 @@ async function resolveSlave(client, slaveName) {
|
||||
}
|
||||
|
||||
if (slaveId === undefined) {
|
||||
throw new errors.CommandError(`No slave named ${slaveName}`);
|
||||
throw new libErrors.CommandError(`No slave named ${slaveName}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ async function resolveInstance(client, instanceName) {
|
||||
if (/^-?\d+$/.test(instanceName)) {
|
||||
instanceId = parseInt(instanceName, 10);
|
||||
} else {
|
||||
let response = await link.messages.listInstances.send(client);
|
||||
let response = await libLink.messages.listInstances.send(client);
|
||||
for (let instance of response.list) {
|
||||
if (instance.name === instanceName) {
|
||||
instanceId = instance.id;
|
||||
@@ -191,7 +191,7 @@ async function resolveInstance(client, instanceName) {
|
||||
}
|
||||
|
||||
if (instanceId === undefined) {
|
||||
throw new errors.CommandError(`No instance named ${instanceName}`);
|
||||
throw new libErrors.CommandError(`No instance named ${instanceName}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ async function resolveInstance(client, instanceName) {
|
||||
* @static
|
||||
*/
|
||||
async function retrieveRole(client, roleName) {
|
||||
let response = await link.messages.listRoles.send(client);
|
||||
let response = await libLink.messages.listRoles.send(client);
|
||||
|
||||
let resolvedRole;
|
||||
if (/^-?\d+$/.test(roleName)) {
|
||||
@@ -232,7 +232,7 @@ async function retrieveRole(client, roleName) {
|
||||
}
|
||||
|
||||
if (!resolvedRole) {
|
||||
throw new errors.CommandError(`No role named ${roleName}`);
|
||||
throw new libErrors.CommandError(`No role named ${roleName}`);
|
||||
}
|
||||
|
||||
return resolvedRole;
|
||||
|
||||
@@ -6,7 +6,7 @@ const ini = require("ini");
|
||||
const Jimp = require("jimp");
|
||||
const JSZip = require("jszip");
|
||||
|
||||
const buildMod = require("@clusterio/lib/build_mod");
|
||||
const libBuildMod = require("@clusterio/lib/build_mod");
|
||||
|
||||
/**
|
||||
* Generate the export mod needed for exportData
|
||||
@@ -29,7 +29,7 @@ async function generateExportMod(server) {
|
||||
}
|
||||
}
|
||||
|
||||
await buildMod.build({
|
||||
await libBuildMod.build({
|
||||
clean: false,
|
||||
build: true,
|
||||
pack: true,
|
||||
|
||||
@@ -7,7 +7,7 @@ const jszip = require("jszip");
|
||||
const path = require("path");
|
||||
const semver = require("semver");
|
||||
|
||||
const hash = require("@clusterio/lib/hash");
|
||||
const libHash = require("@clusterio/lib/hash");
|
||||
|
||||
|
||||
const knownScenarios = {
|
||||
@@ -225,7 +225,7 @@ async function patch(savePath, modules) {
|
||||
// No info file present, try to detect if it's a known compatible scenario.
|
||||
} else {
|
||||
let controlStream = root.file("control.lua").nodeStream("nodebuffer");
|
||||
let controlHash = await hash.hashStream(controlStream);
|
||||
let controlHash = await libHash.hashStream(controlStream);
|
||||
|
||||
if (controlHash in knownScenarios) {
|
||||
patchInfo = {
|
||||
|
||||
@@ -9,7 +9,7 @@ const crypto = require("crypto");
|
||||
|
||||
const ini = require("ini");
|
||||
const rconClient = require("rcon-client");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
|
||||
/**
|
||||
@@ -705,7 +705,7 @@ class FactorioServer extends events.EventEmitter {
|
||||
if (this._state !== "stopping") {
|
||||
if (this._unexpected.length === 0) {
|
||||
if (signal === "SIGKILL") {
|
||||
this.emit("error", new errors.EnvironmentError(
|
||||
this.emit("error", new libErrors.EnvironmentError(
|
||||
"Factorio server was unexpectedly killed, is the system low on memory?"
|
||||
));
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"use strict";
|
||||
const fileOps = require("./fileOps");
|
||||
module.exports = fileOps;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @module lib/fileOps
|
||||
* @module lib/file_ops
|
||||
*/
|
||||
"use strict";
|
||||
const fs = require("fs-extra");
|
||||
@@ -3,8 +3,8 @@
|
||||
const events = require("events");
|
||||
const WebSocket = require("isomorphic-ws");
|
||||
|
||||
const schema = require("@clusterio/lib/schema");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
|
||||
/**
|
||||
@@ -60,10 +60,10 @@ class WebSocketBaseConnector extends events.EventEmitter {
|
||||
}
|
||||
|
||||
_processHeartbeat(message) {
|
||||
if (!schema.heartbeat(message)) {
|
||||
if (!libSchema.heartbeat(message)) {
|
||||
console.log("SOCKET | closing after received invalid heartbeat:", message);
|
||||
this._socket.close(1002, "Invalid heartbeat");
|
||||
console.log(schema.heartbeat.errors);
|
||||
console.log(libSchema.heartbeat.errors);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ class WebSocketBaseConnector extends events.EventEmitter {
|
||||
*/
|
||||
send(type, data) {
|
||||
if (!["handshake", "connected", "closing"].includes(this._state)) {
|
||||
throw new errors.SessionLost("No session");
|
||||
throw new libErrors.SessionLost("No session");
|
||||
}
|
||||
let message = { seq: this._seq, type, data };
|
||||
this._sendBuffer.push(message);
|
||||
@@ -287,7 +287,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
console.log(`SOCKET | Close (code: ${event.code}, reason: ${event.reason})`);
|
||||
// Authentication failed
|
||||
if (event.code === 4003) {
|
||||
this.emit("error", new errors.AuthenticationFailed(event.reason));
|
||||
this.emit("error", new libErrors.AuthenticationFailed(event.reason));
|
||||
this._state = "closing";
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
}
|
||||
|
||||
_processHandshake(message) {
|
||||
if (!schema.serverHandshake(message)) {
|
||||
if (!libSchema.serverHandshake(message)) {
|
||||
console.log("SOCKET | closing after received invalid handshake:", message);
|
||||
this._socket.close(1002, "Invalid handshake");
|
||||
return;
|
||||
|
||||
+10
-10
@@ -1,8 +1,8 @@
|
||||
// Implementation of Link class
|
||||
"use strict";
|
||||
|
||||
const schema = require("@clusterio/lib/schema");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const messages = require("./messages");
|
||||
|
||||
// Some definitions for the terminology used here:
|
||||
@@ -34,7 +34,7 @@ class Link {
|
||||
try {
|
||||
this.processMessage(payload);
|
||||
} catch (err) {
|
||||
if (err instanceof errors.InvalidMessage) {
|
||||
if (err instanceof libErrors.InvalidMessage) {
|
||||
console.error(`Invalid message on ${this.source}-${this.target} link: ${err.message}`);
|
||||
if (err.errors) {
|
||||
console.error(err.errors);
|
||||
@@ -48,7 +48,7 @@ class Link {
|
||||
connector.on("invalidate", () => {
|
||||
for (let waiterType of this._waiters.values()) {
|
||||
for (let waiter of waiterType) {
|
||||
waiter.reject(new errors.SessionLost("Session Lost"));
|
||||
waiter.reject(new libErrors.SessionLost("Session Lost"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class Link {
|
||||
connector.on("close", () => {
|
||||
for (let waiterType of this._waiters.values()) {
|
||||
for (let waiter of waiterType) {
|
||||
waiter.reject(new errors.SessionLost("Session Closed"));
|
||||
waiter.reject(new libErrors.SessionLost("Session Closed"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,17 +78,17 @@ class Link {
|
||||
* handlers/waiters were invoked to handle the message.
|
||||
*/
|
||||
processMessage(message) {
|
||||
if (!schema.message(message)) {
|
||||
throw new errors.InvalidMessage("Malformed", schema.message.errors);
|
||||
if (!libSchema.message(message)) {
|
||||
throw new libErrors.InvalidMessage("Malformed", libSchema.message.errors);
|
||||
}
|
||||
|
||||
let validator = this._validators.get(message.type);
|
||||
if (!validator) {
|
||||
throw new errors.InvalidMessage(`No validator for ${message.type} on ${this.source}-${this.target}`);
|
||||
throw new libErrors.InvalidMessage(`No validator for ${message.type} on ${this.source}-${this.target}`);
|
||||
}
|
||||
|
||||
if (!validator(message)) {
|
||||
throw new errors.InvalidMessage(`Validation failed for ${message.type}`, validator.errors);
|
||||
throw new libErrors.InvalidMessage(`Validation failed for ${message.type}`, validator.errors);
|
||||
}
|
||||
|
||||
let hadHandlers = this._processHandler(message);
|
||||
@@ -96,7 +96,7 @@ class Link {
|
||||
|
||||
if (!hadWaiters && !hadHandlers) {
|
||||
// XXX console.error(`Unhandled message: ${JSON.stringify(message, null, 4)}`);
|
||||
throw new errors.InvalidMessage(`Unhandled message ${message.type}`);
|
||||
throw new libErrors.InvalidMessage(`Unhandled message ${message.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Message definitions for links
|
||||
"use strict";
|
||||
const schema = require("@clusterio/lib/schema");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
/**
|
||||
* Represents a message that can be sent over the link
|
||||
@@ -88,7 +88,7 @@ class Request extends Message {
|
||||
throw new Error(`Invalid forwardTo value ${forwardTo}`);
|
||||
}
|
||||
|
||||
this._requestValidator = schema.compile({
|
||||
this._requestValidator = libSchema.compile({
|
||||
$schema: "http://json-schema.org/draft-07/schema#",
|
||||
properties: {
|
||||
"type": { const: this.requestType },
|
||||
@@ -100,7 +100,7 @@ class Request extends Message {
|
||||
},
|
||||
});
|
||||
|
||||
this._responseValidator = schema.compile({
|
||||
this._responseValidator = libSchema.compile({
|
||||
$schema: "http://json-schema.org/draft-07/schema#",
|
||||
properties: {
|
||||
"type": { const: this.responseType },
|
||||
@@ -195,7 +195,7 @@ class Request extends Message {
|
||||
link.connector.send(this.responseType, { ...response, seq: message.seq });
|
||||
|
||||
}).catch(err => {
|
||||
if (!(err instanceof errors.RequestError)) {
|
||||
if (!(err instanceof libErrors.RequestError)) {
|
||||
console.error(`Unexpected error while responding to ${this.requestType}`, err);
|
||||
}
|
||||
link.connector.send(this.responseType, { seq: message.seq, error: err.message });
|
||||
@@ -223,7 +223,7 @@ class Request extends Message {
|
||||
let seq = link.connector.send(this.requestType, data);
|
||||
let responseMessage = await link.waitFor(this.responseType, { seq });
|
||||
if (responseMessage.data.error) {
|
||||
throw new errors.RequestError(responseMessage.data.error);
|
||||
throw new libErrors.RequestError(responseMessage.data.error);
|
||||
}
|
||||
return responseMessage.data;
|
||||
}
|
||||
@@ -702,7 +702,7 @@ class Event extends Message {
|
||||
}
|
||||
|
||||
this.eventType = type + "_event";
|
||||
this._eventValidator = schema.compile({
|
||||
this._eventValidator = libSchema.compile({
|
||||
$schema: "http://json-schema.org/draft-07/schema#",
|
||||
properties: {
|
||||
"type": { const: this.eventType },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Utilities for dealing with Lua
|
||||
* @module lib/luaTools
|
||||
* @module lib/lua_tools
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
File renamed without changes.
@@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
const path = require("path");
|
||||
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
|
||||
/**
|
||||
@@ -409,11 +409,11 @@ async function loadPluginInfos(pluginList) {
|
||||
pluginPackage = require(path.posix.join(pluginPath, "package.json"));
|
||||
|
||||
} catch (err) {
|
||||
throw new errors.PluginError(pluginName, err);
|
||||
throw new libErrors.PluginError(pluginName, err);
|
||||
}
|
||||
|
||||
if (pluginInfo.name !== pluginName) {
|
||||
throw new errors.EnvironmentError(
|
||||
throw new libErrors.EnvironmentError(
|
||||
`Expected plugin at ${pluginPath} to be named ${pluginName} but got ${pluginInfo.name}`
|
||||
);
|
||||
}
|
||||
|
||||
+101
-101
@@ -42,17 +42,17 @@ let pluginList = {};
|
||||
let devMiddleware;
|
||||
|
||||
// homebrew modules
|
||||
const generateSSLcert = require("./src/generate_ssl_cert");
|
||||
const generateSslCert = require("./src/generate_ssl_cert");
|
||||
const routes = require("./src/routes");
|
||||
const database = require("@clusterio/lib/database");
|
||||
const schema = require("@clusterio/lib/schema");
|
||||
const link = require("@clusterio/lib/link");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const prometheus = require("@clusterio/lib/prometheus");
|
||||
const config = require("@clusterio/lib/config");
|
||||
const users = require("@clusterio/lib/users");
|
||||
const sharedCommands = require("@clusterio/lib/shared_commands");
|
||||
const libDatabase = require("@clusterio/lib/database");
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libPrometheus = require("@clusterio/lib/prometheus");
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
const libUsers = require("@clusterio/lib/users");
|
||||
const libSharedCommands = require("@clusterio/lib/shared_commands");
|
||||
|
||||
const express = require("express");
|
||||
const compression = require("compression");
|
||||
@@ -100,34 +100,34 @@ function serveWeb(route) {
|
||||
app.use(express.static(path.join(__dirname, "static")));
|
||||
app.use(express.static("static")); // Used for data export files
|
||||
|
||||
const endpointHitCounter = new prometheus.Counter(
|
||||
const endpointHitCounter = new libPrometheus.Counter(
|
||||
"clusterio_master_http_endpoint_hits_total",
|
||||
"How many requests a particular HTTP endpoint has gotten",
|
||||
{ labels: ["route"] }
|
||||
);
|
||||
|
||||
const wsMessageCounter = new prometheus.Counter(
|
||||
const wsMessageCounter = new libPrometheus.Counter(
|
||||
"clusterio_master_websocket_message_total",
|
||||
"How many messages have been received over WebSocket on the master server",
|
||||
{ labels: ["direction"] }
|
||||
);
|
||||
|
||||
const wsConnectionsCounter = new prometheus.Counter(
|
||||
const wsConnectionsCounter = new libPrometheus.Counter(
|
||||
"clusterio_master_websocket_connections_total",
|
||||
"How many WebSocket connections have been initiated on the master server"
|
||||
);
|
||||
|
||||
const wsRejectedConnectionsCounter = new prometheus.Counter(
|
||||
const wsRejectedConnectionsCounter = new libPrometheus.Counter(
|
||||
"clusterio_master_websocket_rejected_connections_total",
|
||||
"How many WebSocket connections have been rejected during the handshake on the master server"
|
||||
);
|
||||
|
||||
const wsActiveConnectionsGauge = new prometheus.Gauge(
|
||||
const wsActiveConnectionsGauge = new libPrometheus.Gauge(
|
||||
"clusterio_master_websocket_active_connections",
|
||||
"How many WebSocket connections are currently open to the master server"
|
||||
);
|
||||
|
||||
const wsActiveSlavesGauge = new prometheus.Gauge(
|
||||
const wsActiveSlavesGauge = new libPrometheus.Gauge(
|
||||
"clusterio_master_active_slaves",
|
||||
"How many slaves are currently connected to the master"
|
||||
);
|
||||
@@ -137,7 +137,7 @@ async function getMetrics(req, res, next) {
|
||||
endpointHitCounter.labels(req.route.path).inc();
|
||||
|
||||
let results = [];
|
||||
let pluginResults = await plugin.invokeHook(masterPlugins, "onMetrics");
|
||||
let pluginResults = await libPlugin.invokeHook(masterPlugins, "onMetrics");
|
||||
for (let metricIterator of pluginResults) {
|
||||
for await (let metric of metricIterator) {
|
||||
results.push(metric);
|
||||
@@ -147,10 +147,10 @@ async function getMetrics(req, res, next) {
|
||||
let requests = [];
|
||||
for (let slaveConnection of slaveConnections.values()) {
|
||||
// XXX this needs a timeout
|
||||
requests.push(link.messages.getMetrics.send(slaveConnection));
|
||||
requests.push(libLink.messages.getMetrics.send(slaveConnection));
|
||||
}
|
||||
|
||||
for await (let result of await prometheus.defaultRegistry.collect()) {
|
||||
for await (let result of await libPrometheus.defaultRegistry.collect()) {
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
@@ -169,15 +169,15 @@ async function getMetrics(req, res, next) {
|
||||
}
|
||||
|
||||
for (let result of resultMap.values()) {
|
||||
results.push(prometheus.deserializeResult(result));
|
||||
results.push(libPrometheus.deserializeResult(result));
|
||||
}
|
||||
|
||||
wsActiveConnectionsGauge.set(activeConnectors.size);
|
||||
wsActiveSlavesGauge.set(slaveConnections.size);
|
||||
|
||||
|
||||
let text = await prometheus.exposition(results);
|
||||
res.set("Content-Type", prometheus.exposition.contentType);
|
||||
let text = await libPrometheus.exposition(results);
|
||||
res.set("Content-Type", libPrometheus.exposition.contentType);
|
||||
res.send(text);
|
||||
}
|
||||
app.get("/metrics", (req, res, next) => getMetrics(req, res, next).catch(next));
|
||||
@@ -241,7 +241,7 @@ app.put("/api/upload-export",
|
||||
(req, res, next) => uploadExport(req, res, next).catch(next)
|
||||
);
|
||||
|
||||
const masterConnectedClientsCount = new prometheus.Gauge(
|
||||
const masterConnectedClientsCount = new libPrometheus.Gauge(
|
||||
"clusterio_master_connected_clients_count", "How many clients are currently connected to this master server",
|
||||
{
|
||||
labels: ["type"], callback: async function(gauge) {
|
||||
@@ -264,7 +264,7 @@ const db = {};
|
||||
async function loadMap(databaseDirectory, file) {
|
||||
let databasePath = path.resolve(databaseDirectory, file);
|
||||
console.log(`Loading ${databasePath}`);
|
||||
return await database.loadJsonArrayAsMap(databasePath);
|
||||
return await libDatabase.loadJsonArrayAsMap(databasePath);
|
||||
}
|
||||
|
||||
async function loadInstances(databaseDirectory, file) {
|
||||
@@ -275,7 +275,7 @@ async function loadInstances(databaseDirectory, file) {
|
||||
try {
|
||||
let serialized = JSON.parse(await fs.readFile(filePath));
|
||||
for (let serializedConfig of serialized) {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.load(serializedConfig);
|
||||
let status = instanceConfig.get("instance.assigned_slave") === null ? "unassigned" : "unknown";
|
||||
instances.set(instanceConfig.get("instance.id"), { config: instanceConfig, status });
|
||||
@@ -296,12 +296,12 @@ async function loadUsers(databaseDirectory, file) {
|
||||
try {
|
||||
let content = JSON.parse(await fs.readFile(path.join(databaseDirectory, file)));
|
||||
for (let serializedRole of content.roles) {
|
||||
let role = new users.Role(serializedRole);
|
||||
let role = new libUsers.Role(serializedRole);
|
||||
loadedRoles.set(role.id, role);
|
||||
}
|
||||
|
||||
for (let serializedUser of content.users) {
|
||||
let user = new users.User(serializedUser, loadedRoles);
|
||||
let user = new libUsers.User(serializedUser, loadedRoles);
|
||||
loadedUsers.set(user.name, user);
|
||||
}
|
||||
|
||||
@@ -311,8 +311,8 @@ async function loadUsers(databaseDirectory, file) {
|
||||
}
|
||||
|
||||
// Create default roles if loading failed
|
||||
users.ensureDefaultAdminRole(loadedRoles);
|
||||
users.ensureDefaultPlayerRole(loadedRoles);
|
||||
libUsers.ensureDefaultAdminRole(loadedRoles);
|
||||
libUsers.ensureDefaultPlayerRole(loadedRoles);
|
||||
}
|
||||
|
||||
db.roles = loadedRoles;
|
||||
@@ -333,7 +333,7 @@ function createUser(name) {
|
||||
}
|
||||
|
||||
let defaultRoleId = masterConfig.get("master.default_role_id");
|
||||
let user = new users.User({ name, roles: [defaultRoleId] }, db.roles);
|
||||
let user = new libUsers.User({ name, roles: [defaultRoleId] }, db.roles);
|
||||
db.users.set(name, user);
|
||||
return user;
|
||||
}
|
||||
@@ -348,7 +348,7 @@ function createUser(name) {
|
||||
async function saveMap(databaseDirectory, file, map) {
|
||||
let databasePath = path.resolve(databaseDirectory, file);
|
||||
console.log(`Saving ${databasePath}`);
|
||||
await database.saveMapAsJsonArray(databasePath, map);
|
||||
await libDatabase.saveMapAsJsonArray(databasePath, map);
|
||||
}
|
||||
|
||||
async function saveInstances(databaseDirectory, file, instances) {
|
||||
@@ -394,7 +394,7 @@ async function shutdown() {
|
||||
await saveInstances(masterConfig.get("master.database_directory"), "instances.json", db.instances);
|
||||
await saveUsers(masterConfig.get("master.database_directory"), "users.json");
|
||||
|
||||
await plugin.invokeHook(masterPlugins, "onShutdown");
|
||||
await libPlugin.invokeHook(masterPlugins, "onShutdown");
|
||||
|
||||
stopAcceptingNewSessions = true;
|
||||
|
||||
@@ -418,7 +418,7 @@ async function shutdown() {
|
||||
try {
|
||||
await task;
|
||||
} catch (err) {
|
||||
if (!(err instanceof errors.SessionLost)) {
|
||||
if (!(err instanceof libErrors.SessionLost)) {
|
||||
console.log("Unexpected error disconnecting connector");
|
||||
console.log(err);
|
||||
}
|
||||
@@ -455,32 +455,32 @@ async function shutdown() {
|
||||
*
|
||||
* @extends module:lib/link.Link
|
||||
*/
|
||||
class BaseConnection extends link.Link {
|
||||
class BaseConnection extends libLink.Link {
|
||||
constructor(target, connector) {
|
||||
super("master", target, connector);
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
for (let masterPlugin of masterPlugins.values()) {
|
||||
plugin.attachPluginMessages(this, masterPlugin.info, masterPlugin);
|
||||
libPlugin.attachPluginMessages(this, masterPlugin.info, masterPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
async forwardRequestToInstance(message, request) {
|
||||
let instance = db.instances.get(message.data.instance_id);
|
||||
if (!instance) {
|
||||
throw new errors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
}
|
||||
|
||||
let slaveId = instance.config.get("instance.assigned_slave");
|
||||
if (slaveId === null) {
|
||||
throw new errors.RequestError("Instance is not assigned to a slave");
|
||||
throw new libErrors.RequestError("Instance is not assigned to a slave");
|
||||
}
|
||||
|
||||
let connection = slaveConnections.get(slaveId);
|
||||
if (!connection) {
|
||||
throw new errors.RequestError("Slave containing instance is not connected");
|
||||
throw new libErrors.RequestError("Slave containing instance is not connected");
|
||||
}
|
||||
if (request.plugin && !connection.plugins.has(request.plugin)) {
|
||||
throw new errors.RequestError(`Slave containing instance does not have ${request.plugin} plugin`);
|
||||
throw new libErrors.RequestError(`Slave containing instance does not have ${request.plugin} plugin`);
|
||||
}
|
||||
|
||||
return await request.send(connection, message.data);
|
||||
@@ -516,16 +516,16 @@ class BaseConnection extends link.Link {
|
||||
}
|
||||
|
||||
async prepareDisconnectRequestHandler(message, request) {
|
||||
await plugin.invokeHook(masterPlugins, "onPrepareSlaveDisconnect", this);
|
||||
await libPlugin.invokeHook(masterPlugins, "onPrepareSlaveDisconnect", this);
|
||||
this.connector.setClosing();
|
||||
return await super.prepareDisconnectRequestHandler(message, request);
|
||||
}
|
||||
|
||||
async disconnect(code, reason) {
|
||||
try {
|
||||
await link.messages.prepareDisconnect.send(this);
|
||||
await libLink.messages.prepareDisconnect.send(this);
|
||||
} catch (err) {
|
||||
if (!(err instanceof errors.SessionLost)) {
|
||||
if (!(err instanceof libErrors.SessionLost)) {
|
||||
console.error("Unexpected error preparing disconnect");
|
||||
console.error(err);
|
||||
}
|
||||
@@ -592,7 +592,7 @@ class ControlConnection extends BaseConnection {
|
||||
}
|
||||
|
||||
async createSlaveConfigRequestHandler(message) {
|
||||
let slaveConfig = new config.SlaveConfig();
|
||||
let slaveConfig = new libConfig.SlaveConfig();
|
||||
await slaveConfig.init();
|
||||
|
||||
slaveConfig.set("slave.master_url", getMasterUrl());
|
||||
@@ -624,12 +624,12 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
// XXX should probably add a hook for slave reuqests?
|
||||
async createInstanceRequestHandler(message) {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.load(message.data.serialized_config);
|
||||
|
||||
let instanceId = instanceConfig.get("instance.id");
|
||||
if (db.instances.has(instanceId)) {
|
||||
throw new errors.RequestError(`Instance with ID ${instanceId} already exists`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${instanceId} already exists`);
|
||||
}
|
||||
db.instances.set(instanceId, { config: instanceConfig, status: "unassigned" });
|
||||
}
|
||||
@@ -637,7 +637,7 @@ class ControlConnection extends BaseConnection {
|
||||
async deleteInstanceRequestHandler(message, request) {
|
||||
let instance = db.instances.get(message.data.instance_id);
|
||||
if (!instance) {
|
||||
throw new errors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
}
|
||||
|
||||
if (instance.config.get("instance.assigned_slave") !== null) {
|
||||
@@ -649,7 +649,7 @@ class ControlConnection extends BaseConnection {
|
||||
async getInstanceConfigRequestHandler(message) {
|
||||
let instance = db.instances.get(message.data.instance_id);
|
||||
if (!instance) {
|
||||
throw new errors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -662,7 +662,7 @@ class ControlConnection extends BaseConnection {
|
||||
if (slaveId) {
|
||||
let connection = slaveConnections.get(slaveId);
|
||||
if (connection) {
|
||||
await link.messages.assignInstance.send(connection, {
|
||||
await libLink.messages.assignInstance.send(connection, {
|
||||
instance_id: instance.config.get("instance.id"),
|
||||
serialized_config: instance.config.serialize(),
|
||||
});
|
||||
@@ -673,16 +673,16 @@ class ControlConnection extends BaseConnection {
|
||||
async setInstanceConfigFieldRequestHandler(message) {
|
||||
let instance = db.instances.get(message.data.instance_id);
|
||||
if (!instance) {
|
||||
throw new errors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
}
|
||||
|
||||
if (message.data.field === "instance.assigned_slave") {
|
||||
throw new errors.RequestError("instance.assigned_slave must be set through the assign-slave interface");
|
||||
throw new libErrors.RequestError("instance.assigned_slave must be set through the assign-slave interface");
|
||||
}
|
||||
|
||||
if (message.data.field === "instance.id") {
|
||||
// XXX is this worth implementing? It's race condition galore.
|
||||
throw new errors.RequestError("Setting instance.id is not supported");
|
||||
throw new libErrors.RequestError("Setting instance.id is not supported");
|
||||
}
|
||||
|
||||
instance.config.set(message.data.field, message.data.value);
|
||||
@@ -692,7 +692,7 @@ class ControlConnection extends BaseConnection {
|
||||
async setInstanceConfigPropRequestHandler(message) {
|
||||
let instance = db.instances.get(message.data.instance_id);
|
||||
if (!instance) {
|
||||
throw new errors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
}
|
||||
|
||||
let { field, prop, value } = message.data;
|
||||
@@ -703,7 +703,7 @@ class ControlConnection extends BaseConnection {
|
||||
async assignInstanceCommandRequestHandler(message, request) {
|
||||
let instance = db.instances.get(message.data.instance_id);
|
||||
if (!instance) {
|
||||
throw new errors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
|
||||
}
|
||||
|
||||
// XXX: Should the instance be stopped if it's running on another slave?
|
||||
@@ -715,12 +715,12 @@ class ControlConnection extends BaseConnection {
|
||||
// target slave be connected to the master while doing the
|
||||
// assignment, but it is IMHO a better user experience if this
|
||||
// is the case.
|
||||
throw new errors.RequestError("Target slave is not connected to the master server");
|
||||
throw new libErrors.RequestError("Target slave is not connected to the master server");
|
||||
}
|
||||
|
||||
instance.config.set("instance.assigned_slave", message.data.slave_id);
|
||||
|
||||
return await link.messages.assignInstance.send(connection, {
|
||||
return await libLink.messages.assignInstance.send(connection, {
|
||||
instance_id: instance.config.get("instance.id"),
|
||||
serialized_config: instance.config.serialize(),
|
||||
});
|
||||
@@ -732,7 +732,7 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
async listPermissionsRequestHandler(message) {
|
||||
let list = [];
|
||||
for (let permission of users.permissions.values()) {
|
||||
for (let permission of libUsers.permissions.values()) {
|
||||
list.push({
|
||||
name: permission.name,
|
||||
title: permission.title,
|
||||
@@ -760,7 +760,7 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
// Start at 5 to leave space for future default roles
|
||||
let id = Math.max(5, lastId+1);
|
||||
db.roles.set(id, new users.Role({ id, ...message.data }));
|
||||
db.roles.set(id, new libUsers.Role({ id, ...message.data }));
|
||||
return { id };
|
||||
}
|
||||
|
||||
@@ -768,7 +768,7 @@ class ControlConnection extends BaseConnection {
|
||||
let { id, name, description, permissions } = message.data;
|
||||
let role = db.roles.get(id);
|
||||
if (!role) {
|
||||
throw new errors.RequestError(`Role with ID ${id} does not exist`);
|
||||
throw new libErrors.RequestError(`Role with ID ${id} does not exist`);
|
||||
}
|
||||
|
||||
role.name = name;
|
||||
@@ -779,7 +779,7 @@ class ControlConnection extends BaseConnection {
|
||||
async grantDefaultRolePermissionsRequestHandler(message) {
|
||||
let role = db.roles.get(message.data.id);
|
||||
if (!role) {
|
||||
throw new errors.RequestError(`Role with ID ${message.data.id} does not exist`);
|
||||
throw new libErrors.RequestError(`Role with ID ${message.data.id} does not exist`);
|
||||
}
|
||||
|
||||
role.grantDefaultPermissions();
|
||||
@@ -789,7 +789,7 @@ class ControlConnection extends BaseConnection {
|
||||
let id = message.data.id;
|
||||
let role = db.roles.get(id);
|
||||
if (!role) {
|
||||
throw new errors.RequestError(`Role with ID ${id} does not exist`);
|
||||
throw new libErrors.RequestError(`Role with ID ${id} does not exist`);
|
||||
}
|
||||
|
||||
db.roles.delete(id);
|
||||
@@ -820,14 +820,14 @@ class ControlConnection extends BaseConnection {
|
||||
async updateUserRolesRequestHandler(message) {
|
||||
let user = db.users.get(message.data.name);
|
||||
if (!user) {
|
||||
throw new errors.RequestError(`User '${message.data.name}' does not exist`);
|
||||
throw new libErrors.RequestError(`User '${message.data.name}' does not exist`);
|
||||
}
|
||||
|
||||
let resolvedRoles = new Set();
|
||||
for (let roleId of message.data.roles) {
|
||||
let role = db.roles.get(roleId);
|
||||
if (!role) {
|
||||
throw new errors.RequestError(`Role with ID ${roleId} does not exist`);
|
||||
throw new libErrors.RequestError(`Role with ID ${roleId} does not exist`);
|
||||
}
|
||||
|
||||
resolvedRoles.add(role);
|
||||
@@ -844,12 +844,12 @@ class ControlConnection extends BaseConnection {
|
||||
this.user.checkPermission("core.user.create");
|
||||
user = createUser(name);
|
||||
} else {
|
||||
throw new errors.RequestError(`User '${name}' does not exist`);
|
||||
throw new libErrors.RequestError(`User '${name}' does not exist`);
|
||||
}
|
||||
}
|
||||
|
||||
user.isAdmin = admin;
|
||||
this.broadcastEventToSlaves({ data: { name, admin }}, link.messages.adminlistUpdate);
|
||||
this.broadcastEventToSlaves({ data: { name, admin }}, libLink.messages.adminlistUpdate);
|
||||
}
|
||||
|
||||
async setUserBannedRequestHandler(message) {
|
||||
@@ -860,13 +860,13 @@ class ControlConnection extends BaseConnection {
|
||||
this.user.checkPermission("core.user.create");
|
||||
user = createUser(name);
|
||||
} else {
|
||||
throw new errors.RequestError(`User '${name}' does not exist`);
|
||||
throw new libErrors.RequestError(`User '${name}' does not exist`);
|
||||
}
|
||||
}
|
||||
|
||||
user.isBanned = banned;
|
||||
user.banReason = reason;
|
||||
this.broadcastEventToSlaves({ data: { name, banned, reason }}, link.messages.banlistUpdate);
|
||||
this.broadcastEventToSlaves({ data: { name, banned, reason }}, libLink.messages.banlistUpdate);
|
||||
}
|
||||
|
||||
async setUserWhitelistedRequestHandler(message) {
|
||||
@@ -877,28 +877,28 @@ class ControlConnection extends BaseConnection {
|
||||
this.user.checkPermission("core.user.create");
|
||||
user = createUser(name);
|
||||
} else {
|
||||
throw new errors.RequestError(`User '${name}' does not exist`);
|
||||
throw new libErrors.RequestError(`User '${name}' does not exist`);
|
||||
}
|
||||
}
|
||||
|
||||
user.isWhitelisted = whitelisted;
|
||||
this.broadcastEventToSlaves({ data: { name, whitelisted }}, link.messages.whitelistUpdate);
|
||||
this.broadcastEventToSlaves({ data: { name, whitelisted }}, libLink.messages.whitelistUpdate);
|
||||
}
|
||||
|
||||
async deleteUserRequestHandler(message) {
|
||||
let user = db.users.get(message.data.name);
|
||||
if (!user) {
|
||||
throw new errors.RequestError(`User '${message.data.name}' does not exist`);
|
||||
throw new libErrors.RequestError(`User '${message.data.name}' does not exist`);
|
||||
}
|
||||
|
||||
if (user.is_admin) {
|
||||
this.broadcastEventToSlaves({ data: { name, admin: false }}, link.messages.adminlistUpdate);
|
||||
this.broadcastEventToSlaves({ data: { name, admin: false }}, libLink.messages.adminlistUpdate);
|
||||
}
|
||||
if (user.is_whitelisted) {
|
||||
this.broadcastEventToSlaves({ data: { name, whitelisted: false }}, link.messages.whitelistUpdate);
|
||||
this.broadcastEventToSlaves({ data: { name, whitelisted: false }}, libLink.messages.whitelistUpdate);
|
||||
}
|
||||
if (user.is_banned) {
|
||||
this.broadcastEventToSlaves({ data: { name, banned: false, reason: "" }}, link.messages.banlistUpdate);
|
||||
this.broadcastEventToSlaves({ data: { name, banned: false, reason: "" }}, libLink.messages.banlistUpdate);
|
||||
}
|
||||
db.users.delete(message.data.name);
|
||||
}
|
||||
@@ -906,7 +906,7 @@ class ControlConnection extends BaseConnection {
|
||||
async debugDumpWsRequestHandler(message) {
|
||||
this.ws_dumper = data => {
|
||||
if (this.connector.connected) {
|
||||
link.messages.debugWsMessage.send(this, data);
|
||||
libLink.messages.debugWsMessage.send(this, data);
|
||||
}
|
||||
};
|
||||
this.connector._socket.clusterio_ignore_dump = true;
|
||||
@@ -959,14 +959,14 @@ class SlaveConnection extends BaseConnection {
|
||||
let prev = instance.status;
|
||||
instance.status = message.data.status;
|
||||
console.log(`Clusterio | Instance ${instance.config.get("instance.name")} State: ${instance.status}`);
|
||||
await plugin.invokeHook(masterPlugins, "onInstanceStatusChanged", instance, prev);
|
||||
await libPlugin.invokeHook(masterPlugins, "onInstanceStatusChanged", instance, prev);
|
||||
}
|
||||
|
||||
async updateInstancesEventHandler(message) {
|
||||
// Push updated instance configs
|
||||
for (let instance of db.instances.values()) {
|
||||
if (instance.config.get("instance.assigned_slave") === this._id) {
|
||||
await link.messages.assignInstance.send(this, {
|
||||
await libLink.messages.assignInstance.send(this, {
|
||||
instance_id: instance.config.get("instance.id"),
|
||||
serialized_config: instance.config.serialize(),
|
||||
});
|
||||
@@ -975,7 +975,7 @@ class SlaveConnection extends BaseConnection {
|
||||
|
||||
// Assign instances the slave has but master does not
|
||||
for (let instance of message.data.instances) {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.load(instance.serialized_config);
|
||||
|
||||
let masterInstance = db.instances.get(instanceConfig.get("instance.id"));
|
||||
@@ -984,7 +984,7 @@ class SlaveConnection extends BaseConnection {
|
||||
if (masterInstance.status !== instance.status) {
|
||||
let prev = masterInstance.status;
|
||||
masterInstance.status = instance.status;
|
||||
await plugin.invokeHook(masterPlugins, "onInstanceStatusChanged", instance, prev);
|
||||
await libPlugin.invokeHook(masterPlugins, "onInstanceStatusChanged", instance, prev);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -994,7 +994,7 @@ class SlaveConnection extends BaseConnection {
|
||||
config: instanceConfig,
|
||||
status: instance.status,
|
||||
});
|
||||
await link.messages.assignInstance.send(this, {
|
||||
await libLink.messages.assignInstance.send(this, {
|
||||
instance_id: instanceConfig.get("instance.id"),
|
||||
serialized_config: instanceConfig.serialize(),
|
||||
});
|
||||
@@ -1017,14 +1017,14 @@ class SlaveConnection extends BaseConnection {
|
||||
}
|
||||
}
|
||||
|
||||
link.messages.syncUserLists.send(this, { adminlist, banlist, whitelist });
|
||||
libLink.messages.syncUserLists.send(this, { adminlist, banlist, whitelist });
|
||||
}
|
||||
|
||||
async instanceOutputEventHandler(message) {
|
||||
let { instance_id, output } = message.data;
|
||||
for (let controlConnection of controlConnections) {
|
||||
if (controlConnection.instanceOutputSubscriptions.has(instance_id)) {
|
||||
link.messages.instanceOutput.send(controlConnection, message.data);
|
||||
libLink.messages.instanceOutput.send(controlConnection, message.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1043,7 +1043,7 @@ class SlaveConnection extends BaseConnection {
|
||||
}
|
||||
|
||||
let instance = db.instances.get(instance_id);
|
||||
await plugin.invokeHook(masterPlugins, "onPlayerEvent", instance, message.data);
|
||||
await libPlugin.invokeHook(masterPlugins, "onPlayerEvent", instance, message.data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,7 +1070,7 @@ function isInteger(value) {
|
||||
*
|
||||
* @extends module:lib/link.WebSocketBaseConnector
|
||||
*/
|
||||
class WebSocketServerConnector extends link.WebSocketBaseConnector {
|
||||
class WebSocketServerConnector extends libLink.WebSocketBaseConnector {
|
||||
constructor(socket, sessionId) {
|
||||
super();
|
||||
|
||||
@@ -1341,7 +1341,7 @@ async function handleHandshake(message, socket, req, attachHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!schema.clientHandshake(message)) {
|
||||
if (!libSchema.clientHandshake(message)) {
|
||||
console.log(`SOCKET | closing ${req.socket.remoteAddress} after receiving invalid handshake:`, message);
|
||||
wsRejectedConnectionsCounter.inc();
|
||||
socket.close(1002, "Bad handshake");
|
||||
@@ -1460,7 +1460,7 @@ async function loadPlugins(pluginInfos) {
|
||||
pluginList[pluginInfo.name] = pluginInfo.version;
|
||||
|
||||
let pluginLoadStarted = Date.now();
|
||||
let MasterPlugin = plugin.BaseMasterPlugin;
|
||||
let MasterPlugin = libPlugin.BaseMasterPlugin;
|
||||
try {
|
||||
if (pluginInfo.masterEntrypoint) {
|
||||
({ MasterPlugin } = require(path.posix.join(pluginInfo.requirePath, pluginInfo.masterEntrypoint)));
|
||||
@@ -1473,7 +1473,7 @@ async function loadPlugins(pluginInfos) {
|
||||
plugins.set(pluginInfo.name, masterPlugin);
|
||||
|
||||
} catch (err) {
|
||||
throw new errors.PluginError(pluginInfo.name, err);
|
||||
throw new libErrors.PluginError(pluginInfo.name, err);
|
||||
}
|
||||
|
||||
console.log(`Clusterio | Loaded plugin ${pluginInfo.name} in ${Date.now() - pluginLoadStarted}ms`);
|
||||
@@ -1503,7 +1503,7 @@ function listen(server, ...args) {
|
||||
});
|
||||
|
||||
function wrapError(err) {
|
||||
reject(new errors.StartupError(
|
||||
reject(new libErrors.StartupError(
|
||||
`Server listening failed: ${err.message}`
|
||||
));
|
||||
}
|
||||
@@ -1561,8 +1561,8 @@ async function startServer() {
|
||||
default: "plugin-list.json",
|
||||
type: "string",
|
||||
})
|
||||
.command("plugin", "Manage available plugins", sharedCommands.pluginCommand)
|
||||
.command("config", "Manage Master config", config.configCommand)
|
||||
.command("plugin", "Manage available plugins", libSharedCommands.pluginCommand)
|
||||
.command("config", "Manage Master config", libConfig.configCommand)
|
||||
.command("bootstrap", "Bootstrap access to cluster", yargs => {
|
||||
yargs
|
||||
.command("create-admin <name>", "Create a cluster admin")
|
||||
@@ -1595,18 +1595,18 @@ async function startServer() {
|
||||
// If the command is plugin management we don't try to load plugins
|
||||
let command = args._[0];
|
||||
if (command === "plugin") {
|
||||
await sharedCommands.handlePluginCommand(args, pluginList, args.pluginList);
|
||||
await libSharedCommands.handlePluginCommand(args, pluginList, args.pluginList);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Loading Plugin info");
|
||||
pluginInfos = await plugin.loadPluginInfos(pluginList);
|
||||
config.registerPluginConfigGroups(pluginInfos);
|
||||
config.finalizeConfigs();
|
||||
pluginInfos = await libPlugin.loadPluginInfos(pluginList);
|
||||
libConfig.registerPluginConfigGroups(pluginInfos);
|
||||
libConfig.finalizeConfigs();
|
||||
|
||||
masterConfigPath = args.config;
|
||||
console.log(`Loading config from ${masterConfigPath}`);
|
||||
masterConfig = new config.MasterConfig();
|
||||
masterConfig = new libConfig.MasterConfig();
|
||||
try {
|
||||
await masterConfig.load(JSON.parse(await fs.readFile(masterConfigPath)));
|
||||
|
||||
@@ -1629,7 +1629,7 @@ async function startServer() {
|
||||
}
|
||||
|
||||
if (command === "config") {
|
||||
await config.handleConfigCommand(args, masterConfig, masterConfigPath);
|
||||
await libConfig.handleConfigCommand(args, masterConfig, masterConfigPath);
|
||||
return;
|
||||
|
||||
} else if (command === "bootstrap") {
|
||||
@@ -1647,7 +1647,7 @@ async function startServer() {
|
||||
admin = createUser(args.name);
|
||||
}
|
||||
|
||||
let adminRole = users.ensureDefaultAdminRole(db.roles);
|
||||
let adminRole = libUsers.ensureDefaultAdminRole(db.roles);
|
||||
admin.roles.add(adminRole);
|
||||
admin.isAdmin = true;
|
||||
await saveUsers(masterConfig.get("master.database_directory"), "users.json");
|
||||
@@ -1659,7 +1659,7 @@ async function startServer() {
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
let controlConfig = new config.ControlConfig();
|
||||
let controlConfig = new libConfig.ControlConfig();
|
||||
await controlConfig.init();
|
||||
|
||||
controlConfig.set("control.master_url", getMasterUrl());
|
||||
@@ -1728,7 +1728,7 @@ async function startServer() {
|
||||
let tls_key = masterConfig.get("master.tls_private_key");
|
||||
// Create a self signed certificate if the certificate files doesn't exist
|
||||
if (httpsPort && !await fs.exists(tls_cert) && !await fs.exists(tls_key)) {
|
||||
await generateSSLcert({
|
||||
await generateSslCert({
|
||||
bits: masterConfig.get("master.tls_bits"),
|
||||
sslCertPath: tls_cert,
|
||||
sslPrivKeyPath: tls_key,
|
||||
@@ -1763,7 +1763,7 @@ async function startServer() {
|
||||
privateKey = await fs.readFile(tls_key);
|
||||
|
||||
} catch (err) {
|
||||
throw new errors.StartupError(
|
||||
throw new libErrors.StartupError(
|
||||
`Error loading ssl certificate: ${err.message}`
|
||||
);
|
||||
}
|
||||
@@ -1799,13 +1799,13 @@ I version of clusterio. Expect things to break. I
|
||||
`
|
||||
);
|
||||
startServer().catch(err => {
|
||||
if (err instanceof errors.StartupError) {
|
||||
if (err instanceof libErrors.StartupError) {
|
||||
console.error(`
|
||||
+----------------------------------+
|
||||
| Unable to to start master server |
|
||||
+----------------------------------+`
|
||||
);
|
||||
} else if (err instanceof errors.PluginError) {
|
||||
} else if (err instanceof libErrors.PluginError) {
|
||||
console.error(`
|
||||
Error: ${err.pluginName} plugin threw an unexpected error
|
||||
during startup, please report it to the plugin author.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const link = require("@clusterio/lib/link");
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
/**
|
||||
* Format a parsed Factorio output message
|
||||
@@ -35,7 +35,7 @@ function formatOutput(output) {
|
||||
* Connector for control connection to master server
|
||||
* @private
|
||||
*/
|
||||
export class ControlConnector extends link.WebSocketClientConnector {
|
||||
export class ControlConnector extends libLink.WebSocketClientConnector {
|
||||
constructor(url, reconnectDelay, token) {
|
||||
super(url, reconnectDelay);
|
||||
this._token = token;
|
||||
@@ -57,10 +57,10 @@ export class ControlConnector extends link.WebSocketClientConnector {
|
||||
* Connects to the master server over WebSocket and sends commands to it.
|
||||
* @static
|
||||
*/
|
||||
export class Control extends link.Link {
|
||||
export class Control extends libLink.Link {
|
||||
constructor(connector, controlPlugins) {
|
||||
super("control", "master", connector);
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
|
||||
/**
|
||||
* Mapping of plugin names to their instance for loaded plugins.
|
||||
@@ -68,7 +68,7 @@ export class Control extends link.Link {
|
||||
*/
|
||||
this.plugins = controlPlugins;
|
||||
for (let controlPlugin of controlPlugins.values()) {
|
||||
plugin.attachPluginMessages(this, controlPlugin.info, controlPlugin);
|
||||
libPlugin.attachPluginMessages(this, controlPlugin.info, controlPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +88,9 @@ export class Control extends link.Link {
|
||||
this.connector.setTimeout(30);
|
||||
|
||||
try {
|
||||
await link.messages.prepareDisconnect.send(this);
|
||||
await libLink.messages.prepareDisconnect.send(this);
|
||||
} catch (err) {
|
||||
if (!(err instanceof errors.SessionLost)) {
|
||||
if (!(err instanceof libErrors.SessionLost)) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
+79
-79
@@ -24,36 +24,36 @@ const util = require("util");
|
||||
const version = require("./package").version;
|
||||
|
||||
// internal libraries
|
||||
const fileOps = require("@clusterio/lib/fileOps");
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const link = require("@clusterio/lib/link");
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const prometheus = require("@clusterio/lib/prometheus");
|
||||
const luaTools = require("@clusterio/lib/luaTools");
|
||||
const config = require("@clusterio/lib/config");
|
||||
const sharedCommands = require("@clusterio/lib/shared_commands");
|
||||
const libFileOps = require("@clusterio/lib/file_ops");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const libPrometheus = require("@clusterio/lib/prometheus");
|
||||
const libLuaTools = require("@clusterio/lib/lua_tools");
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
const libSharedCommands = require("@clusterio/lib/shared_commands");
|
||||
|
||||
|
||||
const instanceRconCommandsCounter = new prometheus.Counter(
|
||||
const instanceRconCommandsCounter = new libPrometheus.Counter(
|
||||
"clusterio_instance_rcon_commands_total",
|
||||
"How many commands have been sent to the instance",
|
||||
{ labels: ["instance_id"] }
|
||||
);
|
||||
|
||||
const instanceFactorioCpuTime = new prometheus.Gauge(
|
||||
const instanceFactorioCpuTime = new libPrometheus.Gauge(
|
||||
"clusterio_instance_factorio_cpu_time_total",
|
||||
"Factorio CPU time spent in seconds.",
|
||||
{ labels: ["instance_id"] }
|
||||
);
|
||||
|
||||
const instanceFactorioMemoryUsage = new prometheus.Gauge(
|
||||
const instanceFactorioMemoryUsage = new libPrometheus.Gauge(
|
||||
"clusterio_instance_factorio_resident_memory_bytes",
|
||||
"Factorio resident memory size in bytes.",
|
||||
{ labels: ["instance_id"] }
|
||||
);
|
||||
|
||||
const instanceFactorioAutosaveSize = new prometheus.Gauge(
|
||||
const instanceFactorioAutosaveSize = new libPrometheus.Gauge(
|
||||
"clusterio_instance_factorio_autosave_bytes",
|
||||
"Size of Factorio server autosave in bytes.",
|
||||
{ labels: ["instance_id"] }
|
||||
@@ -105,10 +105,10 @@ const serverSettingsActions = {
|
||||
/**
|
||||
* Keeps track of the runtime parameters of an instance
|
||||
*/
|
||||
class Instance extends link.Link{
|
||||
class Instance extends libLink.Link{
|
||||
constructor(slave, connector, dir, factorioDir, instanceConfig) {
|
||||
super("instance", "slave", connector);
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
this._slave = slave;
|
||||
this._dir = dir;
|
||||
|
||||
@@ -116,7 +116,7 @@ class Instance extends link.Link{
|
||||
this.config = instanceConfig;
|
||||
|
||||
this._configFieldChanged = (group, field, prev) => {
|
||||
let hook = () => plugin.invokeHook(this.plugins, "onInstanceConfigFieldChanged", group, field, prev);
|
||||
let hook = () => libPlugin.invokeHook(this.plugins, "onInstanceConfigFieldChanged", group, field, prev);
|
||||
|
||||
if (group.name === "factorio" && field === "settings") {
|
||||
this.updateFactorioSettings(group.get(field), prev).finally(hook);
|
||||
@@ -137,7 +137,7 @@ class Instance extends link.Link{
|
||||
};
|
||||
|
||||
this._running = false;
|
||||
this.server = new factorio.FactorioServer(
|
||||
this.server = new libFactorio.FactorioServer(
|
||||
factorioDir, this._dir, serverOptions
|
||||
);
|
||||
|
||||
@@ -148,9 +148,9 @@ class Instance extends link.Link{
|
||||
};
|
||||
|
||||
this.server.on("output", (output) => {
|
||||
link.messages.instanceOutput.send(this, { instance_id: this.config.get("instance.id"), output });
|
||||
libLink.messages.instanceOutput.send(this, { instance_id: this.config.get("instance.id"), output });
|
||||
|
||||
plugin.invokeHook(this.plugins, "onOutput", output);
|
||||
libPlugin.invokeHook(this.plugins, "onOutput", output);
|
||||
});
|
||||
|
||||
this.server.on("error", err => {
|
||||
@@ -164,11 +164,11 @@ class Instance extends link.Link{
|
||||
});
|
||||
|
||||
this.server.on("ipc-player_event", event => {
|
||||
link.messages.playerEvent.send(this, {
|
||||
libLink.messages.playerEvent.send(this, {
|
||||
instance_id: this.config.get("instance.id"),
|
||||
...event,
|
||||
});
|
||||
plugin.invokeHook(this.plugins, "onPlayerEvent", event);
|
||||
libPlugin.invokeHook(this.plugins, "onPlayerEvent", event);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ class Instance extends link.Link{
|
||||
}
|
||||
|
||||
notifyStatus(status) {
|
||||
link.messages.instanceStatusChanged.send(this, {
|
||||
libLink.messages.instanceStatusChanged.send(this, {
|
||||
instance_id: this.config.get("instance.id"), status,
|
||||
});
|
||||
}
|
||||
@@ -190,9 +190,9 @@ class Instance extends link.Link{
|
||||
this.config.off("fieldChanged", this._configFieldChanged);
|
||||
|
||||
// Clear metrics this instance is exporting
|
||||
for (let collector of prometheus.defaultRegistry.collectors) {
|
||||
for (let collector of libPrometheus.defaultRegistry.collectors) {
|
||||
if (
|
||||
collector instanceof prometheus.ValueCollector
|
||||
collector instanceof libPrometheus.ValueCollector
|
||||
&& collector.metric.labels.includes("instance_id")
|
||||
) {
|
||||
collector.removeAll({ instance_id: String(this.config.get("instance.id")) });
|
||||
@@ -211,7 +211,7 @@ class Instance extends link.Link{
|
||||
let instancePlugin = new InstancePlugin(pluginInfo, this, slave);
|
||||
this.plugins.set(pluginInfo.name, instancePlugin);
|
||||
await instancePlugin.init();
|
||||
plugin.attachPluginMessages(this, pluginInfo, instancePlugin);
|
||||
libPlugin.attachPluginMessages(this, pluginInfo, instancePlugin);
|
||||
|
||||
console.log(`Clusterio | Loaded plugin ${pluginInfo.name} in ${Date.now() - pluginLoadStarted}ms`);
|
||||
}
|
||||
@@ -241,7 +241,7 @@ class Instance extends link.Link{
|
||||
for (let [name, plugin] of this.plugins) {
|
||||
plugins[name] = plugin.info.version;
|
||||
}
|
||||
link.messages.instanceInitialized.send(this, { instance_id: this.config.get("instance.id"), plugins });
|
||||
libLink.messages.instanceInitialized.send(this, { instance_id: this.config.get("instance.id"), plugins });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,7 +362,7 @@ class Instance extends link.Link{
|
||||
async prepareSave(saveName) {
|
||||
// Use latest save if no save was specified
|
||||
if (saveName === null) {
|
||||
saveName = await fileOps.getNewestFile(
|
||||
saveName = await libFileOps.getNewestFile(
|
||||
this.path("saves"), (name) => !name.endsWith(".tmp.zip")
|
||||
);
|
||||
}
|
||||
@@ -440,7 +440,7 @@ class Instance extends link.Link{
|
||||
}
|
||||
}
|
||||
|
||||
await factorio.patch(this.path("saves", saveName), [...modules.values()]);
|
||||
await libFactorio.patch(this.path("saves", saveName), [...modules.values()]);
|
||||
return saveName;
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ class Instance extends link.Link{
|
||||
await this.updateInstanceData();
|
||||
}
|
||||
|
||||
await plugin.invokeHook(this.plugins, "onStart");
|
||||
await libPlugin.invokeHook(this.plugins, "onStart");
|
||||
|
||||
this._running = true;
|
||||
this.notifyStatus("running");
|
||||
@@ -486,7 +486,7 @@ class Instance extends link.Link{
|
||||
this.server.on("exit", () => this.notifyExit());
|
||||
await this.server.startScenario(scenario);
|
||||
|
||||
await plugin.invokeHook(this.plugins, "onStart");
|
||||
await libPlugin.invokeHook(this.plugins, "onStart");
|
||||
|
||||
this._running = true;
|
||||
this.notifyStatus("running");
|
||||
@@ -496,7 +496,7 @@ class Instance extends link.Link{
|
||||
* Update instance information on the Factorio side
|
||||
*/
|
||||
async updateInstanceData() {
|
||||
let name = luaTools.escapeString(this.config.get("instance.name"));
|
||||
let name = libLuaTools.escapeString(this.config.get("instance.name"));
|
||||
let id = this.config.get("instance.id");
|
||||
await this.server.sendRcon(`/sc clusterio_private.update_instance(${id}, "${name}")`, true);
|
||||
}
|
||||
@@ -574,26 +574,26 @@ class Instance extends link.Link{
|
||||
|
||||
// XXX this needs more thought to it
|
||||
if (this.server._state === "running") {
|
||||
await plugin.invokeHook(this.plugins, "onStop");
|
||||
await libPlugin.invokeHook(this.plugins, "onStop");
|
||||
await this.server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
async masterConnectionEventEventHandler(message) {
|
||||
await plugin.invokeHook(this.plugins, "onMasterConnectionEvent", message.data.event);
|
||||
await libPlugin.invokeHook(this.plugins, "onMasterConnectionEvent", message.data.event);
|
||||
}
|
||||
|
||||
async prepareMasterDisconnectRequestHandler() {
|
||||
await plugin.invokeHook(this.plugins, "onPrepareMasterDisconnect");
|
||||
await libPlugin.invokeHook(this.plugins, "onPrepareMasterDisconnect");
|
||||
}
|
||||
|
||||
async getMetricsRequestHandler() {
|
||||
let results = [];
|
||||
if (this._running) {
|
||||
let pluginResults = await plugin.invokeHook(this.plugins, "onMetrics");
|
||||
let pluginResults = await libPlugin.invokeHook(this.plugins, "onMetrics");
|
||||
for (let metricIterator of pluginResults) {
|
||||
for await (let metric of metricIterator) {
|
||||
results.push(prometheus.serializeResult(metric));
|
||||
results.push(libPrometheus.serializeResult(metric));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -629,7 +629,7 @@ class Instance extends link.Link{
|
||||
async loadScenarioRequestHandler(message) {
|
||||
if (this.config.get("factorio.enable_save_patching")) {
|
||||
this.notifyExit();
|
||||
throw new errors.RequestError("Load scenario cannot be used with save patching enabled");
|
||||
throw new libErrors.RequestError("Load scenario cannot be used with save patching enabled");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -674,7 +674,7 @@ class Instance extends link.Link{
|
||||
|
||||
console.log("Exporting data .....");
|
||||
await symlinkMods(this, "sharedMods", console);
|
||||
let zip = await factorio.exportData(this.server);
|
||||
let zip = await libFactorio.exportData(this.server);
|
||||
|
||||
let content = await zip.generateAsync({ type: "nodebuffer" });
|
||||
let url = new URL(this._slave.config.get("slave.master_url"));
|
||||
@@ -745,7 +745,7 @@ class Instance extends link.Link{
|
||||
async function discoverInstances(instanceInfos, instancesDir, logger) {
|
||||
for (let entry of await fs.readdir(instancesDir, { withFileTypes: true })) {
|
||||
if (entry.isDirectory()) {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
let configPath = path.join(instancesDir, entry.name, "instance.json");
|
||||
|
||||
try {
|
||||
@@ -775,17 +775,17 @@ async function discoverInstances(instanceInfos, instancesDir, logger) {
|
||||
}
|
||||
}
|
||||
|
||||
class InstanceConnection extends link.Link {
|
||||
class InstanceConnection extends libLink.Link {
|
||||
constructor(connector, slave, instanceId) {
|
||||
super("slave", "instance", connector);
|
||||
this.slave = slave;
|
||||
this.instanceId = instanceId;
|
||||
this.plugins = new Map();
|
||||
this.status = "stopped";
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
|
||||
for (let pluginInfo of slave.pluginInfos) {
|
||||
plugin.attachPluginMessages(this, pluginInfo, null);
|
||||
libPlugin.attachPluginMessages(this, pluginInfo, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,7 +833,7 @@ class InstanceConnection extends link.Link {
|
||||
}
|
||||
}
|
||||
|
||||
class SlaveConnector extends link.WebSocketClientConnector {
|
||||
class SlaveConnector extends libLink.WebSocketClientConnector {
|
||||
constructor(slaveConfig, pluginInfos) {
|
||||
super(slaveConfig.get("slave.master_url"), slaveConfig.get("slave.reconnect_delay"));
|
||||
this.slaveConfig = slaveConfig;
|
||||
@@ -863,16 +863,16 @@ class SlaveConnector extends link.WebSocketClientConnector {
|
||||
*
|
||||
* Connects to the master server over the WebSocket and manages intsances.
|
||||
*/
|
||||
class Slave extends link.Link {
|
||||
class Slave extends libLink.Link {
|
||||
// I don't like God classes, but the alternative of putting all this state
|
||||
// into global variables is not much better.
|
||||
constructor(connector, slaveConfig, pluginInfos) {
|
||||
super("slave", "master", connector);
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
|
||||
this.pluginInfos = pluginInfos;
|
||||
for (let pluginInfo of pluginInfos) {
|
||||
plugin.attachPluginMessages(this, pluginInfo, null);
|
||||
libPlugin.attachPluginMessages(this, pluginInfo, null);
|
||||
}
|
||||
|
||||
this.config = slaveConfig;
|
||||
@@ -941,7 +941,7 @@ class Slave extends link.Link {
|
||||
for (let event of ["connect", "drop", "close"]) {
|
||||
this.connector.on(event, () => {
|
||||
for (let instanceConnection of this.instanceConnections.values()) {
|
||||
link.messages.masterConnectionEvent.send(instanceConnection, { event });
|
||||
libLink.messages.masterConnectionEvent.send(instanceConnection, { event });
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -966,16 +966,16 @@ class Slave extends link.Link {
|
||||
async forwardRequestToInstance(message, request) {
|
||||
let instanceId = message.data.instance_id;
|
||||
if (!this.instanceInfos.has(instanceId)) {
|
||||
throw new errors.RequestError(`Instance with ID ${instanceId} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${instanceId} does not exist`);
|
||||
}
|
||||
|
||||
let instanceConnection = this.instanceConnections.get(instanceId);
|
||||
if (!instanceConnection) {
|
||||
throw new errors.RequestError(`Instance ID ${instanceId} is not running`);
|
||||
throw new libErrors.RequestError(`Instance ID ${instanceId} is not running`);
|
||||
}
|
||||
|
||||
if (request.plugin && !instanceConnection.plugins.has(request.plugin)) {
|
||||
throw new errors.RequestError(`Instance ID ${instanceId} does not have ${request.plugin} plugin loaded`);
|
||||
throw new libErrors.RequestError(`Instance ID ${instanceId} does not have ${request.plugin} plugin loaded`);
|
||||
}
|
||||
|
||||
return await request.send(instanceConnection, message.data);
|
||||
@@ -1022,8 +1022,8 @@ class Slave extends link.Link {
|
||||
}
|
||||
};
|
||||
|
||||
updateList(this.adminlist, message.data.adminlist, "admin", link.messages.adminlistUpdate);
|
||||
updateList(this.whitelist, message.data.whitelist, "whitelisted", link.messages.whitelistUpdate);
|
||||
updateList(this.adminlist, message.data.adminlist, "admin", libLink.messages.adminlistUpdate);
|
||||
updateList(this.whitelist, message.data.whitelist, "whitelisted", libLink.messages.whitelistUpdate);
|
||||
|
||||
let updatedBanlist = new Map(message.data.banlist);
|
||||
let addedOrChanged = new Map(updatedBanlist);
|
||||
@@ -1038,14 +1038,14 @@ class Slave extends link.Link {
|
||||
for (let [name, reason] of addedOrChanged) {
|
||||
this.banlist.set(name, reason);
|
||||
this.broadcastEventToInstance(
|
||||
{ data: { name, banned: true, reason }}, link.messages.banlistUpdate
|
||||
{ data: { name, banned: true, reason }}, libLink.messages.banlistUpdate
|
||||
);
|
||||
}
|
||||
|
||||
for (let name of removed) {
|
||||
this.banlist.delete(name);
|
||||
this.broadcastEventToInstance(
|
||||
{ data: { name, banned: false, reason: "" }}, link.messages.banlistUpdate
|
||||
{ data: { name, banned: false, reason: "" }}, libLink.messages.banlistUpdate
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1086,7 +1086,7 @@ class Slave extends link.Link {
|
||||
// TODO: Notify of update if instance is running
|
||||
|
||||
} else {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.load(serialized_config);
|
||||
|
||||
// XXX: race condition on multiple simultanious calls
|
||||
@@ -1113,7 +1113,7 @@ class Slave extends link.Link {
|
||||
);
|
||||
|
||||
// Notify master the instance is no longer usassigned
|
||||
link.messages.instanceStatusChanged.send(this, { instance_id, status: "stopped" });
|
||||
libLink.messages.instanceStatusChanged.send(this, { instance_id, status: "stopped" });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1125,14 +1125,14 @@ class Slave extends link.Link {
|
||||
async _connectInstance(instanceId) {
|
||||
let instanceInfo = this.instanceInfos.get(instanceId);
|
||||
if (!instanceInfo) {
|
||||
throw new errors.RequestError(`Instance with ID ${instanceId} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${instanceId} does not exist`);
|
||||
}
|
||||
|
||||
if (this.instanceConnections.has(instanceId)) {
|
||||
throw new errors.RequestError(`Instance with ID ${instanceId} is running`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${instanceId} is running`);
|
||||
}
|
||||
|
||||
let [connectionClient, connectionServer] = link.VirtualConnector.makePair();
|
||||
let [connectionClient, connectionServer] = libLink.VirtualConnector.makePair();
|
||||
let instanceConnection = new InstanceConnection(connectionServer, this, instanceId);
|
||||
let instance = new Instance(
|
||||
this, connectionClient, instanceInfo.path, this.config.get("slave.factorio_directory"), instanceInfo.config
|
||||
@@ -1147,7 +1147,7 @@ class Slave extends link.Link {
|
||||
async getMetricsRequestHandler() {
|
||||
let requests = [];
|
||||
for (let instanceConnection of this.instanceConnections.values()) {
|
||||
requests.push(link.messages.getMetrics.send(instanceConnection));
|
||||
requests.push(libLink.messages.getMetrics.send(instanceConnection));
|
||||
}
|
||||
|
||||
let results = [];
|
||||
@@ -1155,15 +1155,15 @@ class Slave extends link.Link {
|
||||
results.push(...response.results);
|
||||
}
|
||||
|
||||
for await (let result of prometheus.defaultRegistry.collect()) {
|
||||
for await (let result of libPrometheus.defaultRegistry.collect()) {
|
||||
if (result.metric.name.startsWith("process_")) {
|
||||
results.push(prometheus.serializeResult(result, {
|
||||
results.push(libPrometheus.serializeResult(result, {
|
||||
addLabels: { "slave_id": String(this.config.get("slave.id")) },
|
||||
metricName: result.metric.name.replace("process_", "clusterio_slave_"),
|
||||
}));
|
||||
|
||||
} else {
|
||||
results.push(prometheus.serializeResult(result));
|
||||
results.push(libPrometheus.serializeResult(result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1196,18 +1196,18 @@ class Slave extends link.Link {
|
||||
|
||||
async stopInstance(instanceId) {
|
||||
let instanceConnection = this.instanceConnections.get(instanceId);
|
||||
await link.messages.stopInstance.send(instanceConnection, { instance_id: instanceId });
|
||||
await libLink.messages.stopInstance.send(instanceConnection, { instance_id: instanceId });
|
||||
}
|
||||
|
||||
async deleteInstanceRequestHandler(message) {
|
||||
let instanceId = message.data.instance_id;
|
||||
if (this.instanceConnections.has(instanceId)) {
|
||||
throw new errors.RequestError(`Instance with ID ${instanceId} is running`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${instanceId} is running`);
|
||||
}
|
||||
|
||||
let instanceInfo = this.instanceInfos.get(instanceId);
|
||||
if (!instanceInfo) {
|
||||
throw new errors.RequestError(`Instance with ID ${instanceId} does not exist`);
|
||||
throw new libErrors.RequestError(`Instance with ID ${instanceId} does not exist`);
|
||||
}
|
||||
|
||||
await fs.remove(instanceInfo.path);
|
||||
@@ -1230,13 +1230,13 @@ class Slave extends link.Link {
|
||||
status: instanceConnection ? instanceConnection.status : "stopped",
|
||||
});
|
||||
}
|
||||
link.messages.updateInstances.send(this, { instances: list });
|
||||
libLink.messages.updateInstances.send(this, { instances: list });
|
||||
}
|
||||
|
||||
async prepareDisconnectRequestHandler(message, request) {
|
||||
this._disconnecting = true;
|
||||
for (let instanceConnection of this.instanceConnections.values()) {
|
||||
await link.messages.prepareMasterDisconnect.send(instanceConnection);
|
||||
await libLink.messages.prepareMasterDisconnect.send(instanceConnection);
|
||||
}
|
||||
this.connector.setClosing();
|
||||
return await super.prepareDisconnectRequestHandler(message, request);
|
||||
@@ -1250,9 +1250,9 @@ class Slave extends link.Link {
|
||||
this.connector.setTimeout(30);
|
||||
|
||||
try {
|
||||
await link.messages.prepareDisconnect.send(this);
|
||||
await libLink.messages.prepareDisconnect.send(this);
|
||||
} catch (err) {
|
||||
if (!(err instanceof errors.SessionLost)) {
|
||||
if (!(err instanceof libErrors.SessionLost)) {
|
||||
console.error("Unexpected error preparing disconnect");
|
||||
console.error(err);
|
||||
}
|
||||
@@ -1391,8 +1391,8 @@ async function startSlave() {
|
||||
default: "plugin-list.json",
|
||||
type: "string",
|
||||
})
|
||||
.command("plugin", "Manage available plugins", sharedCommands.pluginCommand)
|
||||
.command("config", "Manage Slave config", config.configCommand)
|
||||
.command("plugin", "Manage available plugins", libSharedCommands.pluginCommand)
|
||||
.command("config", "Manage Slave config", libConfig.configCommand)
|
||||
.command("run", "Run slave")
|
||||
.demandCommand(1, "You need to specify a command to run")
|
||||
.strict()
|
||||
@@ -1412,17 +1412,17 @@ async function startSlave() {
|
||||
// If the command is plugin management we don't try to load plugins
|
||||
let command = args._[0];
|
||||
if (command === "plugin") {
|
||||
await sharedCommands.handlePluginCommand(args, pluginList, args.pluginList);
|
||||
await libSharedCommands.handlePluginCommand(args, pluginList, args.pluginList);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Loading Plugin info");
|
||||
let pluginInfos = await plugin.loadPluginInfos(pluginList);
|
||||
config.registerPluginConfigGroups(pluginInfos);
|
||||
config.finalizeConfigs();
|
||||
let pluginInfos = await libPlugin.loadPluginInfos(pluginList);
|
||||
libConfig.registerPluginConfigGroups(pluginInfos);
|
||||
libConfig.finalizeConfigs();
|
||||
|
||||
console.log(`Loading config from ${args.config}`);
|
||||
let slaveConfig = new config.SlaveConfig();
|
||||
let slaveConfig = new libConfig.SlaveConfig();
|
||||
try {
|
||||
await slaveConfig.load(JSON.parse(await fs.readFile(args.config)));
|
||||
|
||||
@@ -1437,7 +1437,7 @@ async function startSlave() {
|
||||
}
|
||||
|
||||
if (command === "config") {
|
||||
await config.handleConfigCommand(args, slaveConfig, args.config);
|
||||
await libConfig.handleConfigCommand(args, slaveConfig, args.config);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1518,7 +1518,7 @@ I version of clusterio. Expect things to break. I
|
||||
`
|
||||
);
|
||||
startSlave().catch(err => {
|
||||
if (err instanceof errors.AuthenticationFailed) {
|
||||
if (err instanceof libErrors.AuthenticationFailed) {
|
||||
console.error(err.message);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
"use strict";
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const info = require("./info");
|
||||
const command = require("@clusterio/lib/command");
|
||||
const libCommand = require("@clusterio/lib/command");
|
||||
|
||||
|
||||
const globalChatCommands = new command.CommandTree({ name: "global-chat", description: "Global Chat plugin commands" });
|
||||
globalChatCommands.add(new command.Command({
|
||||
const globalChatCommands = new libCommand.CommandTree({
|
||||
name: "global-chat", description: "Global Chat plugin commands",
|
||||
});
|
||||
globalChatCommands.add(new libCommand.Command({
|
||||
definition: ["shout <message>", "Send message to all instances", (yargs) => {
|
||||
yargs.positional("message", { describe: "message to send", type: "string" });
|
||||
}],
|
||||
@@ -17,7 +19,7 @@ globalChatCommands.add(new command.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
class ControlPlugin extends plugin.BaseControlPlugin {
|
||||
class ControlPlugin extends libPlugin.BaseControlPlugin {
|
||||
async addCommands(rootCommand) {
|
||||
rootCommand.add(globalChatCommands);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
let link = require("@clusterio/lib/link");
|
||||
let plugin = require("@clusterio/lib/plugin");
|
||||
let libLink = require("@clusterio/lib/link");
|
||||
|
||||
module.exports = {
|
||||
name: "global_chat",
|
||||
@@ -10,7 +9,7 @@ module.exports = {
|
||||
controlEntrypoint: "control",
|
||||
|
||||
messages: {
|
||||
chat: new link.Event({
|
||||
chat: new libLink.Event({
|
||||
type: "global_chat:chat",
|
||||
links: ["instance-slave", "slave-master", "master-slave", "slave-instance", "control-master"],
|
||||
forwardTo: "master",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* @module
|
||||
*/
|
||||
"use strict";
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const luaTools = require("@clusterio/lib/luaTools");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libLuaTools = require("@clusterio/lib/lua_tools");
|
||||
|
||||
|
||||
/**
|
||||
@@ -16,7 +16,7 @@ function removeTags(content) {
|
||||
return content.replace(/(\[gps=-?\d+,-?\d+\]|\[train=\d+\])/g, "");
|
||||
}
|
||||
|
||||
class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
class InstancePlugin extends libPlugin.BaseInstancePlugin {
|
||||
async init() {
|
||||
this.messageQueue = [];
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
async chatEventHandler(message) {
|
||||
// TODO check if cross server chat is enabled
|
||||
let content = `[${message.data.instance_name}] ${removeTags(message.data.content)}`;
|
||||
await this.instance.server.sendRcon(`/sc game.print('${luaTools.escapeString(content)}')`, true);
|
||||
await this.instance.server.sendRcon(`/sc game.print('${libLuaTools.escapeString(content)}')`, true);
|
||||
}
|
||||
|
||||
sendChat(message) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use strict";
|
||||
const link = require("@clusterio/lib/link");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
|
||||
|
||||
// schema used for syncing technologies to and from the master
|
||||
@@ -26,7 +26,7 @@ module.exports = {
|
||||
masterEntrypoint: "master",
|
||||
|
||||
messages: {
|
||||
contribution: new link.Event({
|
||||
contribution: new libLink.Event({
|
||||
type: "research_sync:contribution",
|
||||
links: ["instance-slave", "slave-master"],
|
||||
forwardTo: "master",
|
||||
@@ -36,7 +36,7 @@ module.exports = {
|
||||
"contribution": { type: "number" },
|
||||
},
|
||||
}),
|
||||
progress: new link.Event({
|
||||
progress: new libLink.Event({
|
||||
type: "research_sync:progress",
|
||||
links: ["master-slave", "slave-instance"],
|
||||
broadcastTo: "instance",
|
||||
@@ -55,7 +55,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
}),
|
||||
finished: new link.Event({
|
||||
finished: new libLink.Event({
|
||||
type: "research_sync:finished",
|
||||
links: ["instance-slave", "slave-master", "master-slave", "slave-instance"],
|
||||
forwardTo: "master",
|
||||
@@ -65,7 +65,7 @@ module.exports = {
|
||||
"level": { type: "integer" },
|
||||
},
|
||||
}),
|
||||
syncTechnologies: new link.Request({
|
||||
syncTechnologies: new libLink.Request({
|
||||
type: "research_sync:sync_technologies",
|
||||
links: ["instance-slave", "slave-master"],
|
||||
forwardTo: "master",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const luaTools = require("@clusterio/lib/luaTools");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libLuaTools = require("@clusterio/lib/lua_tools");
|
||||
|
||||
|
||||
function unexpectedError(err) {
|
||||
@@ -9,7 +9,7 @@ function unexpectedError(err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
class InstancePlugin extends libPlugin.BaseInstancePlugin {
|
||||
async init() {
|
||||
if (!this.instance.config.get("factorio.enable_save_patching")) {
|
||||
throw new Error("research_sync plugin requires save patching.");
|
||||
@@ -28,7 +28,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
}
|
||||
|
||||
async progressEventHandler(message) {
|
||||
let techsJson = luaTools.escapeString(JSON.stringify(message.data.technologies));
|
||||
let techsJson = libLuaTools.escapeString(JSON.stringify(message.data.technologies));
|
||||
await this.instance.server.sendRcon(`/sc research_sync.update_progress("${techsJson}")`, true);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
async finishedEventHandler(message) {
|
||||
let { name, level, researched } = message.data;
|
||||
await this.instance.server.sendRcon(
|
||||
`/sc research_sync.research_technology("${luaTools.escapeString(name)}", ${level})`, true
|
||||
`/sc research_sync.research_technology("${libLuaTools.escapeString(name)}", ${level})`, true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
}
|
||||
|
||||
if (techsToSync.length) {
|
||||
let syncJson = luaTools.escapeString(JSON.stringify(techsToSync));
|
||||
let syncJson = libLuaTools.escapeString(JSON.stringify(techsToSync));
|
||||
await this.instance.server.sendRcon(`/sc research_sync.sync_technologies("${syncJson}")`, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
|
||||
|
||||
class MasterPlugin extends plugin.BaseMasterPlugin {
|
||||
class MasterPlugin extends libPlugin.BaseMasterPlugin {
|
||||
async init() {
|
||||
this.technologies = await loadTechnologies(this.master.config);
|
||||
this.lastProgressBroadcast = Date.now();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use strict";
|
||||
let link = require("@clusterio/lib/link");
|
||||
|
||||
module.exports = {
|
||||
name: "statistics_exporter",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use strict";
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const { Gauge } = require("@clusterio/lib/prometheus");
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ const instanceGameFlowStatistics = new Gauge(
|
||||
);
|
||||
|
||||
|
||||
class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
class InstancePlugin extends libPlugin.BaseInstancePlugin {
|
||||
async init() {
|
||||
if (!this.instance.config.get("factorio.enable_save_patching")) {
|
||||
throw new Error("statistics_exporter plugin requires save patching.");
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
"use strict";
|
||||
const doleNN = require("./dole_nn_base");
|
||||
|
||||
const prometheus = require("@clusterio/lib/prometheus");
|
||||
const { Gauge } = require("@clusterio/lib/prometheus");
|
||||
|
||||
|
||||
const prometheusNNDoleGauge = new prometheus.Gauge(
|
||||
const prometheusNNDoleGauge = new Gauge(
|
||||
"clusterio_subspace_storage_nn_dole_gauge",
|
||||
"Current demand being supplied by Neural Network ; 1 means all demand covered, 0.5 means about half of each supply is covered, 0 means no items are given",
|
||||
{ labels: ["resource"] }
|
||||
);
|
||||
const prometheusDoleFactorGauge = new prometheus.Gauge(
|
||||
const prometheusDoleFactorGauge = new Gauge(
|
||||
"clusterio_subspace_storage_dole_factor_gauge",
|
||||
"The current dole division factor for this resource",
|
||||
{ labels: ["resource"] }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
const link = require("@clusterio/lib/link");
|
||||
const config = require("@clusterio/lib/config");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
|
||||
class MasterConfigGroup extends config.PluginConfigGroup {}
|
||||
class MasterConfigGroup extends libConfig.PluginConfigGroup {}
|
||||
MasterConfigGroup.groupName = "subspace_storage";
|
||||
MasterConfigGroup.define({
|
||||
name: "autosave_interval",
|
||||
@@ -28,7 +28,7 @@ MasterConfigGroup.define({
|
||||
});
|
||||
MasterConfigGroup.finalize();
|
||||
|
||||
class InstanceConfigGroup extends config.PluginConfigGroup {}
|
||||
class InstanceConfigGroup extends libConfig.PluginConfigGroup {}
|
||||
InstanceConfigGroup.groupName = "subspace_storage";
|
||||
InstanceConfigGroup.define({
|
||||
name: "log_item_transfers",
|
||||
@@ -65,7 +65,7 @@ module.exports = {
|
||||
|
||||
messages: {
|
||||
// XXX this should be a request to be reliable
|
||||
place: new link.Event({
|
||||
place: new libLink.Event({
|
||||
type: "subspace_storage:place",
|
||||
links: ["instance-slave", "slave-master"],
|
||||
forwardTo: "master",
|
||||
@@ -74,7 +74,7 @@ module.exports = {
|
||||
"items": items,
|
||||
},
|
||||
}),
|
||||
remove: new link.Request({
|
||||
remove: new libLink.Request({
|
||||
type: "subspace_storage:remove",
|
||||
links: ["instance-slave", "slave-master"],
|
||||
forwardTo: "master",
|
||||
@@ -86,7 +86,7 @@ module.exports = {
|
||||
"items": items,
|
||||
},
|
||||
}),
|
||||
getStorage: new link.Request({
|
||||
getStorage: new libLink.Request({
|
||||
type: "subspace_storage:get_storage",
|
||||
links: ["instance-slave", "slave-master"],
|
||||
forwardTo: "master",
|
||||
@@ -94,7 +94,7 @@ module.exports = {
|
||||
"items": items,
|
||||
},
|
||||
}),
|
||||
updateStorage: new link.Event({
|
||||
updateStorage: new libLink.Event({
|
||||
type: "subspace_storage:update_storage",
|
||||
links: ["master-slave", "slave-instance"],
|
||||
broadcastTo: "instance",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
const fs = require("fs-extra");
|
||||
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const luaTools = require("@clusterio/lib/luaTools");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libLuaTools = require("@clusterio/lib/lua_tools");
|
||||
|
||||
function unexpectedError(err) {
|
||||
console.log("Unexpected error in subspace_storage");
|
||||
@@ -10,7 +10,7 @@ function unexpectedError(err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
class InstancePlugin extends libPlugin.BaseInstancePlugin {
|
||||
async init() {
|
||||
this.instance.server.on("ipc-subspace_storage:output", (output) => {
|
||||
this.provideItems(output).catch(unexpectedError);
|
||||
@@ -29,7 +29,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
|
||||
let response = await this.info.messages.getStorage.send(this.instance);
|
||||
// TODO Diff with dump of invdata produce minimal command to sync
|
||||
let itemsJson = luaTools.escapeString(JSON.stringify(response.items));
|
||||
let itemsJson = libLuaTools.escapeString(JSON.stringify(response.items));
|
||||
await this.instance.server.sendRcon(`/sc __subspace_storage__ UpdateInvData("${itemsJson}", true)`, true);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
console.log(response.items);
|
||||
}
|
||||
|
||||
let itemsJson = luaTools.escapeString(JSON.stringify(response.items));
|
||||
let itemsJson = libLuaTools.escapeString(JSON.stringify(response.items));
|
||||
await this.instance.server.sendRcon(`/sc __subspace_storage__ Import("${itemsJson}")`, true);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
|
||||
// XXX this should be moved to instance/clusterio api
|
||||
items.push(["signal-unixtime", Math.floor(Date.now()/1000)]);
|
||||
|
||||
let itemsJson = luaTools.escapeString(JSON.stringify(items));
|
||||
let itemsJson = libLuaTools.escapeString(JSON.stringify(items));
|
||||
await this.instance.server.sendRcon(`/sc __subspace_storage__ UpdateInvData("${itemsJson}")`, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,32 +2,32 @@
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const database = require("@clusterio/lib/database");
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const prometheus = require("@clusterio/lib/prometheus");
|
||||
const libDatabase = require("@clusterio/lib/database");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const { Counter, Gauge } = require("@clusterio/lib/prometheus");
|
||||
|
||||
const routes = require("./routes");
|
||||
const dole = require("./dole");
|
||||
|
||||
|
||||
const exportCounter = new prometheus.Counter(
|
||||
const exportCounter = new Counter(
|
||||
"clusterio_subspace_storage_export_total",
|
||||
"Resources exported by instance",
|
||||
{ labels: ["instance_id", "resource"] }
|
||||
);
|
||||
const importCounter = new prometheus.Counter(
|
||||
const importCounter = new Counter(
|
||||
"clusterio_subspace_storage_import_total",
|
||||
"Resources imported by instance",
|
||||
{ labels: ["instance_id", "resource"] }
|
||||
);
|
||||
const masterInventoryGauge = new prometheus.Gauge(
|
||||
const masterInventoryGauge = new Gauge(
|
||||
"clusterio_subspace_storage_master_inventory",
|
||||
"Amount of resources stored on master",
|
||||
{ labels: ["resource"] }
|
||||
);
|
||||
|
||||
|
||||
class MasterPlugin extends plugin.BaseMasterPlugin {
|
||||
class MasterPlugin extends libPlugin.BaseMasterPlugin {
|
||||
async init() {
|
||||
|
||||
this.items = await loadDatabase(this.master.config);
|
||||
@@ -175,12 +175,12 @@ async function loadDatabase(config) {
|
||||
console.log(`Loading ${itemsPath}`);
|
||||
try {
|
||||
let content = await fs.readFile(itemsPath);
|
||||
return new database.ItemDatabase(JSON.parse(content));
|
||||
return new libDatabase.ItemDatabase(JSON.parse(content));
|
||||
|
||||
} catch (err) {
|
||||
if (err.code === "ENOENT") {
|
||||
console.log("Creating new item database");
|
||||
return new database.ItemDatabase();
|
||||
return new libDatabase.ItemDatabase();
|
||||
|
||||
} else {
|
||||
throw err;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
"use strict";
|
||||
const path = require("path");
|
||||
|
||||
const prometheus = require("@clusterio/lib/prometheus");
|
||||
|
||||
|
||||
function addApiRoutes(app, items, endpointHitCounter) {
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
|
||||
const { slowTest, get, execCtl, sendRcon, getControl, instancesDir } = require("./index");
|
||||
|
||||
|
||||
async function getInstances() {
|
||||
let result = await link.messages.listInstances.send(getControl());
|
||||
let result = await libLink.messages.listInstances.send(getControl());
|
||||
return new Map(result.list.map(instance => [instance.id, instance]));
|
||||
}
|
||||
|
||||
@@ -170,14 +170,14 @@ describe("Integration of Clusterio", function() {
|
||||
|
||||
describe("user set-admin/whitelisted/banned", function() {
|
||||
async function getUsers() {
|
||||
let result = await link.messages.listUsers.send(getControl());
|
||||
let result = await libLink.messages.listUsers.send(getControl());
|
||||
return new Map(result.list.map(user => [user.name, user]));
|
||||
}
|
||||
|
||||
let lists = ["admin", "whitelisted", "banned"];
|
||||
it("should add and remove the given user to the list", async function() {
|
||||
slowTest(this);
|
||||
await link.messages.createUser.send(getControl(), { name: "list_test" });
|
||||
await libLink.messages.createUser.send(getControl(), { name: "list_test" });
|
||||
let user = (await getUsers()).get("list_test");
|
||||
for (let list of lists) {
|
||||
assert.equal(user[`is_${list}`], false, `unexpected ${list} status`);
|
||||
@@ -248,7 +248,7 @@ describe("Integration of Clusterio", function() {
|
||||
it("should create the given role", async function() {
|
||||
let args = "--description \"A temp role\" --permissions core.control.connect";
|
||||
await execCtl(`role create temp ${args}`);
|
||||
let result = await link.messages.listRoles.send(getControl());
|
||||
let result = await libLink.messages.listRoles.send(getControl());
|
||||
let role = result.list.find(role => role.name === "temp");
|
||||
assert.deepEqual(role, { id: 5, name: "temp", description: "A temp role", permissions: ["core.control.connect"] });
|
||||
});
|
||||
@@ -258,7 +258,7 @@ describe("Integration of Clusterio", function() {
|
||||
it("should modify the given role", async function() {
|
||||
let args = "--name new --description \"A new role\" --permissions";
|
||||
await execCtl(`role edit temp ${args}`);
|
||||
let result = await link.messages.listRoles.send(getControl());
|
||||
let result = await libLink.messages.listRoles.send(getControl());
|
||||
let role = result.list.find(role => role.name === "new");
|
||||
assert.deepEqual(role, { id: 5, name: "new", description: "A new role", permissions: [] });
|
||||
});
|
||||
@@ -267,7 +267,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("role delete", function() {
|
||||
it("should modify the given role", async function() {
|
||||
await execCtl("role delete new");
|
||||
let result = await link.messages.listRoles.send(getControl());
|
||||
let result = await libLink.messages.listRoles.send(getControl());
|
||||
let role = result.list.find(role => role.name === "new");
|
||||
assert(!role, "Role was not deleted");
|
||||
});
|
||||
@@ -282,7 +282,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("user create", function() {
|
||||
it("should create the given user", async function() {
|
||||
await execCtl("user create temp");
|
||||
let result = await link.messages.listUsers.send(getControl());
|
||||
let result = await libLink.messages.listUsers.send(getControl());
|
||||
let user = result.list.find(user => user.name === "temp");
|
||||
assert(user, "user was not created");
|
||||
});
|
||||
@@ -291,7 +291,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("user set-roles", function() {
|
||||
it("should set the roles on the user", async function() {
|
||||
await execCtl("user set-roles temp Admin");
|
||||
let result = await link.messages.listUsers.send(getControl());
|
||||
let result = await libLink.messages.listUsers.send(getControl());
|
||||
let user = result.list.find(user => user.name === "temp");
|
||||
assert.deepEqual(user.roles, [0]);
|
||||
});
|
||||
@@ -300,7 +300,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("user delete", function() {
|
||||
it("should delete the user", async function() {
|
||||
await execCtl("user delete temp");
|
||||
let result = await link.messages.listUsers.send(getControl());
|
||||
let result = await libLink.messages.listUsers.send(getControl());
|
||||
let user = result.list.find(user => user.name === "temp");
|
||||
assert(!user, "user was note deleted");
|
||||
});
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
|
||||
|
||||
describe("Integration of lib/factorio/export", function() {
|
||||
describe("exportLocale()", function() {
|
||||
it("returns a nested Map with base game locale information", async function() {
|
||||
let writePath = path.join("temp", "test", "server");
|
||||
let testServer = new factorio.FactorioServer("factorio", writePath, {});
|
||||
let testServer = new libFactorio.FactorioServer("factorio", writePath, {});
|
||||
await testServer.init();
|
||||
|
||||
let locale = await factorio._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
let locale = await libFactorio._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
|
||||
assert(locale instanceof Map, "locale is not a map");
|
||||
assert.equal(locale.get("entity-name.fish"), "Fish");
|
||||
|
||||
@@ -7,14 +7,14 @@ const phin = require("phin");
|
||||
const util = require("util");
|
||||
const events = require("events");
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const server = require("@clusterio/lib/factorio/server");
|
||||
|
||||
|
||||
class TestControl extends link.Link {
|
||||
class TestControl extends libLink.Link {
|
||||
constructor(connector) {
|
||||
super("control", "master", connector);
|
||||
link.attachAllMessages(this);
|
||||
libLink.attachAllMessages(this);
|
||||
}
|
||||
|
||||
async prepareDisconnectRequestHandler(message, request) {
|
||||
@@ -27,7 +27,7 @@ class TestControl extends link.Link {
|
||||
async instanceOutputEventHandler() { }
|
||||
}
|
||||
|
||||
class TestControlConnector extends link.WebSocketClientConnector {
|
||||
class TestControlConnector extends libLink.WebSocketClientConnector {
|
||||
register() {
|
||||
this.sendHandshake("register_control", { token: this.token, agent: "clusterioctl", version: "test" });
|
||||
}
|
||||
@@ -81,7 +81,7 @@ async function execCtl(...args) {
|
||||
}
|
||||
|
||||
async function sendRcon(instanceId, command) {
|
||||
let response = await link.messages.sendRcon.send(control, { instance_id: instanceId, command });
|
||||
let response = await libLink.messages.sendRcon.send(control, { instance_id: instanceId, command });
|
||||
return response.result;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ const fs = require("fs-extra");
|
||||
const jszip = require("jszip");
|
||||
const path = require("path");
|
||||
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
|
||||
const { slowTest } = require("./index");
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("Integration of lib/factorio/patch", function() {
|
||||
let savePath = path.join("temp", "test", "integration", "saves", "test.zip");
|
||||
it("should patch a freeplay game", async function() {
|
||||
slowTest(this);
|
||||
await factorio.patch(savePath, [{
|
||||
await libFactorio.patch(savePath, [{
|
||||
name: "test",
|
||||
version: "1.0.0",
|
||||
dependencies: {},
|
||||
@@ -39,7 +39,7 @@ describe("Integration of lib/factorio/patch", function() {
|
||||
});
|
||||
it("should remove old modules in a save", async function() {
|
||||
slowTest(this);
|
||||
await factorio.patch(savePath, []);
|
||||
await libFactorio.patch(savePath, []);
|
||||
let zip = await jszip.loadAsync(await fs.readFile(savePath));
|
||||
assert.equal(zip.file("test/modules/test/test.lua"), null);
|
||||
});
|
||||
|
||||
@@ -4,8 +4,8 @@ const events = require("events");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
|
||||
const { slowTest } = require("./index");
|
||||
|
||||
@@ -13,7 +13,7 @@ const { slowTest } = require("./index");
|
||||
describe("Integration of lib/factorio/server", function() {
|
||||
describe("_getVersion()", function() {
|
||||
it("should get a version from factorio's changelog.txt", async function() {
|
||||
let version = await factorio._getVersion(path.join("factorio", "data", "changelog.txt"));
|
||||
let version = await libFactorio._getVersion(path.join("factorio", "data", "changelog.txt"));
|
||||
if (!/^\d+\.\d+\.\d+$/.test(version)) {
|
||||
assert.fail(`Detected version '${version}' does not followed the format x.y.z`);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ describe("Integration of lib/factorio/server", function() {
|
||||
|
||||
describe("class FactorioServer", function() {
|
||||
let writePath = path.join("temp", "test", "integration");
|
||||
let server = new factorio.FactorioServer("factorio", writePath, {});
|
||||
let server = new libFactorio.FactorioServer("factorio", writePath, {});
|
||||
let logFile;
|
||||
|
||||
before(async function() {
|
||||
@@ -215,7 +215,9 @@ describe("Integration of lib/factorio/server", function() {
|
||||
|
||||
await assert.rejects(
|
||||
startPromise,
|
||||
new errors.EnvironmentError("Factorio server was unexpectedly killed, is the system low on memory?")
|
||||
new libErrors.EnvironmentError(
|
||||
"Factorio server was unexpectedly killed, is the system low on memory?"
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -225,7 +227,7 @@ describe("Integration of lib/factorio/server", function() {
|
||||
|
||||
await assert.rejects(
|
||||
server.start("does-not-exist.zip"),
|
||||
new errors.EnvironmentError("Factorio server unexpectedly shut down with code 1")
|
||||
new libErrors.EnvironmentError("Factorio server unexpectedly shut down with code 1")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+18
-18
@@ -1,9 +1,9 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const command = require("@clusterio/lib/command");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const link = require("@clusterio/lib/link");
|
||||
const libCommand = require("@clusterio/lib/command");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const mock = require("../mock");
|
||||
|
||||
|
||||
@@ -39,49 +39,49 @@ describe("lib/command", function() {
|
||||
});
|
||||
|
||||
let testControl = new mock.MockControl(mockConnector);
|
||||
link.messages.listSlaves.attach(testControl);
|
||||
link.messages.listInstances.attach(testControl);
|
||||
link.messages.listRoles.attach(testControl);
|
||||
libLink.messages.listSlaves.attach(testControl);
|
||||
libLink.messages.listInstances.attach(testControl);
|
||||
libLink.messages.listRoles.attach(testControl);
|
||||
|
||||
describe("resolveSlave", function() {
|
||||
it("should pass an integer like string back", async function() {
|
||||
assert.equal(await command.resolveSlave(null, "123"), 123);
|
||||
assert.equal(await libCommand.resolveSlave(null, "123"), 123);
|
||||
});
|
||||
it("should resolve a slave name with the master server", async function() {
|
||||
assert.equal(await command.resolveSlave(testControl, "Test Slave"), 11);
|
||||
assert.equal(await libCommand.resolveSlave(testControl, "Test Slave"), 11);
|
||||
});
|
||||
it("should throw if slave is not found", async function() {
|
||||
await assert.rejects(
|
||||
command.resolveSlave(testControl, "invalid"),
|
||||
new errors.CommandError("No slave named invalid")
|
||||
libCommand.resolveSlave(testControl, "invalid"),
|
||||
new libErrors.CommandError("No slave named invalid")
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("resolveInstance", function() {
|
||||
it("should pass an integer like string back", async function() {
|
||||
assert.equal(await command.resolveInstance(null, "123"), 123);
|
||||
assert.equal(await libCommand.resolveInstance(null, "123"), 123);
|
||||
});
|
||||
it("should resolve an instance name with the master server", async function() {
|
||||
assert.equal(await command.resolveInstance(testControl, "Test Instance"), 57);
|
||||
assert.equal(await libCommand.resolveInstance(testControl, "Test Instance"), 57);
|
||||
});
|
||||
it("should throw if instance is not found", async function() {
|
||||
await assert.rejects(
|
||||
command.resolveInstance(testControl, "invalid"),
|
||||
new errors.CommandError("No instance named invalid")
|
||||
libCommand.resolveInstance(testControl, "invalid"),
|
||||
new libErrors.CommandError("No instance named invalid")
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("retrieveRole", function() {
|
||||
it("should retrieve a role by id from an integer like string", async function() {
|
||||
assert.deepEqual(await command.retrieveRole(testControl, "28"), testRole);
|
||||
assert.deepEqual(await libCommand.retrieveRole(testControl, "28"), testRole);
|
||||
});
|
||||
it("should retrieve a role by name from a string", async function() {
|
||||
assert.deepEqual(await command.retrieveRole(testControl, "Test Role"), testRole);
|
||||
assert.deepEqual(await libCommand.retrieveRole(testControl, "Test Role"), testRole);
|
||||
});
|
||||
it("should throw if role is not found", async function() {
|
||||
await assert.rejects(
|
||||
command.retrieveRole(testControl, "invalid"),
|
||||
new errors.CommandError("No role named invalid")
|
||||
libCommand.retrieveRole(testControl, "invalid"),
|
||||
new libErrors.CommandError("No role named invalid")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+34
-34
@@ -3,24 +3,24 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const database = require("@clusterio/lib/database");
|
||||
const libDatabase = require("@clusterio/lib/database");
|
||||
|
||||
describe("lib/database", function() {
|
||||
describe("mapToObject()", function() {
|
||||
it("should throw on non-string key", function() {
|
||||
assert.throws(
|
||||
() => database.mapToObject(new Map([[1, 1]])),
|
||||
() => libDatabase.mapToObject(new Map([[1, 1]])),
|
||||
new Error("Expected all keys to be string but got number")
|
||||
);
|
||||
assert.throws(
|
||||
() => database.mapToObject(new Map([[Symbol("test"), 1]])),
|
||||
() => libDatabase.mapToObject(new Map([[Symbol("test"), 1]])),
|
||||
new Error("Expected all keys to be string but got symbol")
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw convert a map to an object", function() {
|
||||
assert.deepEqual(
|
||||
database.mapToObject(new Map([["a", 1], ["b", true]])),
|
||||
libDatabase.mapToObject(new Map([["a", 1], ["b", true]])),
|
||||
{ "a": 1, "b": true }
|
||||
);
|
||||
});
|
||||
@@ -32,7 +32,7 @@ describe("lib/database", function() {
|
||||
for (let type of badTypes) {
|
||||
it(`should reject on ${type} JSON`, async function() {
|
||||
await assert.rejects(
|
||||
database.loadJsonAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
libDatabase.loadJsonAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
new Error(`Expected object but got ${type}`)
|
||||
);
|
||||
});
|
||||
@@ -40,21 +40,21 @@ describe("lib/database", function() {
|
||||
|
||||
it("should work on empty object JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await database.loadJsonAsMap(path.join("test", "file", "json", "object.json")),
|
||||
await libDatabase.loadJsonAsMap(path.join("test", "file", "json", "object.json")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
|
||||
it("should work on object JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await database.loadJsonAsMap(path.join("test", "file", "json", "load_map.json")),
|
||||
await libDatabase.loadJsonAsMap(path.join("test", "file", "json", "load_map.json")),
|
||||
new Map([["a", 1], ["b", true]])
|
||||
);
|
||||
});
|
||||
|
||||
it("should give an empty Map for non-existant file", async function() {
|
||||
assert.deepEqual(
|
||||
await database.loadJsonAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
await libDatabase.loadJsonAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
@@ -75,7 +75,7 @@ describe("lib/database", function() {
|
||||
}
|
||||
|
||||
await deleteTestFile();
|
||||
await database.saveMapAsJson(
|
||||
await libDatabase.saveMapAsJson(
|
||||
testFile, new Map([["c", {}], ["d", "foo"]])
|
||||
);
|
||||
|
||||
@@ -92,7 +92,7 @@ describe("lib/database", function() {
|
||||
for (let type of badTypes) {
|
||||
it(`should reject on ${type} JSON`, async function() {
|
||||
await assert.rejects(
|
||||
database.loadJsonArrayAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
new Error(`Expected array but got ${type}`)
|
||||
);
|
||||
});
|
||||
@@ -100,35 +100,35 @@ describe("lib/database", function() {
|
||||
|
||||
it("should reject on null element", async function() {
|
||||
await assert.rejects(
|
||||
database.loadJsonArrayAsMap(path.join("test", "file", "json", "array_null.json")),
|
||||
libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "array_null.json")),
|
||||
new Error("Expected all elements to be objects")
|
||||
);
|
||||
});
|
||||
|
||||
it("should reject on element missing id", async function() {
|
||||
await assert.rejects(
|
||||
database.loadJsonArrayAsMap(path.join("test", "file", "json", "array_object.json")),
|
||||
libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "array_object.json")),
|
||||
new Error("Expected all elements to have an id property")
|
||||
);
|
||||
});
|
||||
|
||||
it("should work on empty array JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await database.loadJsonArrayAsMap(path.join("test", "file", "json", "array.json")),
|
||||
await libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "array.json")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
|
||||
it("should work on array JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await database.loadJsonArrayAsMap(path.join("test", "file", "json", "load_array_map.json")),
|
||||
await libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "load_array_map.json")),
|
||||
new Map([["a", { id: "a" }], ["b", { id: "b" }]])
|
||||
);
|
||||
});
|
||||
|
||||
it("should give an empty Map for non-existant file", async function() {
|
||||
assert.deepEqual(
|
||||
await database.loadJsonArrayAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
await libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
@@ -149,7 +149,7 @@ describe("lib/database", function() {
|
||||
}
|
||||
|
||||
await deleteTestFile();
|
||||
await database.saveMapAsJsonArray(
|
||||
await libDatabase.saveMapAsJsonArray(
|
||||
testFile, new Map([["c", { id: "c" }], ["d", { id: "d" }]])
|
||||
);
|
||||
|
||||
@@ -163,23 +163,23 @@ describe("lib/database", function() {
|
||||
describe("class ItemDatabase", function() {
|
||||
describe("constructor()", function() {
|
||||
it("should create an empty database with no args", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.deepEqual(items._items, new Map());
|
||||
});
|
||||
|
||||
it("should restore the passed serialized database", function() {
|
||||
let items = new database.ItemDatabase({ "a": 1, "b": 2 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 1, "b": 2 });
|
||||
assert.deepEqual(items._items, new Map([["a", 1], ["b", 2]]));
|
||||
});
|
||||
|
||||
it("should throw on invalid serialized database", function() {
|
||||
assert.throws(
|
||||
() => new database.ItemDatabase({ "a": NaN }),
|
||||
() => new libDatabase.ItemDatabase({ "a": NaN }),
|
||||
new Error("count must be a number")
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => new database.ItemDatabase({ "a": "a" }),
|
||||
() => new libDatabase.ItemDatabase({ "a": "a" }),
|
||||
new Error("count must be a number")
|
||||
);
|
||||
});
|
||||
@@ -187,36 +187,36 @@ describe("lib/database", function() {
|
||||
|
||||
describe(".serialize()", function() {
|
||||
it("should return a serialized database", function() {
|
||||
let items = new database.ItemDatabase({ "a": 10 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
assert.deepEqual(items.serialize(), { "a": 10 });
|
||||
});
|
||||
|
||||
it("should remove zero count entries", function() {
|
||||
let items = new database.ItemDatabase({ "a": 0 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 0 });
|
||||
assert.deepEqual(items.serialize(), {});
|
||||
});
|
||||
});
|
||||
|
||||
describe(".size", function() {
|
||||
it("should give an approximate size of the database", function() {
|
||||
let items = new database.ItemDatabase({ "a": 10 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
assert.equal(items.size, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".getItemCount()", function() {
|
||||
it("should return the count of the given item", function() {
|
||||
let items = new database.ItemDatabase({ "a": 10 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
assert.equal(items.getItemCount("a"), 10);
|
||||
});
|
||||
|
||||
it("should return zero if item does not exist", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.equal(items.getItemCount("b"), 0);
|
||||
});
|
||||
|
||||
it("should throw on invalid name", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.getItemCount(2),
|
||||
new Error("name must be a string")
|
||||
@@ -226,19 +226,19 @@ describe("lib/database", function() {
|
||||
|
||||
describe(".addItem()", function() {
|
||||
it("should add a new item", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
items.addItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", 10]]));
|
||||
});
|
||||
|
||||
it("should add an existing item", function() {
|
||||
let items = new database.ItemDatabase({ "a": 10 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
items.addItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", 20]]));
|
||||
});
|
||||
|
||||
it("should throw on invalid name", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.addItem(2, 10),
|
||||
new Error("name must be a string")
|
||||
@@ -246,7 +246,7 @@ describe("lib/database", function() {
|
||||
});
|
||||
|
||||
it("should throw on invalid count", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.addItem("a", NaN),
|
||||
new Error("count must be a number")
|
||||
@@ -260,19 +260,19 @@ describe("lib/database", function() {
|
||||
|
||||
describe(".removeItem()", function() {
|
||||
it("should remove an existing item", function() {
|
||||
let items = new database.ItemDatabase({ "a": 20 });
|
||||
let items = new libDatabase.ItemDatabase({ "a": 20 });
|
||||
items.removeItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", 10]]));
|
||||
});
|
||||
|
||||
it("should turn a non-existing item negative", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
items.removeItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", -10]]));
|
||||
});
|
||||
|
||||
it("should throw on invalid name", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.removeItem(2, 10),
|
||||
new Error("name must be a string")
|
||||
@@ -280,7 +280,7 @@ describe("lib/database", function() {
|
||||
});
|
||||
|
||||
it("should throw on invalid count", function() {
|
||||
let items = new database.ItemDatabase();
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.removeItem("a", "b"),
|
||||
new Error("count must be a number")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
|
||||
|
||||
describe("lib/factorio/export", function() {
|
||||
@@ -10,12 +10,12 @@ describe("lib/factorio/export", function() {
|
||||
let testServer;
|
||||
before(async function() {
|
||||
let writePath = path.join("temp", "test", "server");
|
||||
testServer = new factorio.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
testServer = new libFactorio.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
await testServer.init();
|
||||
});
|
||||
|
||||
it("returns a flattened mapping with locale definitions", async function() {
|
||||
let locale = await factorio._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
let locale = await libFactorio._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
assert.deepEqual(locale, new Map([["test.key-a", "1"], ["test.key-b", "2"]]));
|
||||
});
|
||||
});
|
||||
|
||||
+16
-16
@@ -4,7 +4,7 @@ const fs = require("fs-extra");
|
||||
const jszip = require("jszip");
|
||||
const path = require("path");
|
||||
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
|
||||
|
||||
describe("lib/factorio", function() {
|
||||
@@ -14,7 +14,7 @@ describe("lib/factorio", function() {
|
||||
zip.file("root/foo.txt", "");
|
||||
zip.file("root/bar.txt", "");
|
||||
|
||||
assert.equal(factorio._findRoot(zip), "root");
|
||||
assert.equal(libFactorio._findRoot(zip), "root");
|
||||
});
|
||||
|
||||
it("should throw if files are at the root of the zip", function() {
|
||||
@@ -23,7 +23,7 @@ describe("lib/factorio", function() {
|
||||
zip.file("bar.txt", "");
|
||||
|
||||
assert.throws(
|
||||
() => factorio._findRoot(zip),
|
||||
() => libFactorio._findRoot(zip),
|
||||
new Error("Zip contains file 'bar.txt' in root dir")
|
||||
);
|
||||
});
|
||||
@@ -34,7 +34,7 @@ describe("lib/factorio", function() {
|
||||
zip.file("root-2/bar.txt", "");
|
||||
|
||||
assert.throws(
|
||||
() => factorio._findRoot(zip),
|
||||
() => libFactorio._findRoot(zip),
|
||||
new Error("Zip contains multiple root folders")
|
||||
);
|
||||
});
|
||||
@@ -43,7 +43,7 @@ describe("lib/factorio", function() {
|
||||
let zip = new jszip();
|
||||
|
||||
assert.throws(
|
||||
() => factorio._findRoot(zip),
|
||||
() => libFactorio._findRoot(zip),
|
||||
new Error("Empty zip file")
|
||||
);
|
||||
});
|
||||
@@ -79,7 +79,7 @@ describe("lib/factorio", function() {
|
||||
};
|
||||
|
||||
it("should produce output matching the reference", function() {
|
||||
assert.equal(factorio._generateLoader(patchInfo), reference);
|
||||
assert.equal(libFactorio._generateLoader(patchInfo), reference);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "1.0.0", dependencies: {"b": "*"} },
|
||||
{ name: "b", version: "1.0.0", dependencies: {} },
|
||||
];
|
||||
factorio._reorderDependencies(modules);
|
||||
libFactorio._reorderDependencies(modules);
|
||||
assert(modules[0].name === "b", "Dependency was not reorederd");
|
||||
});
|
||||
it("should throw on invalid version", function() {
|
||||
@@ -97,7 +97,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "foo", dependencies: {} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Invalid version 'foo' for module a")
|
||||
);
|
||||
});
|
||||
@@ -106,7 +106,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "1.0.0", dependencies: {"b": "invalid"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Invalid version range 'invalid' for dependency b on module a")
|
||||
);
|
||||
});
|
||||
@@ -115,7 +115,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "1.0.0", dependencies: {"b": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Missing dependency b for module a")
|
||||
);
|
||||
modules = [
|
||||
@@ -124,7 +124,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "c", version: "1.0.0", dependencies: {"d": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Missing dependency d for module c")
|
||||
);
|
||||
});
|
||||
@@ -134,7 +134,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "b", version: "1.0.0", dependencies: {"a": ">=2"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Module b requires a >=2")
|
||||
);
|
||||
});
|
||||
@@ -144,7 +144,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "b", version: "1.0.0", dependencies: {"a": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Module dependency loop detected: a -> b -> a")
|
||||
);
|
||||
modules = [
|
||||
@@ -154,7 +154,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "c", version: "1.0.0", dependencies: {"a": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => factorio._reorderDependencies(modules),
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
new Error("Module dependency loop detected: b -> c -> a -> b")
|
||||
);
|
||||
});
|
||||
@@ -194,7 +194,7 @@ describe("lib/factorio", function() {
|
||||
}
|
||||
let success = false;
|
||||
try {
|
||||
factorio._reorderDependencies(modules);
|
||||
libFactorio._reorderDependencies(modules);
|
||||
success = true;
|
||||
} catch (err) { }
|
||||
if (success) {
|
||||
@@ -217,7 +217,7 @@ describe("lib/factorio", function() {
|
||||
await fs.outputFile(zipPath, await zip.generateAsync({ type: "nodebuffer" }));
|
||||
|
||||
await assert.rejects(
|
||||
factorio.patch(zipPath, []),
|
||||
libFactorio.patch(zipPath, []),
|
||||
new Error("Unable to patch save, unknown scenario (3acc3be3861144e55604f5ac2f2555071885ebc4)")
|
||||
);
|
||||
});
|
||||
|
||||
+20
-20
@@ -4,22 +4,22 @@ const events = require("events");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const factorio = require("@clusterio/lib/factorio");
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const { testLines } = require("./lines");
|
||||
|
||||
|
||||
describe("lib/factorio/server", function() {
|
||||
describe("_getVersion()", function() {
|
||||
it("should get the version from a changelog", async function() {
|
||||
let version = await factorio._getVersion(path.join("test", "file", "changelog-test.txt"));
|
||||
let version = await libFactorio._getVersion(path.join("test", "file", "changelog-test.txt"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should return null if unable to find the version", async function() {
|
||||
let version = await factorio._getVersion(path.join("test", "file", "changelog-bad.txt"));
|
||||
let version = await libFactorio._getVersion(path.join("test", "file", "changelog-bad.txt"));
|
||||
assert.equal(version, null);
|
||||
});
|
||||
it("should return null if file does not exist", async function() {
|
||||
let version = await factorio._getVersion(path.join("test", "file", "does-not-exist.txt"));
|
||||
let version = await libFactorio._getVersion(path.join("test", "file", "does-not-exist.txt"));
|
||||
assert.equal(version, null);
|
||||
});
|
||||
});
|
||||
@@ -27,7 +27,7 @@ describe("lib/factorio/server", function() {
|
||||
describe("_versionOrder()", function() {
|
||||
it("should sort an array of versions", function() {
|
||||
let versions = ["1.2.3", "0.1.4", "0.1.2", "1.2.3", "0.1.5", "1.10.2"];
|
||||
versions.sort(factorio._versionOrder);
|
||||
versions.sort(libFactorio._versionOrder);
|
||||
assert.deepEqual(
|
||||
versions,
|
||||
["1.10.2", "1.2.3", "1.2.3", "0.1.5", "0.1.4", "0.1.2"]
|
||||
@@ -38,46 +38,46 @@ describe("lib/factorio/server", function() {
|
||||
describe("_findVersion()", function() {
|
||||
it("should find a given install dir with latest as target", async function() {
|
||||
let installDir = path.join("test", "file", "factorio");
|
||||
let [dir, version] = await factorio._findVersion(installDir, "latest");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "latest");
|
||||
assert.equal(dir, path.join(installDir, "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should find a given install dir with correct version as target", async function() {
|
||||
let installDir = path.join("test", "file", "factorio");
|
||||
let [dir, version] = await factorio._findVersion(installDir, "0.1.1");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "0.1.1");
|
||||
assert.equal(dir, path.join(installDir, "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should reject if the install dir version does not match target version", async function() {
|
||||
let installDir = path.join("test", "file", "factorio");
|
||||
await assert.rejects(
|
||||
factorio._findVersion(installDir, "0.1.2"),
|
||||
libFactorio._findVersion(installDir, "0.1.2"),
|
||||
new Error("Factorio version 0.1.2 was requested, but install directory contains 0.1.1")
|
||||
);
|
||||
});
|
||||
it("should search given directory for latest Factorio install", async function() {
|
||||
let installDir = path.join("test", "file");
|
||||
let [dir, version] = await factorio._findVersion(installDir, "latest");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "latest");
|
||||
assert.equal(dir, path.join(installDir, "factorio", "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should search given directory for given Factorio install", async function() {
|
||||
let installDir = path.join("test", "file");
|
||||
let [dir, version] = await factorio._findVersion(installDir, "0.1.1");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "0.1.1");
|
||||
assert.equal(dir, path.join(installDir, "factorio", "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should reject if no factorio install with the given version was found", async function() {
|
||||
let installDir = path.join("test", "file");
|
||||
await assert.rejects(
|
||||
factorio._findVersion(installDir, "0.1.2"),
|
||||
libFactorio._findVersion(installDir, "0.1.2"),
|
||||
new Error("Unable to find Factorio version 0.1.2")
|
||||
);
|
||||
});
|
||||
it("should reject if no factorio install was found", async function() {
|
||||
let installDir = path.join("test", "file", "instances");
|
||||
await assert.rejects(
|
||||
factorio._findVersion(installDir, "latest"),
|
||||
libFactorio._findVersion(installDir, "latest"),
|
||||
new Error(`Unable to find any Factorio install in ${installDir}`)
|
||||
);
|
||||
});
|
||||
@@ -85,7 +85,7 @@ describe("lib/factorio/server", function() {
|
||||
|
||||
describe("randomDynamicPort()", function() {
|
||||
it("should return a port number", function() {
|
||||
let port = factorio._randomDynamicPort();
|
||||
let port = libFactorio._randomDynamicPort();
|
||||
assert.equal(typeof port, "number");
|
||||
assert(Number.isInteger(port));
|
||||
assert(0 <= port && port < 2**16);
|
||||
@@ -96,31 +96,31 @@ describe("lib/factorio/server", function() {
|
||||
return (49152 <= port && port <= 65535);
|
||||
}
|
||||
for (let i=0; i < 20; i++) {
|
||||
assert(validate(factorio._randomDynamicPort()));
|
||||
assert(validate(libFactorio._randomDynamicPort()));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("generatePassword()", function() {
|
||||
it("should return a string", async function() {
|
||||
let password = await factorio._generatePassword(1);
|
||||
let password = await libFactorio._generatePassword(1);
|
||||
assert.equal(typeof password, "string");
|
||||
});
|
||||
|
||||
it("should return a string of the given length", async function() {
|
||||
let password = await factorio._generatePassword(10);
|
||||
let password = await libFactorio._generatePassword(10);
|
||||
assert.equal(password.length, 10);
|
||||
});
|
||||
|
||||
it("should contain only a-z, A-Z, 0-9", async function() {
|
||||
let password = await factorio._generatePassword(10);
|
||||
let password = await libFactorio._generatePassword(10);
|
||||
assert(/^[a-zA-Z0-9]+$/.test(password), `${password} failed test`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("class LineSplitter", function() {
|
||||
function createSplitter(lines) {
|
||||
return new factorio._LineSplitter(line => lines.push(line.toString("utf-8")));
|
||||
return new libFactorio._LineSplitter(line => lines.push(line.toString("utf-8")));
|
||||
}
|
||||
|
||||
it("should split three lines", function() {
|
||||
@@ -159,7 +159,7 @@ describe("lib/factorio/server", function() {
|
||||
it("should parse the test lines", function() {
|
||||
for (let [line, reference] of testLines) {
|
||||
reference.source = "test";
|
||||
let output = factorio._parseOutput(line, "test");
|
||||
let output = libFactorio._parseOutput(line, "test");
|
||||
delete output.received;
|
||||
assert.deepEqual(output, reference);
|
||||
}
|
||||
@@ -168,7 +168,7 @@ describe("lib/factorio/server", function() {
|
||||
|
||||
describe("class FactorioServer", function() {
|
||||
let writePath = path.join("temp", "test", "server");
|
||||
let server = new factorio.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
let server = new libFactorio.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
|
||||
describe(".init()", function() {
|
||||
it("should not throw on first call", async function() {
|
||||
|
||||
@@ -3,10 +3,10 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const fileOps = require("@clusterio/lib/fileOps");
|
||||
const libFileOps = require("@clusterio/lib/file_ops");
|
||||
|
||||
describe("fileOps.js", function(){
|
||||
let baseDir = path.join("temp", "test", "fileOps");
|
||||
describe("lib/file_ops", function() {
|
||||
let baseDir = path.join("temp", "test", "file_ops");
|
||||
async function setupTestingEnv() {
|
||||
await fs.ensureDir(path.join(baseDir, "test", "folder"));
|
||||
await fs.ensureDir(path.join(baseDir, "test", "another folder"));
|
||||
@@ -17,17 +17,17 @@ describe("fileOps.js", function(){
|
||||
|
||||
before(setupTestingEnv);
|
||||
|
||||
describe("fileOps.getNewestFile()", function(){
|
||||
describe("getNewestFile()", function() {
|
||||
it("returns a string in a directory with files", async function() {
|
||||
let newest = await fileOps.getNewestFile(path.join(baseDir, "test"));
|
||||
let newest = await libFileOps.getNewestFile(path.join(baseDir, "test"));
|
||||
assert.equal(typeof newest, "string");
|
||||
});
|
||||
it("returns null if all entries were filtered out", async function() {
|
||||
let newest = await fileOps.getNewestFile(path.join(baseDir, "test"), (name) => !name.endsWith(".txt"));
|
||||
let newest = await libFileOps.getNewestFile(path.join(baseDir, "test"), (name) => !name.endsWith(".txt"));
|
||||
assert.equal(newest, null);
|
||||
});
|
||||
it("returns null if directory is empty", async function() {
|
||||
let newest = await fileOps.getNewestFile(path.join(baseDir, "test", "folder"));
|
||||
let newest = await libFileOps.getNewestFile(path.join(baseDir, "test", "folder"));
|
||||
assert.equal(newest, null);
|
||||
});
|
||||
});
|
||||
+3
-3
@@ -4,21 +4,21 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
const stream = require("stream");
|
||||
|
||||
const hash = require("@clusterio/lib/hash");
|
||||
const libHash = require("@clusterio/lib/hash");
|
||||
|
||||
|
||||
describe("lib/hash", function() {
|
||||
describe("hashStream()", function() {
|
||||
it("should hash a stream of bytes", async function() {
|
||||
let stream = fs.createReadStream(path.join("test", "file", "hash.txt"));
|
||||
let result = await hash.hashStream(stream);
|
||||
let result = await libHash.hashStream(stream);
|
||||
assert.equal(result, "be417768b5c3c5c1d9bcb2e7c119196dd76b5570");
|
||||
});
|
||||
});
|
||||
|
||||
describe("hashFile()", function() {
|
||||
it("should hash a file", async function() {
|
||||
let result = await hash.hashFile(path.join("test", "file", "hash.txt"));
|
||||
let result = await libHash.hashFile(path.join("test", "file", "hash.txt"));
|
||||
assert.equal(result, "be417768b5c3c5c1d9bcb2e7c119196dd76b5570");
|
||||
});
|
||||
});
|
||||
|
||||
+7
-7
@@ -1,18 +1,18 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const helpers = require("@clusterio/lib/helpers");
|
||||
const libHelpers = require("@clusterio/lib/helpers");
|
||||
|
||||
|
||||
describe("lib/helpers", function() {
|
||||
describe("basicType()", function() {
|
||||
it("should return the expected values", function() {
|
||||
assert.equal(helpers.basicType("s"), "string");
|
||||
assert.equal(helpers.basicType(null), "null");
|
||||
assert.equal(helpers.basicType(undefined), "undefined");
|
||||
assert.equal(helpers.basicType([1, 2]), "array");
|
||||
assert.equal(helpers.basicType(7), "number");
|
||||
assert.equal(helpers.basicType({ a: 1 }), "object");
|
||||
assert.equal(libHelpers.basicType("s"), "string");
|
||||
assert.equal(libHelpers.basicType(null), "null");
|
||||
assert.equal(libHelpers.basicType(undefined), "undefined");
|
||||
assert.equal(libHelpers.basicType([1, 2]), "array");
|
||||
assert.equal(libHelpers.basicType(7), "number");
|
||||
assert.equal(libHelpers.basicType({ a: 1 }), "object");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,12 +3,12 @@ const assert = require("assert").strict;
|
||||
const events = require("events");
|
||||
|
||||
const mock = require("../../mock");
|
||||
const link = require("@clusterio/lib/link");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
|
||||
|
||||
describe("lib/link/connectors", function() {
|
||||
describe("class WebSocketBaseConnector", function() {
|
||||
let testConnector = new link.WebSocketBaseConnector();
|
||||
let testConnector = new libLink.WebSocketBaseConnector();
|
||||
|
||||
describe("._dropSendBufferSeq()", function() {
|
||||
beforeEach(function() {
|
||||
@@ -34,7 +34,7 @@ describe("lib/link/connectors", function() {
|
||||
});
|
||||
|
||||
describe("class WebSocketClientConnector", function() {
|
||||
let testConnector = new link.WebSocketClientConnector("url", 1);
|
||||
let testConnector = new libLink.WebSocketClientConnector("url", 1);
|
||||
testConnector._socket = new mock.MockSocket();
|
||||
|
||||
describe(".register()", function() {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
const assert = require("assert").strict;
|
||||
const events = require("events");
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const schema = require("@clusterio/lib/schema");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const mock = require("../../mock");
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ describe("lib/link/link", function() {
|
||||
|
||||
before(function() {
|
||||
testConnector = new mock.MockConnector();
|
||||
testLink = new link.Link("source", "target", testConnector);
|
||||
testLink.setValidator("simple", schema.compile({
|
||||
testLink = new libLink.Link("source", "target", testConnector);
|
||||
testLink.setValidator("simple", libSchema.compile({
|
||||
properties: {
|
||||
"data": {
|
||||
type: "object",
|
||||
@@ -78,7 +78,7 @@ describe("lib/link/link", function() {
|
||||
it("should throw on message without validator", function() {
|
||||
assert.throws(
|
||||
() => testLink.processMessage({ seq: 1, type: "no_validator", data: {} }),
|
||||
new errors.InvalidMessage("No validator for no_validator on source-target")
|
||||
new libErrors.InvalidMessage("No validator for no_validator on source-target")
|
||||
);
|
||||
});
|
||||
it("should throw on message failing validation", function() {
|
||||
@@ -90,7 +90,7 @@ describe("lib/link/link", function() {
|
||||
it("should throw on unhandled message", function() {
|
||||
assert.throws(
|
||||
() => testLink.processMessage({ seq: 1, type: "simple", data: { string: "a" }}),
|
||||
new errors.InvalidMessage("Unhandled message simple")
|
||||
new libErrors.InvalidMessage("Unhandled message simple")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+11
-11
@@ -1,20 +1,20 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const mock = require("../../mock");
|
||||
|
||||
|
||||
describe("lib/link/messages", function() {
|
||||
let testSourceLink = new link.Link("source", "target", new mock.MockConnector());
|
||||
let testTargetLink = new link.Link("target", "source", new mock.MockConnector());
|
||||
let testSourceLink = new libLink.Link("source", "target", new mock.MockConnector());
|
||||
let testTargetLink = new libLink.Link("target", "source", new mock.MockConnector());
|
||||
|
||||
let lastTargetSent;
|
||||
testTargetLink.send = (type, data) => { lastTargetSent = { type, data }; };
|
||||
|
||||
describe("class Request", function() {
|
||||
let testRequest = new link.Request({
|
||||
let testRequest = new libLink.Request({
|
||||
type: "test",
|
||||
links: ["source-target"],
|
||||
requestProperties: {
|
||||
@@ -25,7 +25,7 @@ describe("lib/link/messages", function() {
|
||||
describe("constructor", function() {
|
||||
it("should throw on invalid forwardTo", function() {
|
||||
assert.throws(
|
||||
() => new link.Request({ links: [], forwardTo: "invalid" }),
|
||||
() => new libLink.Request({ links: [], forwardTo: "invalid" }),
|
||||
new Error("Invalid forwardTo value invalid")
|
||||
);
|
||||
});
|
||||
@@ -95,7 +95,7 @@ describe("lib/link/messages", function() {
|
||||
testSourceLink.waitFor = (type, condition) => ({ data: { error: "test error" }});
|
||||
await assert.rejects(
|
||||
testRequest.send(testSourceLink, { test: "blah" }),
|
||||
new errors.RequestError("test error")
|
||||
new libErrors.RequestError("test error")
|
||||
);
|
||||
delete testSourceLink.waitFor;
|
||||
});
|
||||
@@ -103,7 +103,7 @@ describe("lib/link/messages", function() {
|
||||
});
|
||||
|
||||
describe("class Event", function() {
|
||||
let testEvent = new link.Event({
|
||||
let testEvent = new libLink.Event({
|
||||
type: "test",
|
||||
links: ["source-target"],
|
||||
eventProperties: {
|
||||
@@ -114,13 +114,13 @@ describe("lib/link/messages", function() {
|
||||
describe("constructor", function() {
|
||||
it("should throw on invalid forwardTo", function() {
|
||||
assert.throws(
|
||||
() => new link.Event({ forwardTo: "invalid" }),
|
||||
() => new libLink.Event({ forwardTo: "invalid" }),
|
||||
new Error("Invalid forwardTo value invalid")
|
||||
);
|
||||
});
|
||||
it("should throw on invalid broadcastTo", function() {
|
||||
assert.throws(
|
||||
() => new link.Event({ broadcastTo: "invalid" }),
|
||||
() => new libLink.Event({ broadcastTo: "invalid" }),
|
||||
new Error("Invalid broadcastTo value invalid")
|
||||
);
|
||||
});
|
||||
@@ -159,7 +159,7 @@ describe("lib/link/messages", function() {
|
||||
|
||||
describe("attachAllMessages()", function() {
|
||||
it("does not throw", function() {
|
||||
link.attachAllMessages(testSourceLink);
|
||||
libLink.attachAllMessages(testSourceLink);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const luaTools = require("@clusterio/lib/luaTools");
|
||||
|
||||
|
||||
describe("lib/luaTools", function() {
|
||||
describe("escapeString()", function() {
|
||||
it("should escape backslashes", function() {
|
||||
assert.equal(luaTools.escapeString("\\a"), "\\\\a");
|
||||
});
|
||||
it("should escape double quotes", function() {
|
||||
assert.equal(luaTools.escapeString('"a"'), '\\"a\\"');
|
||||
});
|
||||
it("should escape single quotes", function() {
|
||||
assert.equal(luaTools.escapeString("'a'"), "\\'a\\'");
|
||||
});
|
||||
it("should escape nul bytes", function() {
|
||||
assert.equal(luaTools.escapeString("a\0b"), "a\\0b");
|
||||
});
|
||||
it("should escape newlines", function() {
|
||||
assert.equal(luaTools.escapeString("a\nb"), "a\\nb");
|
||||
});
|
||||
it("should escape carriage return", function() {
|
||||
assert.equal(luaTools.escapeString("a\rb"), "a\\rb");
|
||||
});
|
||||
it("should escape all combined", function() {
|
||||
assert.equal(luaTools.escapeString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const libLuaTools = require("@clusterio/lib/lua_tools");
|
||||
|
||||
|
||||
describe("lib/lua_tools", function() {
|
||||
describe("escapeString()", function() {
|
||||
it("should escape backslashes", function() {
|
||||
assert.equal(libLuaTools.escapeString("\\a"), "\\\\a");
|
||||
});
|
||||
it("should escape double quotes", function() {
|
||||
assert.equal(libLuaTools.escapeString('"a"'), '\\"a\\"');
|
||||
});
|
||||
it("should escape single quotes", function() {
|
||||
assert.equal(libLuaTools.escapeString("'a'"), "\\'a\\'");
|
||||
});
|
||||
it("should escape nul bytes", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\0b"), "a\\0b");
|
||||
});
|
||||
it("should escape newlines", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\nb"), "a\\nb");
|
||||
});
|
||||
it("should escape carriage return", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\rb"), "a\\rb");
|
||||
});
|
||||
it("should escape all combined", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,13 @@
|
||||
"use strict";
|
||||
var assert = require("assert");
|
||||
var objectOps = require("@clusterio/lib/objectOps");
|
||||
var libObjectOps = require("@clusterio/lib/object_ops");
|
||||
|
||||
describe("objectOps.js", function(){
|
||||
describe("objectOps.deepclone()", function(){
|
||||
describe("lib/object_ops", function(){
|
||||
describe("deepclone()", function(){
|
||||
it("deep clones javascript objects", function(){
|
||||
var obj1 = { hello: "world", cat: { legs: 4, name: "Kitty", colors: ["brown", "yellow", "purple"] }};
|
||||
var obj2 = {};
|
||||
obj2 = objectOps.deepclone(obj1);
|
||||
obj2 = libObjectOps.deepclone(obj1);
|
||||
|
||||
obj1.cat.colors = "black";
|
||||
assert.equal(obj1.cat.colors, "black");
|
||||
@@ -15,7 +15,7 @@ describe("objectOps.js", function(){
|
||||
});
|
||||
it("throws on non JSON parameters", function(){
|
||||
assert.throws(function(){
|
||||
let y = objectOps.deepclone(objectOps.deepclone);
|
||||
let y = libObjectOps.deepclone(libObjectOps.deepclone);
|
||||
});
|
||||
});
|
||||
});
|
||||
+19
-18
@@ -4,16 +4,15 @@ const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const mock = require("../mock");
|
||||
const link = require("@clusterio/lib/link");
|
||||
const plugin = require("@clusterio/lib/plugin");
|
||||
const errors = require("@clusterio/lib/errors");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
|
||||
|
||||
describe("lib/plugin", function() {
|
||||
describe("class BaseInstancePlugin", function() {
|
||||
let instancePlugin;
|
||||
it("should be constructible", async function() {
|
||||
instancePlugin = new plugin.BaseInstancePlugin();
|
||||
instancePlugin = new libPlugin.BaseInstancePlugin();
|
||||
await instancePlugin.init();
|
||||
});
|
||||
it("should define defaults for hooks", async function() {
|
||||
@@ -30,7 +29,7 @@ describe("lib/plugin", function() {
|
||||
describe("class BaseMasterPlugin", function() {
|
||||
let masterPlugin;
|
||||
it("should be constructible", async function() {
|
||||
masterPlugin = new plugin.BaseMasterPlugin();
|
||||
masterPlugin = new libPlugin.BaseMasterPlugin();
|
||||
await masterPlugin.init();
|
||||
});
|
||||
it("should define defaults for hooks", async function() {
|
||||
@@ -68,50 +67,52 @@ describe("lib/plugin", function() {
|
||||
|
||||
it("should throw on missing plugin", async function() {
|
||||
await assert.rejects(
|
||||
plugin.loadPluginInfos(new Map([["missing", missingPlugin]]), []),
|
||||
libPlugin.loadPluginInfos(new Map([["missing", missingPlugin]]), []),
|
||||
new RegExp(`^Error: PluginError: Cannot find module '${missingPlugin}/info'`)
|
||||
);
|
||||
});
|
||||
it("should load test plugin", async function() {
|
||||
assert.deepEqual(
|
||||
await plugin.loadPluginInfos(new Map([["test", path.resolve(testPlugin)]])),
|
||||
await libPlugin.loadPluginInfos(new Map([["test", path.resolve(testPlugin)]])),
|
||||
[{ name: "test", version: "0.0.1", requirePath: path.resolve(testPlugin) }]
|
||||
);
|
||||
});
|
||||
it("should reject on broken plugin", async function() {
|
||||
await assert.rejects(
|
||||
plugin.loadPluginInfos(new Map([["broken", path.resolve(brokenPlugin)]])),
|
||||
libPlugin.loadPluginInfos(new Map([["broken", path.resolve(brokenPlugin)]])),
|
||||
{ message: "PluginError: Unexpected identifier" }
|
||||
);
|
||||
});
|
||||
it("should reject on invalid plugin", async function() {
|
||||
await assert.rejects(
|
||||
plugin.loadPluginInfos(new Map([["invalid", path.resolve(invalidPlugin)]])),
|
||||
libPlugin.loadPluginInfos(new Map([["invalid", path.resolve(invalidPlugin)]])),
|
||||
{ message: `Expected plugin at ${path.resolve(invalidPlugin)} to be named invalid but got wrong` }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("attachPluginMessages()", function() {
|
||||
let mockLink = new link.Link("source", "target", new mock.MockConnector());
|
||||
let mockEvent = new link.Event({ type: "test:test", links: ["target-source"] });
|
||||
let mockLink = new libLink.Link("source", "target", new mock.MockConnector());
|
||||
let mockEvent = new libLink.Event({ type: "test:test", links: ["target-source"] });
|
||||
it("should accept pluginInfo without messages", function() {
|
||||
plugin.attachPluginMessages(mockLink, {}, null);
|
||||
libPlugin.attachPluginMessages(mockLink, {}, null);
|
||||
});
|
||||
it("should attach handler for the given message", function() {
|
||||
function mockEventEventHandler() { };
|
||||
plugin.attachPluginMessages(mockLink, { name: "test", messages: { mockEvent }}, { mockEventEventHandler });
|
||||
libPlugin.attachPluginMessages(
|
||||
mockLink, { name: "test", messages: { mockEvent }}, { mockEventEventHandler }
|
||||
);
|
||||
assert(mockLink._handlers.get("test:test_event"), "handler was not registered");
|
||||
});
|
||||
it("should throw if missing handler for the given message", function() {
|
||||
assert.throws(
|
||||
() => plugin.attachPluginMessages(mockLink, { name: "test", messages: { mockEvent }}, {}),
|
||||
() => libPlugin.attachPluginMessages(mockLink, { name: "test", messages: { mockEvent }}, {}),
|
||||
new Error("Missing handler for test:test_event on source-target link")
|
||||
);
|
||||
});
|
||||
it("should throw if message starts with the wrong prefix", function() {
|
||||
assert.throws(
|
||||
() => plugin.attachPluginMessages(mockLink, { name: "foo", messages: { mockEvent }}, {}),
|
||||
() => libPlugin.attachPluginMessages(mockLink, { name: "foo", messages: { mockEvent }}, {}),
|
||||
new Error('Type of mockEvent message must start with "foo:"')
|
||||
);
|
||||
});
|
||||
@@ -132,15 +133,15 @@ describe("lib/plugin", function() {
|
||||
}],
|
||||
]);
|
||||
it("should invoke the hook on the plugin", async function() {
|
||||
await plugin.invokeHook(plugins, "test");
|
||||
await libPlugin.invokeHook(plugins, "test");
|
||||
assert(betaTestCalled, "Hook was not called");
|
||||
});
|
||||
it("should pass and return args", async function() {
|
||||
let result = await plugin.invokeHook(plugins, "pass", 1234);
|
||||
let result = await libPlugin.invokeHook(plugins, "pass", 1234);
|
||||
assert.deepEqual(result, [1234]);
|
||||
});
|
||||
it("should ignore errors", async function() {
|
||||
await plugin.invokeHook(plugins, "error");
|
||||
await libPlugin.invokeHook(plugins, "error");
|
||||
});
|
||||
});
|
||||
});
|
||||
+30
-28
@@ -1,34 +1,36 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
const users = require("@clusterio/lib/users");
|
||||
const libUsers = require("@clusterio/lib/users");
|
||||
|
||||
|
||||
describe("lib/users", function() {
|
||||
describe("definePermission()", function() {
|
||||
it("should validate the types of its arguments", function() {
|
||||
assert.throws(
|
||||
() => users.definePermission({ name: 123, title: "Test", description: "A test" }),
|
||||
() => libUsers.definePermission({ name: 123, title: "Test", description: "A test" }),
|
||||
new Error("Expected name to be a non-empty string")
|
||||
);
|
||||
assert.throws(
|
||||
() => users.definePermission({ name: "test", title: 123, description: "A test" }),
|
||||
() => libUsers.definePermission({ name: "test", title: 123, description: "A test" }),
|
||||
new Error("Expected title to be a non-empty string")
|
||||
);
|
||||
assert.throws(
|
||||
() => users.definePermission({ name: "test", title: "Test", description: 123 }),
|
||||
() => libUsers.definePermission({ name: "test", title: "Test", description: 123 }),
|
||||
new Error("Expected description to be a non-empty string")
|
||||
);
|
||||
assert.throws(
|
||||
() => users.definePermission({ name: "test", title: "Test", description: "A test", grantByDefault: 1 }),
|
||||
() => libUsers.definePermission({
|
||||
name: "test", title: "Test", description: "A test", grantByDefault: 1,
|
||||
}),
|
||||
new Error("Expected grantByDefault to be a boolean")
|
||||
);
|
||||
});
|
||||
|
||||
it("should define a permission", function() {
|
||||
users.definePermission({ name: "test", title: "Test", description: "A test" });
|
||||
assert(users.permissions.has("test"), "Permission was not defined");
|
||||
libUsers.definePermission({ name: "test", title: "Test", description: "A test" });
|
||||
assert(libUsers.permissions.has("test"), "Permission was not defined");
|
||||
|
||||
let test = users.permissions.get("test");
|
||||
let test = libUsers.permissions.get("test");
|
||||
assert.equal(test.name, "test");
|
||||
assert.equal(test.title, "Test");
|
||||
assert.equal(test.description, "A test");
|
||||
@@ -37,7 +39,7 @@ describe("lib/users", function() {
|
||||
|
||||
it("should throw on already defined permission", function() {
|
||||
assert.throws(
|
||||
() => users.definePermission({ name: "test", title: "Test", description: "A test" }),
|
||||
() => libUsers.definePermission({ name: "test", title: "Test", description: "A test" }),
|
||||
new Error("Permission 'test' is already defined")
|
||||
);
|
||||
});
|
||||
@@ -45,19 +47,19 @@ describe("lib/users", function() {
|
||||
|
||||
describe("class Role", function() {
|
||||
it("should round trip serialize", function() {
|
||||
let orig = new users.Role({ id: 11, name: "Role", description: "My Role", permissions: ["test"] });
|
||||
let copy = new users.Role(orig.serialize());
|
||||
let orig = new libUsers.Role({ id: 11, name: "Role", description: "My Role", permissions: ["test"] });
|
||||
let copy = new libUsers.Role(orig.serialize());
|
||||
assert.deepEqual(copy, orig);
|
||||
});
|
||||
|
||||
describe(".grantDefaultRoles()", function() {
|
||||
it("should only grant permissions with grantByDefault", function() {
|
||||
let role = new users.Role({ id: 11, name: "Role", description: "My Role" });
|
||||
let role = new libUsers.Role({ id: 11, name: "Role", description: "My Role" });
|
||||
role.grantDefaultPermissions();
|
||||
assert(role.permissions.size > 0, "No permissions were granted");
|
||||
for (let permission of role.permissions) {
|
||||
assert(
|
||||
users.permissions.get(permission).grantByDefault === true,
|
||||
libUsers.permissions.get(permission).grantByDefault === true,
|
||||
"Non-default permission granted"
|
||||
);
|
||||
}
|
||||
@@ -67,15 +69,15 @@ describe("lib/users", function() {
|
||||
|
||||
describe("class User", function() {
|
||||
let roles = new Map([
|
||||
[1, new users.Role({ id: 1, name: "a", description: "a role", permissions: ["core.admin"] })],
|
||||
[2, new users.Role({ id: 2, name: "b", description: "b role", permissions: ["test"] })],
|
||||
[1, new libUsers.Role({ id: 1, name: "a", description: "a role", permissions: ["core.admin"] })],
|
||||
[2, new libUsers.Role({ id: 2, name: "b", description: "b role", permissions: ["test"] })],
|
||||
]);
|
||||
it("should round trip serialize", function() {
|
||||
function test_roundtrip(serialized) {
|
||||
let user = new users.User(serialized, roles);
|
||||
let user = new libUsers.User(serialized, roles);
|
||||
let user_serialized = user.serialize();
|
||||
assert.deepEqual(user_serialized, serialized);
|
||||
let user_deserialized = new users.User(user_serialized, roles);
|
||||
let user_deserialized = new libUsers.User(user_serialized, roles);
|
||||
assert.deepEqual(user_deserialized, user);
|
||||
}
|
||||
|
||||
@@ -85,40 +87,40 @@ describe("lib/users", function() {
|
||||
test_roundtrip({ name: "user", is_banned: true, ban_reason: "Bad user" });
|
||||
});
|
||||
it("should ignore invalid roles", function() {
|
||||
let user = new users.User({ name: "test", roles: [1, 4, 55] }, roles);
|
||||
let user = new libUsers.User({ name: "test", roles: [1, 4, 55] }, roles);
|
||||
assert.equal(user.roles.size, 1, "Unexpected count of roles");
|
||||
});
|
||||
it("should track online users", function() {
|
||||
let user = new users.User({ name: "admin", roles: [1] }, roles);
|
||||
assert(!users.User.onlineUsers.has(user));
|
||||
let user = new libUsers.User({ name: "admin", roles: [1] }, roles);
|
||||
assert(!libUsers.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set());
|
||||
|
||||
user.notifyJoin(12);
|
||||
assert(users.User.onlineUsers.has(user));
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([12]));
|
||||
|
||||
user.notifyJoin(8);
|
||||
assert(users.User.onlineUsers.has(user));
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([12, 8]));
|
||||
|
||||
user.notifyLeave(11);
|
||||
assert(users.User.onlineUsers.has(user));
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([12, 8]));
|
||||
|
||||
user.notifyLeave(12);
|
||||
assert(users.User.onlineUsers.has(user));
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([8]));
|
||||
|
||||
user.notifyLeave(8);
|
||||
assert(!users.User.onlineUsers.has(user));
|
||||
assert(!libUsers.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set());
|
||||
});
|
||||
|
||||
describe(".checkPermission()", function() {
|
||||
it("should correctly resolve permissions", function() {
|
||||
let a = new users.User({ name: "admin", roles: [1] }, roles);
|
||||
let b = new users.User({ name: "user", roles: [2] }, roles);
|
||||
let c = new users.User({ name: "null", roles: [] }, roles);
|
||||
let a = new libUsers.User({ name: "admin", roles: [1] }, roles);
|
||||
let b = new libUsers.User({ name: "user", roles: [2] }, roles);
|
||||
let c = new libUsers.User({ name: "null", roles: [] }, roles);
|
||||
|
||||
a.checkPermission("core.control.connect");
|
||||
assert.throws(() => b.checkPermission("core.control.connect"), new Error("Permission denied"));
|
||||
|
||||
@@ -3,9 +3,9 @@ const assert = require("assert");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const generateSSLcert = require("@clusterio/master/src/generate_ssl_cert");
|
||||
const generateSslCert = require("@clusterio/master/src/generate_ssl_cert");
|
||||
|
||||
describe("generateSSLcert.js(options)", function() {
|
||||
describe("generate_ssl_cert", function() {
|
||||
let testDir = path.join("temp", "test", "certTest");
|
||||
before(async function() {
|
||||
await fs.remove(testDir);
|
||||
@@ -21,7 +21,7 @@ describe("generateSSLcert.js(options)", function() {
|
||||
let certPath = path.join(testDir, "cert.crt");
|
||||
let privKeyPath = path.join(testDir, "cert.key");
|
||||
|
||||
await generateSSLcert({
|
||||
await generateSslCert({
|
||||
bits: 512, // This is too small for real world usage, but faster to test
|
||||
sslCertPath: certPath,
|
||||
sslPrivKeyPath: privKeyPath,
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
const events = require("events");
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
|
||||
|
||||
class MockSocket {
|
||||
@@ -77,7 +77,7 @@ class MockServer {
|
||||
}
|
||||
}
|
||||
|
||||
class MockInstance extends link.Link {
|
||||
class MockInstance extends libLink.Link {
|
||||
constructor() {
|
||||
super("instance", "slave", new MockConnector());
|
||||
this.server = new MockServer();
|
||||
@@ -92,13 +92,13 @@ class MockInstance extends link.Link {
|
||||
}
|
||||
}
|
||||
|
||||
class MockSlave extends link.Link {
|
||||
class MockSlave extends libLink.Link {
|
||||
constructor() {
|
||||
super("slave", "master", new MockConnector());
|
||||
}
|
||||
}
|
||||
|
||||
class MockControl extends link.Link {
|
||||
class MockControl extends libLink.Link {
|
||||
constructor(connector) {
|
||||
super("control", "master", connector);
|
||||
}
|
||||
|
||||
+8
-8
@@ -3,22 +3,22 @@ const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
const fs = require("fs-extra");
|
||||
|
||||
const link = require("@clusterio/lib/link");
|
||||
const config = require("@clusterio/lib/config");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
const slave = require("@clusterio/slave/slave");
|
||||
|
||||
describe("Slave testing", function() {
|
||||
before(function() {
|
||||
config.InstanceConfig.finalize();
|
||||
libConfig.InstanceConfig.finalize();
|
||||
});
|
||||
|
||||
describe("class Instance", function() {
|
||||
let instance;
|
||||
before(async function() {
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.init();
|
||||
instanceConfig.set("instance.name", "foo");
|
||||
instance = new slave._Instance({}, new link.VirtualConnector(), "dir", "factorioDir", instanceConfig);
|
||||
instance = new slave._Instance({}, new libLink.VirtualConnector(), "dir", "factorioDir", instanceConfig);
|
||||
});
|
||||
|
||||
describe(".name", function() {
|
||||
@@ -106,11 +106,11 @@ describe("Slave testing", function() {
|
||||
await fs.outputFile(path.join(testDir, "shared", "mod_b.zip"), "b");
|
||||
await fs.outputFile(path.join(testDir, "shared", "mod.dat"), "c");
|
||||
|
||||
let instanceConfig = new config.InstanceConfig();
|
||||
let instanceConfig = new libConfig.InstanceConfig();
|
||||
await instanceConfig.init();
|
||||
instanceConfig.set("instance.name", "test");
|
||||
instance = new slave._Instance(
|
||||
{}, new link.VirtualConnector(), path.join(testDir, "instance"), "factorioDir", instanceConfig
|
||||
{}, new libLink.VirtualConnector(), path.join(testDir, "instance"), "factorioDir", instanceConfig
|
||||
);
|
||||
await fs.outputFile(instance.path("mods", "mod_i.zip"), "i");
|
||||
});
|
||||
@@ -161,7 +161,7 @@ describe("Slave testing", function() {
|
||||
let instanceInfos = new Map();
|
||||
await slave._discoverInstances(instanceInfos, instancePath, logger);
|
||||
|
||||
let referenceConfig = new config.InstanceConfig();
|
||||
let referenceConfig = new libConfig.InstanceConfig();
|
||||
await referenceConfig.init();
|
||||
referenceConfig.set("instance.id", 1);
|
||||
referenceConfig.set("instance.name", "test");
|
||||
|
||||
Reference in new issue
Block a user