fix plugins not loading
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
import { afterEach, describe, expect, test } from "bun:test";
|
||||||
|
import { mkdtemp, mkdir, rm, writeFile } from "fs/promises";
|
||||||
|
import { tmpdir } from "os";
|
||||||
|
import { join } from "path";
|
||||||
|
import { loadPluginBundle } from "./plugin-state-bundle";
|
||||||
|
|
||||||
|
let tempRoots: string[] = [];
|
||||||
|
|
||||||
|
async function createTempRoot(): Promise<string> {
|
||||||
|
const root = await mkdtemp(join(tmpdir(), "overlord-plugin-bundle-test-"));
|
||||||
|
tempRoots.push(root);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await Promise.all(tempRoots.map((root) => rm(root, { recursive: true, force: true })));
|
||||||
|
tempRoots = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("loadPluginBundle", () => {
|
||||||
|
test("matches plugin binaries when clients report a pretty Windows OS name", async () => {
|
||||||
|
const root = await createTempRoot();
|
||||||
|
const pluginDir = join(root, "sample-c");
|
||||||
|
await mkdir(pluginDir, { recursive: true });
|
||||||
|
await writeFile(
|
||||||
|
join(pluginDir, "manifest.json"),
|
||||||
|
JSON.stringify({
|
||||||
|
id: "sample-c",
|
||||||
|
name: "sample-c",
|
||||||
|
binaries: { "windows-amd64": "sample-c-windows-amd64.dll" },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
await writeFile(join(pluginDir, "sample-c-windows-amd64.dll"), "test-binary");
|
||||||
|
|
||||||
|
const bundle = await loadPluginBundle(root, "sample-c", async () => {}, "Windows 11 Pro 24H2", "amd64");
|
||||||
|
|
||||||
|
expect(bundle.binaryPath).toBe(join(pluginDir, "sample-c-windows-amd64.dll"));
|
||||||
|
expect(bundle.size).toBe("test-binary".length);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -262,8 +262,9 @@ export async function loadPluginBundle(
|
|||||||
let binaryPath: string | null = null;
|
let binaryPath: string | null = null;
|
||||||
|
|
||||||
if (manifest.binaries && clientOS && clientArch) {
|
if (manifest.binaries && clientOS && clientArch) {
|
||||||
const key = `${clientOS}-${clientArch}`;
|
const filename = getPluginBinaryCandidateKeys(clientOS, clientArch)
|
||||||
const filename = manifest.binaries[key];
|
.map((key) => manifest.binaries?.[key])
|
||||||
|
.find((name): name is string => typeof name === "string" && name.length > 0);
|
||||||
if (filename) {
|
if (filename) {
|
||||||
const candidate = path.join(dir, filename);
|
const candidate = path.join(dir, filename);
|
||||||
try {
|
try {
|
||||||
@@ -274,7 +275,9 @@ export async function loadPluginBundle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!binaryPath) {
|
if (!binaryPath) {
|
||||||
const platformKey = clientOS && clientArch ? `${clientOS}-${clientArch}` : "unknown";
|
const platformKey = clientOS && clientArch ? formatPluginPlatformKey(clientOS, clientArch) : "unknown";
|
||||||
|
const normalizedOS = normalizePluginOS(clientOS);
|
||||||
|
const normalizedArch = normalizePluginArch(clientArch);
|
||||||
const files = await fs.readdir(dir);
|
const files = await fs.readdir(dir);
|
||||||
const archRegex = /-(linux|darwin|windows|freebsd)-(amd64|arm64|arm|386)\.(so|dll|dylib)$/i;
|
const archRegex = /-(linux|darwin|windows|freebsd)-(amd64|arm64|arm|386)\.(so|dll|dylib)$/i;
|
||||||
|
|
||||||
@@ -282,8 +285,8 @@ export async function loadPluginBundle(
|
|||||||
const m = f.match(archRegex);
|
const m = f.match(archRegex);
|
||||||
if (m) {
|
if (m) {
|
||||||
return (
|
return (
|
||||||
m[1].toLowerCase() === (clientOS || "").toLowerCase() &&
|
m[1].toLowerCase() === normalizedOS &&
|
||||||
m[2].toLowerCase() === (clientArch || "").toLowerCase()
|
m[2].toLowerCase() === normalizedArch
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const fl = f.toLowerCase();
|
const fl = f.toLowerCase();
|
||||||
@@ -301,6 +304,39 @@ export async function loadPluginBundle(
|
|||||||
return { manifest, binaryPath, size: stat.size };
|
return { manifest, binaryPath, size: stat.size };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPluginBinaryCandidateKeys(clientOS?: string, clientArch?: string): string[] {
|
||||||
|
if (!clientOS || !clientArch) return [];
|
||||||
|
const rawKey = `${clientOS}-${clientArch}`.toLowerCase();
|
||||||
|
const normalizedKey = formatPluginPlatformKey(clientOS, clientArch);
|
||||||
|
return Array.from(
|
||||||
|
new Set([normalizedKey, rawKey].filter((key) => !key.startsWith("unknown-") && !key.endsWith("-unknown"))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPluginPlatformKey(clientOS?: string, clientArch?: string): string {
|
||||||
|
return `${normalizePluginOS(clientOS)}-${normalizePluginArch(clientArch)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePluginOS(value?: string): string {
|
||||||
|
const os = (value || "").trim().toLowerCase();
|
||||||
|
if (!os) return "unknown";
|
||||||
|
if (os.includes("windows") || os === "win32") return "windows";
|
||||||
|
if (os.includes("mac os") || os.includes("macos") || os.includes("os x") || os === "darwin") return "darwin";
|
||||||
|
if (os.includes("linux")) return "linux";
|
||||||
|
if (os.includes("freebsd")) return "freebsd";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePluginArch(value?: string): string {
|
||||||
|
const arch = (value || "").trim().toLowerCase();
|
||||||
|
if (!arch) return "unknown";
|
||||||
|
if (arch === "x64" || arch === "x86_64") return "amd64";
|
||||||
|
if (arch === "ia32" || arch === "i386" || arch === "x86") return "386";
|
||||||
|
if (arch === "aarch64") return "arm64";
|
||||||
|
if (arch === "armv7" || arch === "armv6") return "arm";
|
||||||
|
return arch;
|
||||||
|
}
|
||||||
|
|
||||||
export type PluginPull = {
|
export type PluginPull = {
|
||||||
id: string;
|
id: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user