import type { SaveSlotList, SaveSlotMeta } from "@rpgjs/common"; import { inject } from "../core/inject"; import { AbstractWebsocket, WebSocketToken } from "./AbstractSocket"; export const SaveClientToken = "SaveClientToken"; type SaveListResult = { requestId: string; slots: SaveSlotList; }; type SaveSaveResult = { requestId: string; index: number; slots: SaveSlotList; }; type SaveLoadResult = { requestId: string; index: number; ok: boolean; slot?: SaveSlotMeta; }; type SaveErrorResult = { requestId: string; message: string; }; type PendingRequest = { resolve: (value: any) => void; reject: (error: Error) => void; }; export class SaveClientService { private webSocket: AbstractWebsocket = inject(WebSocketToken); private pending: Map = new Map(); private requestCounter = 0; initialize() { const saveListResult = (data: SaveListResult) => this.resolveRequest(data.requestId, data); const saveSaveResult = (data: SaveSaveResult) => this.resolveRequest(data.requestId, data); const saveLoadResult = (data: SaveLoadResult) => this.resolveRequest(data.requestId, data); const saveErrorResult = (data: SaveErrorResult) => this.rejectRequest(data.requestId, data.message); this.webSocket.off("save.list.result", saveListResult); this.webSocket.off("save.save.result", saveSaveResult); this.webSocket.off("save.load.result", saveLoadResult); this.webSocket.off("save.error", saveErrorResult); this.webSocket.on("save.list.result", saveListResult); this.webSocket.on("save.save.result", saveSaveResult); this.webSocket.on("save.load.result", saveLoadResult); this.webSocket.on("save.error", saveErrorResult); } listSlots(): Promise { return this.request("save.list", {}).then((result) => result.slots); } saveSlot(index: number, meta: SaveSlotMeta = {}): Promise { return this.request("save.save", { index, meta }).then((result) => result.slots); } loadSlot(index: number): Promise { return this.request("save.load", { index }).then((result) => result.ok); } private request(event: string, payload: Record): Promise { return new Promise((resolve, reject) => { if (!this.webSocket) { this.initialize(); } const requestId = this.nextRequestId(); this.pending.set(requestId, { resolve, reject }); this.webSocket?.emit(event, { requestId, ...payload }); }); } private resolveRequest(requestId: string, result: any) { const pending = this.pending.get(requestId); if (!pending) return; this.pending.delete(requestId); pending.resolve(result); } private rejectRequest(requestId: string, message: string) { const pending = this.pending.get(requestId); if (!pending) return; this.pending.delete(requestId); pending.reject(new Error(message)); } private nextRequestId(): string { this.requestCounter += 1; return `${Date.now()}-${this.requestCounter}`; } } export function provideSaveClient() { return { provide: SaveClientService, useClass: SaveClientService, }; }