mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
Replace bootstrap methods with async factories
Controller.bootstrap and Host.bootstrap returned constructor arguments that the caller had to spread into new Controller/Host, and DatastoreProvider.bootstrap did the same for datastores. They are replaced by Controller.fromConfig, Host.fromConfig and KeyValueDatastore/SubscribableDatastore.fromProvider, which load the data and return the finished instance. Closes #1126 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c3abf27266
commit
d7fc3aaec4
8 files changed
+133
-57
No files matched your search
@@ -147,15 +147,15 @@ async function handleBootstrapCommand(
|
||||
path.join(databaseDirectory, "roles.json"),
|
||||
);
|
||||
|
||||
const roles = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const roles = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "roles.json"),
|
||||
lib.Role.fromJSON.bind(lib.Role),
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const users = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const users = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "users.json"),
|
||||
UserRecord.fromJSON.bind(UserRecord),
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const userManager = new UserManager(users, roles, controllerConfig);
|
||||
|
||||
@@ -474,13 +474,12 @@ async function startup() {
|
||||
return;
|
||||
}
|
||||
|
||||
controller = new Controller(
|
||||
controller = await Controller.fromConfig(
|
||||
clusterLogger,
|
||||
pluginInfos,
|
||||
controllerConfig,
|
||||
Boolean(args.canRestart),
|
||||
Boolean(args.recovery),
|
||||
...await Controller.bootstrap(controllerConfig)
|
||||
);
|
||||
|
||||
// Refuse to start if there are no users loaded
|
||||
|
||||
@@ -148,7 +148,14 @@ export default class Controller {
|
||||
}
|
||||
});
|
||||
|
||||
static async bootstrap(config: lib.ControllerConfig) {
|
||||
/** Create a controller with its datastores and mod store loaded from disk */
|
||||
static async fromConfig(
|
||||
clusterLogger: winston.Logger,
|
||||
pluginInfos: lib.PluginNodeEnvInfo[],
|
||||
config: lib.ControllerConfig,
|
||||
canRestart = false,
|
||||
recoveryMode = false,
|
||||
) {
|
||||
let databaseDirectory = config.get("controller.database_directory");
|
||||
await fs.mkdir(databaseDirectory, { recursive: true });
|
||||
|
||||
@@ -158,23 +165,23 @@ export default class Controller {
|
||||
path.join(databaseDirectory, "roles.json"),
|
||||
);
|
||||
|
||||
const systems = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const systems = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "systems.json"),
|
||||
lib.SystemInfo.fromJSON.bind(lib.SystemInfo),
|
||||
this.migrateSystems,
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const hosts = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const hosts = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "hosts.json"),
|
||||
HostRecord.fromJSON.bind(HostRecord),
|
||||
this.migrateHosts, this.finaliseHosts,
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const instances = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const instances = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "instances.json"),
|
||||
InstanceRecord.fromJSON.bind(InstanceRecord),
|
||||
this.migrateInstances, this.finaliseInstances,
|
||||
).bootstrap());
|
||||
));
|
||||
// Save plugin versions written while loading
|
||||
for (const instance of instances.values()) {
|
||||
if (instance.config.dirty) {
|
||||
@@ -182,33 +189,33 @@ export default class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
const saves = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const saves = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "saves.json"),
|
||||
lib.SaveDetails.fromJSON.bind(lib.SaveDetails)
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const modPacks = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const modPacks = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "mod-packs.json"),
|
||||
lib.ModPack.fromJSON.bind(lib.ModPack),
|
||||
this.migrateModPacks,
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const roles = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const roles = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "roles.json"),
|
||||
lib.Role.fromJSON.bind(lib.Role),
|
||||
this.migrateRoles,
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const users = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const users = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "users.json"),
|
||||
UserRecord.fromJSON.bind(UserRecord),
|
||||
undefined, this.finaliseUsers,
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
const notes = new lib.SubscribableDatastore(...await new lib.JsonIdDatastoreProvider(
|
||||
const notes = await lib.SubscribableDatastore.fromProvider(new lib.JsonIdDatastoreProvider(
|
||||
path.join(databaseDirectory, "notes.json"),
|
||||
lib.Note.fromJSON.bind(lib.Note),
|
||||
).bootstrap());
|
||||
));
|
||||
|
||||
let modsDirectory = config.get("controller.mods_directory");
|
||||
await fs.mkdir(modsDirectory, { recursive: true });
|
||||
@@ -223,7 +230,12 @@ export default class Controller {
|
||||
lib.Role.ensureDefaultAdminRole(roles);
|
||||
lib.Role.ensureDefaultPlayerRole(roles);
|
||||
|
||||
return [
|
||||
return new this(
|
||||
clusterLogger,
|
||||
pluginInfos,
|
||||
config,
|
||||
canRestart,
|
||||
recoveryMode,
|
||||
systems,
|
||||
hosts,
|
||||
instances,
|
||||
@@ -233,7 +245,7 @@ export default class Controller {
|
||||
roles,
|
||||
users,
|
||||
notes,
|
||||
] as const;
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -233,13 +233,12 @@ async function startHost() {
|
||||
}
|
||||
|
||||
let hostConnector = new HostConnector(hostConfig, pluginInfos);
|
||||
host = new Host(
|
||||
host = await Host.fromConfig(
|
||||
hostConnector,
|
||||
hostConfig,
|
||||
pluginInfos,
|
||||
Boolean(args.canRestart),
|
||||
Boolean(args.recovery),
|
||||
...await Host.bootstrap(hostConfig)
|
||||
);
|
||||
|
||||
// Handle interrupts
|
||||
|
||||
@@ -329,12 +329,18 @@ export default class Host extends lib.Link {
|
||||
"_warning": "Changes to this file will be overwritten by the controller's copy.",
|
||||
};
|
||||
|
||||
static async bootstrap(hostConfig: lib.HostConfig) {
|
||||
/** Create a host with its mod store loaded from disk */
|
||||
static async fromConfig(
|
||||
connector: HostConnector,
|
||||
hostConfig: lib.HostConfig,
|
||||
pluginInfos: lib.PluginNodeEnvInfo[],
|
||||
canRestart = false,
|
||||
recoveryMode = false,
|
||||
) {
|
||||
const modsDirectory = hostConfig.get("host.mods_directory");
|
||||
await fs.mkdir(modsDirectory, { recursive: true });
|
||||
return [
|
||||
await lib.ModStore.fromDirectory(modsDirectory),
|
||||
] as const;
|
||||
const modStore = await lib.ModStore.fromDirectory(modsDirectory);
|
||||
return new this(connector, hostConfig, pluginInfos, canRestart, recoveryMode, modStore);
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -17,11 +17,6 @@ export abstract class DatastoreProvider<
|
||||
> {
|
||||
abstract save(data: Map<K, V>): Promise<void>
|
||||
abstract load(): Promise<Map<K, V>>
|
||||
|
||||
// Load data from the source and return it, this should be passed to the constructor of a datastore
|
||||
async bootstrap() {
|
||||
return [this, await this.load()] as const;
|
||||
}
|
||||
}
|
||||
|
||||
// Store all data in memory, used as a default and should be avoided
|
||||
@@ -251,6 +246,11 @@ export class KeyValueDatastore<
|
||||
K extends DatastoreKey,
|
||||
V extends DatastoreValue,
|
||||
> extends Datastore<K, V, [key: K, value: V, isDeleted?: boolean]> {
|
||||
// Create a datastore populated with the data loaded from the provider
|
||||
static async fromProvider<K extends DatastoreKey, V extends DatastoreValue>(provider: DatastoreProvider<K, V>) {
|
||||
return new this(provider, await provider.load());
|
||||
}
|
||||
|
||||
// Set the value in the datastore, be careful of race conditions if you await any functions before calling set
|
||||
set(key: K, value: V) {
|
||||
this.data.set(key, value);
|
||||
@@ -316,6 +316,11 @@ export class SubscribableDatastore<
|
||||
this.lastUpdatedAtMs = SubscribableDatastore.maxUpdatedAtMs(this.data.values());
|
||||
}
|
||||
|
||||
// Create a datastore populated with the data loaded from the provider
|
||||
static async fromProvider<V extends SubscribableValue>(provider: DatastoreProvider<V["id"], V>) {
|
||||
return new this(provider, await provider.load());
|
||||
}
|
||||
|
||||
async load() {
|
||||
await super.load();
|
||||
this.lastUpdatedAtMs = SubscribableDatastore.maxUpdatedAtMs(this.data.values());
|
||||
|
||||
Reference in new issue
Block a user