perf: offload FurnitureData translation build to a worker thread
The translation build's CPU-heavy work (deep clone of the 100k+ entry master, the two full scans and JSON.stringify per language) now runs in a worker thread, so "Alles vertalen" no longer blocks the main event loop. Network/DB parts (official Habbo fetch, LibreTranslate, file writes) stay on the main thread. The pure helpers were extracted to furni-data-i18n-core (no server-only deps) so the worker can import them. Falls back to the same helpers on the main thread when no worker is available or in tests.
This commit is contained in:
1 parent
8d1b09f151
commit
f94246e067
4 files changed
+451
-124
No files matched your search
@@ -0,0 +1,76 @@
|
||||
import { parentPort } from "node:worker_threads";
|
||||
import type { HabboGamedataHotel } from "@/lib/habbo-gamedata-hotel";
|
||||
import {
|
||||
type FurniDataMaster,
|
||||
finalizeLangFile,
|
||||
type PreparedLang,
|
||||
prepareLangFile,
|
||||
type Translation,
|
||||
} from "./furni-data-i18n-core";
|
||||
|
||||
interface InitMsg {
|
||||
id: number;
|
||||
type: "init";
|
||||
masterJson: string;
|
||||
hotelMaps: Record<string, Map<string, Translation>>;
|
||||
}
|
||||
interface PrepareMsg {
|
||||
id: number;
|
||||
type: "prepare";
|
||||
lang: string;
|
||||
hotel: string;
|
||||
}
|
||||
interface FinalizeMsg {
|
||||
id: number;
|
||||
type: "finalize";
|
||||
lang: string;
|
||||
translations: Map<string, string>;
|
||||
}
|
||||
type Msg = InitMsg | PrepareMsg | FinalizeMsg;
|
||||
|
||||
let master: FurniDataMaster | null = null;
|
||||
let hotelMaps: Record<string, Map<string, Translation>> = {};
|
||||
const prepared = new Map<string, PreparedLang>();
|
||||
|
||||
if (parentPort) {
|
||||
parentPort.on("message", (msg: Msg) => {
|
||||
try {
|
||||
if (msg.type === "init") {
|
||||
master = JSON.parse(msg.masterJson);
|
||||
hotelMaps = msg.hotelMaps ?? {};
|
||||
parentPort!.postMessage({ id: msg.id, ok: true });
|
||||
return;
|
||||
}
|
||||
if (msg.type === "prepare") {
|
||||
if (!master) throw new Error("translation worker not initialized");
|
||||
const officialMap =
|
||||
hotelMaps[msg.hotel] ?? new Map<string, Translation>();
|
||||
const r = prepareLangFile(
|
||||
master,
|
||||
msg.lang,
|
||||
msg.hotel as HabboGamedataHotel,
|
||||
officialMap,
|
||||
);
|
||||
prepared.set(msg.lang, r);
|
||||
parentPort!.postMessage({
|
||||
id: msg.id,
|
||||
ok: true,
|
||||
pendingTexts: r.pendingTexts,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// finalize
|
||||
const r = prepared.get(msg.lang);
|
||||
if (!r) throw new Error(`no prepared data for ${msg.lang}`);
|
||||
const res = finalizeLangFile(r.cloned, r.pendingRefs, msg.translations);
|
||||
prepared.delete(msg.lang);
|
||||
parentPort!.postMessage({ id: msg.id, ok: true, ...res });
|
||||
} catch (err) {
|
||||
parentPort!.postMessage({
|
||||
id: msg.id,
|
||||
ok: false,
|
||||
error: (err as Error).message,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user