perf(studio): cache nitro scan, stream progress, virtualize cleanup list
This commit is contained in:
1 parent
c916e42572
commit
ba81d16f00
5 files changed
+727
-257
No files matched your search
@@ -16,7 +16,11 @@ import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { db, ItemsBase, queryRows } from "@/lib/db";
|
||||
import { normalizeClassname } from "@/lib/furni/classname";
|
||||
import {
|
||||
getBaseClassname,
|
||||
getSafeClassnameStem,
|
||||
normalizeClassname,
|
||||
} from "@/lib/furni/classname";
|
||||
import { indexLocalFurniture } from "@/lib/furni/local-presence";
|
||||
import { readFurniData } from "./furni-data";
|
||||
|
||||
@@ -107,6 +111,58 @@ export async function getCatalogIdSet(): Promise<Set<number>> {
|
||||
|
||||
const nitroPresenceCache = new Map<string, boolean>();
|
||||
|
||||
/** Every classname stem a `.nitro`/`.swf`/icon file may legitimately use. */
|
||||
function addClassnameStem(set: Set<string>, classname: string): void {
|
||||
const normalized = classname.trim().toLowerCase();
|
||||
if (!normalized) return;
|
||||
const base = getBaseClassname(normalized).toLowerCase();
|
||||
if (base) set.add(base);
|
||||
if (normalized.includes("*")) {
|
||||
const safe = getSafeClassnameStem(normalized).toLowerCase();
|
||||
if (safe) set.add(safe);
|
||||
}
|
||||
}
|
||||
|
||||
let cleanupStemsSnapshot: { set: Set<string>; timestamp: number } | null = null;
|
||||
|
||||
/**
|
||||
* Authoritative stems for the nitro-cleanup scan: every `item_name` plus the
|
||||
* `public_name` fallback (mirroring repair-nitros.ts resolution). Cached the
|
||||
* same way as the Studio listings so repeated scans (auto-clean, panel) don't
|
||||
* re-query `items_base` on every call.
|
||||
*/
|
||||
export async function getCleanupValidStems(): Promise<Set<string>> {
|
||||
const now = Date.now();
|
||||
if (
|
||||
cleanupStemsSnapshot &&
|
||||
now - cleanupStemsSnapshot.timestamp < CACHE_TTL
|
||||
) {
|
||||
return cleanupStemsSnapshot.set;
|
||||
}
|
||||
const set = new Set<string>();
|
||||
try {
|
||||
const rows = await queryRows<{
|
||||
item_name: string;
|
||||
public_name: string;
|
||||
}>(sql`SELECT item_name, public_name FROM items_base`);
|
||||
for (const row of rows) {
|
||||
addClassnameStem(set, row.item_name);
|
||||
if (
|
||||
row.public_name &&
|
||||
row.public_name !== row.item_name &&
|
||||
!row.public_name.includes(" ") &&
|
||||
row.public_name !== "0"
|
||||
) {
|
||||
addClassnameStem(set, row.public_name);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* empty set → every asset is treated as orphaned */
|
||||
}
|
||||
cleanupStemsSnapshot = { set, timestamp: now };
|
||||
return set;
|
||||
}
|
||||
|
||||
/** `existsSync` memoized per (dir + base) — nitro files change rarely. */
|
||||
export function nitroExistsCached(dir: string, base: string): boolean {
|
||||
const key = `${dir}/${base}`;
|
||||
@@ -210,5 +266,6 @@ export function clearFurniImportCache(): void {
|
||||
furniDataSetSnapshot = null;
|
||||
catalogIdsSnapshot = null;
|
||||
nitroPresenceCache.clear();
|
||||
cleanupStemsSnapshot = null;
|
||||
statsSnapshot = null;
|
||||
}
|
||||
Reference in new issue
Block a user