entire new build system for backstage

This commit is contained in:
KingKDot
2026-08-19 21:01:22 -05:00
parent a489c4368b
commit c79a65d94d
12 changed files with 1058 additions and 68 deletions
+148
View File
@@ -303,6 +303,7 @@ async function renderPermissionsOverview() {
"system:chat",
"system:appearance",
"system:thumbnails",
"system:backstage-dll",
"system:input-archive",
"system:build-limits",
"system:export-import",
@@ -3024,6 +3025,10 @@ async function init() {
await loadThumbnailSettings();
initThumbnailHandlers();
}
if (userHas("system:backstage-dll")) {
await loadBackstageDllSettings();
initBackstageDllHandlers();
}
if (userHas("system:health")) {
await loadHealthStats();
initHealthHandlers();
@@ -3101,3 +3106,146 @@ async function init() {
}
init();
// ── Backstage DLL Settings ────────────────────────────────────────────────
let _backstageDllPollTimer = null;
function showBackstageDllMsg(text, type, targetEl) {
const el = targetEl || document.getElementById("backstage-dll-msg");
if (!el) return;
el.textContent = text;
if (type === "error") {
el.className = "text-sm rounded-lg px-3 py-2 border border-rose-800 bg-rose-900/20 text-rose-200";
} else if (type === "info") {
el.className = "text-sm rounded-lg px-3 py-2 border border-sky-800 bg-sky-900/20 text-sky-200";
} else {
el.className = "text-sm rounded-lg px-3 py-2 border border-emerald-800 bg-emerald-900/20 text-emerald-200";
}
el.classList.remove("hidden");
}
function renderBackstageDllStatus(status) {
if (!status) return;
const setText = (id, text) => {
const el = document.getElementById(id);
if (el) el.textContent = text;
};
setText("backstage-dll-export", status.exportName || (status.exists ? "(no randomized export?)" : "-"));
setText("backstage-dll-path", status.outputPath || "-");
setText("backstage-dll-size", formatBytes(status.sizeBytes));
setText("backstage-dll-crate", status.crateDir || "(crate not found)");
const tc = status.toolchainDetails || {};
const hint = [];
if (tc.cargoOnPath) hint.push("cargo on PATH");
if (tc.rustInstalled) hint.push("rust toolchain cached");
if (tc.rustTargetInstalled) hint.push("windows-gnu target ready");
if (tc.mingwReady) hint.push("mingw-w64 ready");
const tcEl = document.getElementById("backstage-dll-toolchain");
if (tcEl) {
tcEl.textContent = hint.length
? `Build tooling: ${hint.join(", ")}`
: "Build tooling: none detected (the first rebuild will download it into the data dir).";
}
const btn = document.getElementById("backstage-dll-rebuild-btn");
if (btn) btn.disabled = !!status.building;
const lastBuild = status.lastBuild;
if (lastBuild && lastBuild.finishedAt) {
showBackstageDllMsg(
`${lastBuild.ok ? "Last build succeeded" : "Last build failed"} (${formatDate(lastBuild.finishedAt)}): ${lastBuild.message}`,
lastBuild.ok ? "success" : "error",
document.getElementById("backstage-dll-lastbuild"),
);
if (status.building) {
showBackstageDllMsg("Rebuild in progress...", "info");
}
} else if (status.building) {
showBackstageDllMsg("Rebuild in progress...", "info");
}
}
async function loadBackstageDllSettings() {
if (!userHas("system:backstage-dll")) return;
try {
const res = await fetch("/api/settings/backstage-dll", { credentials: "include" });
if (!res.ok) return;
const data = await res.json();
renderBackstageDllStatus(data.status || {});
const el = document.getElementById("backstage-dll-rebuild-startup");
if (el) el.checked = !!(data.backstageDll && data.backstageDll.rebuildOnStartup);
} catch (e) {
console.error("Failed to load backstage DLL settings", e);
}
}
function initBackstageDllHandlers() {
const form = document.getElementById("backstage-dll-form");
if (form) form.addEventListener("submit", saveBackstageDllSettings);
const btn = document.getElementById("backstage-dll-rebuild-btn");
if (btn) btn.addEventListener("click", triggerBackstageDllRebuild);
}
async function saveBackstageDllSettings(e) {
e.preventDefault();
if (!requireUiPermission("system:backstage-dll", "Backstage DLL permission required.")) return;
const rebuildOnStartup = !!document.getElementById("backstage-dll-rebuild-startup")?.checked;
try {
const res = await fetch("/api/settings/backstage-dll", {
method: "PUT",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ rebuildOnStartup }),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
showBackstageDllMsg(data.error || "Failed to save", "error");
return;
}
showBackstageDllMsg("Backstage DLL settings saved.", "success");
renderBackstageDllStatus(data.status || {});
} catch (err) {
console.error("Failed to save backstage DLL settings", err);
showBackstageDllMsg("Failed to save.", "error");
}
}
async function triggerBackstageDllRebuild() {
if (!requireUiPermission("system:backstage-dll", "Backstage DLL permission required.")) return;
try {
const res = await fetch("/api/settings/backstage-dll/rebuild", {
method: "POST",
credentials: "include",
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
showBackstageDllMsg(data.message || data.error || "Rebuild failed to start.", "error");
return;
}
showBackstageDllMsg("Rebuild started in the background.", "info");
pollBackstageDllStatus();
} catch (err) {
console.error("Failed to start backstage DLL rebuild", err);
showBackstageDllMsg("Failed to start rebuild.", "error");
}
}
function pollBackstageDllStatus() {
const tick = async () => {
try {
const res = await fetch("/api/settings/backstage-dll", { credentials: "include" });
if (!res.ok) return;
const data = await res.json();
renderBackstageDllStatus(data.status || {});
if (data.status && data.status.building) {
clearTimeout(_backstageDllPollTimer);
_backstageDllPollTimer = setTimeout(tick, 2000);
}
} catch (err) {
console.error("Failed to poll backstage DLL status", err);
}
};
clearTimeout(_backstageDllPollTimer);
tick();
}
+60
View File
@@ -130,6 +130,7 @@
<a data-target="chat-settings-section" class="settings-nav-link" data-permission="system:chat" style="--accent: 56 189 248"><i class="fa-solid fa-comments w-4 text-sky-400"></i><span>Team Chat</span></a>
<a data-target="registration-section" class="settings-nav-link" data-permission="system:registration" style="--accent: 52 211 153"><i class="fa-solid fa-user-plus w-4 text-emerald-400"></i><span>Registration</span></a>
<a data-target="thumbnails-section" class="settings-nav-link" data-permission="system:thumbnails" style="--accent: 56 189 248"><i class="fa-solid fa-images w-4 text-sky-400"></i><span>Screenshot Thumbnails</span></a>
<a data-target="backstage-dll-section" class="settings-nav-link" data-permission="system:backstage-dll" style="--accent: 251 146 60"><i class="fa-solid fa-gears w-4 text-orange-400"></i><span>Backstage DLL</span></a>
<a data-target="input-archive-admin-section" class="settings-nav-link" data-permission="system:input-archive" style="--accent: 250 204 21"><i class="fa-solid fa-database w-4 text-yellow-400"></i><span>Input Archive Admin</span></a>
<a data-target="build-rate-limit-section" class="settings-nav-link" data-permission="system:build-limits" style="--accent: 251 146 60"><i class="fa-solid fa-gauge-high w-4 text-orange-400"></i><span>Build Rate Limit</span></a>
<a data-target="section-appearance" class="settings-nav-link" data-permission="system:appearance" style="--accent: 232 121 249"><i class="fa-solid fa-palette w-4 text-fuchsia-400"></i><span>Branding</span></a>
@@ -1237,6 +1238,65 @@
<p id="thumbnails-msg" class="hidden text-sm rounded-lg px-3 py-2 border"></p>
</section>
<!-- Backstage DLL -->
<section id="backstage-dll-section" data-permission="system:backstage-dll" class="hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-9 h-9 rounded-lg bg-orange-500/10 border border-orange-500/30">
<i class="fa-solid fa-gears text-orange-400"></i>
</div>
<div>
<h2 class="text-lg font-semibold">Backstage DLL</h2>
<p class="text-sm text-slate-400">Admin-only. Rebuild the BackstageInjection DLL to re-randomize the loader export name.</p>
</div>
</div>
<div class="text-xs text-slate-400 bg-slate-800/40 border border-slate-700/60 rounded-lg p-3">
<p>Each rebuild generates a new random <code class="text-orange-300">x&lthex&gt</code> export name for the reflective loader. The Go client and the C# build harness already locate the loader by pattern, so newly built DLLs are used without further changes. The rebuilt DLL is stored in the server data directory.</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
<div class="rounded-lg bg-slate-900 border border-slate-800 px-3 py-2">
<div class="text-slate-400">Current export name</div>
<div id="backstage-dll-export" class="font-mono text-orange-300">-</div>
</div>
<div class="rounded-lg bg-slate-900 border border-slate-800 px-3 py-2">
<div class="text-slate-400">Active DLL</div>
<div id="backstage-dll-path" class="font-mono text-xs text-slate-200 break-all">-</div>
</div>
<div class="rounded-lg bg-slate-900 border border-slate-800 px-3 py-2">
<div class="text-slate-400">Size</div>
<div id="backstage-dll-size" class="font-medium text-slate-200">-</div>
</div>
<div class="rounded-lg bg-slate-900 border border-slate-800 px-3 py-2">
<div class="text-slate-400">Rust crate</div>
<div id="backstage-dll-crate" class="font-mono text-xs text-slate-200 break-all">-</div>
</div>
</div>
<div id="backstage-dll-toolchain" class="text-xs text-slate-400"></div>
<p id="backstage-dll-lastbuild" class="hidden text-sm rounded-lg px-3 py-2 border"></p>
<form id="backstage-dll-form" class="space-y-4">
<label class="flex items-start gap-3 p-3 rounded-lg border border-slate-700/60 bg-slate-900/40 hover:bg-slate-900/70 cursor-pointer transition-colors">
<input id="backstage-dll-rebuild-startup" type="checkbox" class="mt-1 h-4 w-4 accent-orange-500" />
<div>
<div class="text-sm font-medium text-slate-100">Recompile on server startup</div>
<div class="text-xs text-slate-400">Rebuild and re-randomize the DLL every time the server starts. Uses the persistent toolchain cache in the data dir.</div>
</div>
</label>
<div class="flex flex-wrap items-center gap-3">
<button type="submit" class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-sky-700 hover:bg-sky-600 transition-colors text-white text-sm font-medium">
<i class="fa-solid fa-floppy-disk"></i>Save
</button>
<button type="button" id="backstage-dll-rebuild-btn" class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-orange-700 hover:bg-orange-600 transition-colors text-white text-sm font-medium">
<i class="fa-solid fa-rotate"></i>Rebuild Now (re-randomize)
</button>
</div>
</form>
<p id="backstage-dll-msg" class="hidden text-sm rounded-lg px-3 py-2 border"></p>
</section>
<!-- Input Archive Admin -->
<section id="input-archive-admin-section" data-permission="system:input-archive" class="hidden bg-slate-900/60 border border-slate-800 rounded-xl p-5 space-y-4 settings-section">
<div class="flex items-center gap-3">