From f12a9926eb34e58edca71dd3b0b6bf6e7d979329 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Fri, 8 Dec 2023 18:05:24 +0100 Subject: [PATCH] Add isDeleted and updatedAt to subscribable types Prepare for subscriptinos being able to be cached and resumed by adding updatedAt and isDeleted fields to the subscribable types. --- packages/controller/src/Controller.ts | 6 +++++- packages/controller/src/ControllerUser.ts | 1 + packages/lib/src/ModStore.ts | 1 + packages/lib/src/data/ModInfo.ts | 10 ++++++++- packages/lib/src/data/ModPack.ts | 9 ++++++++ packages/lib/src/data/User.ts | 8 ++++++++ packages/lib/src/data/messages_host.ts | 7 +++++++ packages/lib/src/data/messages_instance.ts | 24 ++++++++++++++++++++-- test/integration/clusterio.js | 2 ++ test/lib/data/ModInfo.js | 1 + 10 files changed, 65 insertions(+), 4 deletions(-) diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index be26d4b0..8b1a466e 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -735,7 +735,7 @@ export default class Controller { // Assign to target instance.config.set("instance.assigned_host", hostId); - this.instancesDirty = true; + // "fieldChanged" event handler will set this.instancesDirty if (hostId !== undefined && newHostConnection) { await newHostConnection.send( new lib.InstanceAssignInternalRequest(instanceId, instance.config.serialize("host")) @@ -819,6 +819,7 @@ export default class Controller { assigned_host, game_port, instance.status, + Date.now(), ) )); } @@ -828,17 +829,20 @@ export default class Controller { } modPackUpdated(modPack: lib.ModPack) { + modPack.updatedAt = Date.now(); this.modPacksDirty = true; this.subscriptions.broadcast(new lib.ModPackUpdateEvent(modPack)); lib.invokeHook(this.plugins, "onModPackUpdated", modPack); } modUpdated(mod: lib.ModInfo) { + // ModStore sets updatedAt for mods this.subscriptions.broadcast(new lib.ModUpdateEvent(mod)); lib.invokeHook(this.plugins, "onModUpdated", mod); } userUpdated(user: ControllerUser) { + user.updatedAt = Date.now(); this.userManager.dirty = true; this.subscriptions.broadcast(new lib.UserUpdateEvent(user)); } diff --git a/packages/controller/src/ControllerUser.ts b/packages/controller/src/ControllerUser.ts index 7c79dfb7..5af3b1c2 100644 --- a/packages/controller/src/ControllerUser.ts +++ b/packages/controller/src/ControllerUser.ts @@ -35,6 +35,7 @@ export default class ControllerUser extends User implements IControllerUser { json.is_banned, json.is_whitelisted, json.ban_reason, + json.updated_at, json.is_deleted, playerStats, instanceStats, diff --git a/packages/lib/src/ModStore.ts b/packages/lib/src/ModStore.ts index 54eda548..83cb0167 100644 --- a/packages/lib/src/ModStore.ts +++ b/packages/lib/src/ModStore.ts @@ -66,6 +66,7 @@ export default class ModStore extends TypedEventEmitter) { @@ -32,6 +37,8 @@ export class HostDetails { json.connected, json.publicAddress, json.tokenValidAfter, + json.updatedAt, + json.isDeleted, ); } } diff --git a/packages/lib/src/data/messages_instance.ts b/packages/lib/src/data/messages_instance.ts index c8989954..19e29ef6 100644 --- a/packages/lib/src/data/messages_instance.ts +++ b/packages/lib/src/data/messages_instance.ts @@ -18,6 +18,8 @@ export class InstanceDetails { public assignedHost: number | undefined, public gamePort: number | undefined, public status: InstanceStatus, + /** Millisecond Unix timestamp this entry was last updated at */ + public updatedAt = 0, ) { } static jsonSchema = Type.Object({ @@ -29,10 +31,22 @@ export class InstanceDetails { "unknown", "unassigned", "stopped", "starting", "running", "stopping", "creating_save", "exporting_data", "deleted", ]), + "updatedAt": Type.Optional(Type.Number()), }); static fromJSON(json: Static) { - return new this(json.name, json.id, json.assignedHost, json.gamePort, json.status); + return new this( + json.name, + json.id, + json.assignedHost, + json.gamePort, + json.status, + json.updatedAt, + ); + } + + get isDeleted() { + return this.status === "deleted"; } } @@ -288,15 +302,21 @@ export class InstanceSaveListUpdateEvent { constructor( public instanceId: number, public saves: SaveDetails[], + public updatedAt = Date.now(), ) { } + get isDeleted() { + return false; + } + static jsonSchema = Type.Object({ "instanceId": Type.Integer(), "saves": Type.Array(SaveDetails.jsonSchema), + "updatedAt": Type.Number(), }); static fromJSON(json: Static) { - return new this(json.instanceId, json.saves.map(i => SaveDetails.fromJSON(i))); + return new this(json.instanceId, json.saves.map(i => SaveDetails.fromJSON(i)), json.updatedAt); } } diff --git a/test/integration/clusterio.js b/test/integration/clusterio.js index b9931847..f074ef13 100644 --- a/test/integration/clusterio.js +++ b/test/integration/clusterio.js @@ -885,6 +885,7 @@ describe("Integration of Clusterio", function() { reference.settings["runtime-global"].set("MyInt", { value: 1235 }); reference.settings["runtime-global"].set("MyDouble", { value: 12.25 }); reference.settings["runtime-per-user"].set("MyString", { value: "a-string" }); + reference.updatedAt = modPack.updatedAt; assert.deepEqual(modPack, reference); }); }); @@ -989,6 +990,7 @@ describe("Integration of Clusterio", function() { "dependencies:\n" + `size: ${stat.size}\n` + `sha1: ${hash}\n` + + `updatedAt: ${stat.mtimeMs}\n` + "isDeleted: false\n", ); }); diff --git a/test/lib/data/ModInfo.js b/test/lib/data/ModInfo.js index 279f535f..8e0cb640 100644 --- a/test/lib/data/ModInfo.js +++ b/test/lib/data/ModInfo.js @@ -92,6 +92,7 @@ describe("lib/data/ModInfo", function() { dependencies: [], filename: "empty_mod_1.0.0.zip", size: stat.size, + updated_at: stat.mtimeMs, sha1: hash, }) );