From 699ef2c3cb27e8f32c39238cc1e150eddf069dc1 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sat, 6 Jan 2024 18:52:41 +0100 Subject: [PATCH] Separate updatedAt from mtime in SaveDetails If a new save is added to the saves list of an instance the current save selected to be loaded by default changes its state without updating the mtime of the file on disk, which in turn means basing the updatedAt property on mtime will not work with caching. Fix by having a separate updatedAt property that is set by the controller whenever the save details changes from the controller's perspective. Noticed-By: @Cooldude2606 --- packages/controller/src/HostConnection.ts | 3 +++ packages/host/src/Instance.ts | 1 + packages/lib/src/data/messages_instance.ts | 12 ++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/controller/src/HostConnection.ts b/packages/controller/src/HostConnection.ts index 72185d37..164f3e82 100644 --- a/packages/controller/src/HostConnection.ts +++ b/packages/controller/src/HostConnection.ts @@ -269,12 +269,14 @@ export default class HostConnection extends BaseConnection { } async handleInstanceSaveDetailsUpdatesEvent(event: lib.InstanceSaveDetailsUpdatesEvent) { + const now = Date.now(); const updates: lib.SaveDetails[] = []; for (const save of event.updates) { const existingSave = this._controller.saves.get(save.id); if (existingSave && save.equals(existingSave)) { continue; } + save.updatedAt = now; this._controller.saves.set(save.id, save); updates.push(save); } @@ -283,6 +285,7 @@ export default class HostConnection extends BaseConnection { for (const [id, save] of this._controller.saves) { if (save.instanceId === event.instanceId && !updatedSaves.has(id)) { save.isDeleted = true; + save.updatedAt = now; updates.push(save); this._controller.saves.delete(id); } diff --git a/packages/host/src/Instance.ts b/packages/host/src/Instance.ts index c49b3035..22c43cf7 100644 --- a/packages/host/src/Instance.ts +++ b/packages/host/src/Instance.ts @@ -402,6 +402,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " "); stat.mtimeMs, name === loadedSave, name === defaultSave, + 0, // Set by controller false, )); } diff --git a/packages/lib/src/data/messages_instance.ts b/packages/lib/src/data/messages_instance.ts index 17a27adf..dbc32be1 100644 --- a/packages/lib/src/data/messages_instance.ts +++ b/packages/lib/src/data/messages_instance.ts @@ -290,6 +290,8 @@ export class SaveDetails { public mtimeMs: number, public loaded: boolean, public loadByDefault: boolean, + /** Millisecond Unix timestamp this entry was last updated at */ + public updatedAt: number, public isDeleted: boolean, ) { } @@ -301,6 +303,7 @@ export class SaveDetails { "mtimeMs": Type.Number(), "loaded": Type.Boolean(), "loadByDefault": Type.Boolean(), + "updatedAt": Type.Number(), "isDeleted": Type.Boolean(), }); @@ -313,6 +316,7 @@ export class SaveDetails { json.mtimeMs, json.loaded, json.loadByDefault, + json.updatedAt, json.isDeleted, ); } @@ -322,16 +326,16 @@ export class SaveDetails { return `${this.instanceId}/${this.name}`; } - get updatedAt() { - return this.mtimeMs; - } - /** * Compare this save with another save. * @param other - save to compare with. * @returns true if this save is identical to the provided save */ equals(other: SaveDetails) { + // Note that updatedAt is not included in the equality check because + // instances send the whole list of saves with updatedAt set to zero + // to the controller whenever any save changes and this equals check + // is used to filter whether a save was updated. return ( this.instanceId === other.instanceId && this.type === other.type