feat: parallelize audit repair and add nitro/SQL repair options
- Parallelize icon and nitro downloads in the audit repair with a sliding-window worker pool (6 concurrent) to speed up large catalogs - Add repairMissingNitros: fetch missing .nitro bundles from configured nitro sources (Wibbo default), validating each bundle before writing - Add catalog-repair service: generate/apply catalog_items SQL for furni missing a catalog entry and repair FurnitureData.json (add missing + dedupe classnames) - Wire all options through the audit API and client UI with live progress and result stats (icons, nitros, SQL, furnidata) - Add Wibbo as default nitro source alongside existing icon sources - Ignore runtime furni assets downloaded into public/ during repair
This commit is contained in:
1 parent
0c8e62357f
commit
5308ce6a12
8 files changed
+1129
-21
No files matched your search
@@ -24,5 +24,10 @@ gitea
|
|||||||
# Runtime uploaded media (persistent, outside public/)
|
# Runtime uploaded media (persistent, outside public/)
|
||||||
storage/
|
storage/
|
||||||
|
|
||||||
|
# Runtime downloaded furni assets (mirrored from gamedata / audit repair)
|
||||||
|
public/nitro-assets/bundled/furniture/
|
||||||
|
public/swf/dcr/
|
||||||
|
public/tmp/
|
||||||
|
|
||||||
# Test coverage reports
|
# Test coverage reports
|
||||||
coverage/
|
coverage/
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -6,9 +6,33 @@ function sseEvent(data: unknown): string {
|
|||||||
return `data: ${JSON.stringify(data)}\n\n`;
|
return `data: ${JSON.stringify(data)}\n\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => {
|
export const POST = withAdmin(
|
||||||
|
{ permission: PERMS.ASSETS_IMPORT },
|
||||||
|
async (request) => {
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
let repair = false;
|
||||||
|
let repairNitros = false;
|
||||||
|
let sql = false;
|
||||||
|
let applySql = false;
|
||||||
|
let repairFurniData = false;
|
||||||
|
try {
|
||||||
|
const body = (await request.json().catch(() => ({}))) as {
|
||||||
|
repair?: unknown;
|
||||||
|
repairNitros?: unknown;
|
||||||
|
sql?: unknown;
|
||||||
|
applySql?: unknown;
|
||||||
|
repairFurniData?: unknown;
|
||||||
|
};
|
||||||
|
repair = body.repair === true;
|
||||||
|
repairNitros = body.repairNitros === true;
|
||||||
|
sql = body.sql === true;
|
||||||
|
applySql = body.applySql === true;
|
||||||
|
repairFurniData = body.repairFurniData === true;
|
||||||
|
} catch {
|
||||||
|
/* no body */
|
||||||
|
}
|
||||||
|
|
||||||
const stream = new ReadableStream({
|
const stream = new ReadableStream({
|
||||||
async start(controller) {
|
async start(controller) {
|
||||||
const send = (data: unknown) => {
|
const send = (data: unknown) => {
|
||||||
@@ -20,7 +44,13 @@ export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await runCatalogAudit(send);
|
await runCatalogAudit(send, {
|
||||||
|
repair,
|
||||||
|
repairNitros,
|
||||||
|
sql,
|
||||||
|
applySql,
|
||||||
|
repairFurniData,
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
send({
|
send({
|
||||||
type: "error",
|
type: "error",
|
||||||
@@ -43,4 +73,5 @@ export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => {
|
|||||||
Connection: "keep-alive",
|
Connection: "keep-alive",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
|
);
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -35,6 +35,16 @@ export const DEFAULT_ICON_SOURCES: CloneSource[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const DEFAULT_NITRO_SOURCES: CloneSource[] = [
|
||||||
|
{
|
||||||
|
id: "default-wibbo",
|
||||||
|
name: "Wibbo",
|
||||||
|
furnidataUrl: "",
|
||||||
|
nitroBaseUrl: "https://assets.wibbo.org/bundled/furniture",
|
||||||
|
iconBaseUrl: "",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export async function listSources(): Promise<CloneSource[]> {
|
export async function listSources(): Promise<CloneSource[]> {
|
||||||
const raw = (await siteSettings.get(KEY, "[]")) ?? "[]";
|
const raw = (await siteSettings.get(KEY, "[]")) ?? "[]";
|
||||||
try {
|
try {
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user