@openmixer/plugin-qualify 0.14.1 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -14
- package/bin/plugin-qualify-sync.mjs +57 -0
- package/bin/plugin-qualify.mjs +66 -15
- package/dist/adjust-cli.d.ts +83 -0
- package/dist/adjust-cli.js +214 -0
- package/dist/adjust-cli.js.map +1 -0
- package/dist/clap-loader.d.ts +3 -3
- package/dist/clap-loader.js +11 -11
- package/dist/clap-loader.js.map +1 -1
- package/dist/history-adjust.d.ts +77 -0
- package/dist/history-adjust.js +99 -0
- package/dist/history-adjust.js.map +1 -0
- package/dist/history-file.d.ts +73 -0
- package/dist/history-file.js +133 -0
- package/dist/history-file.js.map +1 -0
- package/dist/host-admission.d.ts +53 -0
- package/dist/host-admission.js +96 -0
- package/dist/host-admission.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lv2-loader.d.ts +16 -2
- package/dist/lv2-loader.js +168 -17
- package/dist/lv2-loader.js.map +1 -1
- package/dist/measurement/cli.d.ts +6 -4
- package/dist/measurement/cli.js +12 -19
- package/dist/measurement/cli.js.map +1 -1
- package/dist/pins-file.d.ts +8 -2
- package/dist/pins-file.js +17 -3
- package/dist/pins-file.js.map +1 -1
- package/dist/probe-judge.d.ts +11 -1
- package/dist/probe-judge.js +20 -1
- package/dist/probe-judge.js.map +1 -1
- package/dist/probe-output-fixtures.d.ts +10 -0
- package/dist/probe-output-fixtures.js +86 -0
- package/dist/probe-output-fixtures.js.map +1 -1
- package/dist/probe-output.d.ts +2 -0
- package/dist/probe-output.js +1 -0
- package/dist/probe-output.js.map +1 -1
- package/dist/probe-runner.d.ts +9 -3
- package/dist/probe-runner.js +36 -12
- package/dist/probe-runner.js.map +1 -1
- package/dist/qualification-record.d.ts +109 -3
- package/dist/qualification-record.js +79 -13
- package/dist/qualification-record.js.map +1 -1
- package/dist/qualify-cli.d.ts +0 -1
- package/dist/qualify-cli.js +2 -4
- package/dist/qualify-cli.js.map +1 -1
- package/dist/qualify-declarations.d.ts +1 -1
- package/dist/qualify-declarations.js +1 -1
- package/dist/qualify-options.js +1 -2
- package/dist/qualify-options.js.map +1 -1
- package/dist/qualify-sync.d.ts +202 -0
- package/dist/qualify-sync.js +731 -0
- package/dist/qualify-sync.js.map +1 -0
- package/dist/whole-file.d.ts +3 -0
- package/dist/whole-file.js +36 -0
- package/dist/whole-file.js.map +1 -0
- package/fixtures/admission/2026-10-26.json +19 -0
- package/fixtures/clap-scan/fake.json +24 -24
- package/package.json +5 -4
- package/src/adjust-cli.ts +262 -0
- package/src/clap-loader.ts +9 -13
- package/src/history-adjust.ts +156 -0
- package/src/history-file.ts +177 -0
- package/src/host-admission.ts +136 -0
- package/src/index.ts +6 -0
- package/src/lv2-loader.ts +150 -15
- package/src/measurement/cli.ts +11 -17
- package/src/pins-file.ts +17 -3
- package/src/probe-judge.ts +27 -1
- package/src/probe-output-fixtures.ts +86 -0
- package/src/probe-output.ts +3 -0
- package/src/probe-runner.ts +45 -14
- package/src/qualification-record.ts +174 -15
- package/src/qualify-cli.ts +2 -5
- package/src/qualify-declarations.ts +1 -1
- package/src/qualify-options.ts +1 -2
- package/src/qualify-sync.ts +830 -0
- package/src/whole-file.ts +35 -0
- package/tools/_declarations.py +1 -1
- package/tools/gen-hosting-codes.mjs +1 -1
- package/tools/mod-host-admit.mjs +74 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
3
|
+
/**
|
|
4
|
+
* A file written whole or not at all: the bytes go to `<path>.new` beside it, are flushed to the disk, and the name is
|
|
5
|
+
* moved over the old file, then the directory is flushed so the rename itself survives a power cut. A reader of
|
|
6
|
+
* `path`, plugin-hostd at start among them, sees the old file or the whole new one, never a half.
|
|
7
|
+
*/
|
|
8
|
+
import { closeSync, fsyncSync, mkdirSync, openSync, renameSync, writeSync } from "node:fs";
|
|
9
|
+
import { dirname } from "node:path";
|
|
10
|
+
|
|
11
|
+
/** The bytes one write call takes; a large file goes out in pieces of this size. */
|
|
12
|
+
const PIECE_BYTES = 1 << 16;
|
|
13
|
+
|
|
14
|
+
/** The name the new bytes are written under before the rename. */
|
|
15
|
+
export const pendingPath = (path: string): string => `${path}.new`;
|
|
16
|
+
|
|
17
|
+
export function writeFileWhole(path: string, content: string | Uint8Array): void {
|
|
18
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
19
|
+
const bytes = typeof content === "string" ? Buffer.from(content, "utf8") : content;
|
|
20
|
+
const pending = pendingPath(path);
|
|
21
|
+
const fd = openSync(pending, "w", 0o644);
|
|
22
|
+
try {
|
|
23
|
+
for (let at = 0; at < bytes.length; at += PIECE_BYTES) writeSync(fd, bytes, at, Math.min(PIECE_BYTES, bytes.length - at));
|
|
24
|
+
fsyncSync(fd);
|
|
25
|
+
} finally {
|
|
26
|
+
closeSync(fd);
|
|
27
|
+
}
|
|
28
|
+
renameSync(pending, path);
|
|
29
|
+
const dir = openSync(dirname(path), "r");
|
|
30
|
+
try {
|
|
31
|
+
fsyncSync(dir);
|
|
32
|
+
} finally {
|
|
33
|
+
closeSync(dir);
|
|
34
|
+
}
|
|
35
|
+
}
|
package/tools/_declarations.py
CHANGED
|
@@ -25,7 +25,7 @@ DESCRIPTOR_DIR_SYSTEM = "/var/lib/omx/descriptors"
|
|
|
25
25
|
DESCRIPTOR_HASH_PREFIX = 12
|
|
26
26
|
DESCRIPTOR_SCHEMA_ENV = "OMX_CONTRACT_SCHEMA"
|
|
27
27
|
DESCRIPTOR_SCHEMA_INSTALLED = "/usr/share/omx-contract/omx-contract.schema.json"
|
|
28
|
-
DESCRIPTOR_SCHEMA_FLOOR = ">= 3.
|
|
28
|
+
DESCRIPTOR_SCHEMA_FLOOR = ">= 3.4.0"
|
|
29
29
|
DESCRIPTOR_CODE_SCHEMA = "contract.file.invalid"
|
|
30
30
|
DESCRIPTOR_CODE_SCHEMA_MISSING = "qualify.descriptor.schema-missing"
|
|
31
31
|
DESCRIPTOR_CODE_BINARY_UNHASHED = "qualify.descriptor.binary-unhashed"
|
|
@@ -51,7 +51,7 @@ export async function hostingCodesFileFrom(dir) {
|
|
|
51
51
|
function absent() {
|
|
52
52
|
return (
|
|
53
53
|
`omx-clap-core's TypeScript modules were not found in any of: ${clapCoreTsDirCandidates().join(', ')}. ` +
|
|
54
|
-
'Install omx-clap-core
|
|
54
|
+
'Install omx-clap-core (its modules in /usr/share/omx-clap-core/ts), set OMX_CLAP_CORE_TSDIR to its tsdir, or run make -C native deps.'
|
|
55
55
|
);
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
// Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
|
|
4
|
+
// One mod-host admission: a fresh `mod-host -n` on its own port, then `add` and `remove` of one plugin on its
|
|
5
|
+
// socket. Prints one JSON line, {installed, steps:[{cmd, resp | died}]}, for src/host-admission.ts to classify. The host
|
|
6
|
+
// is always killed at the end, so the next plugin gets a fresh one.
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { createConnection } from "node:net";
|
|
9
|
+
|
|
10
|
+
const uri = process.argv[2];
|
|
11
|
+
const port = 20000 + (process.pid % 20000);
|
|
12
|
+
const STEP_MS = 10000;
|
|
13
|
+
const INSTANCE = 0;
|
|
14
|
+
const COMMANDS = [
|
|
15
|
+
["add", `add ${uri} ${INSTANCE}`],
|
|
16
|
+
["remove", `remove ${INSTANCE}`],
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const host = spawn("mod-host", ["-n", "-p", String(port)], { stdio: "ignore" });
|
|
20
|
+
let hostEnd; // how the host went, once it has
|
|
21
|
+
host.on("exit", (code, signal) => (hostEnd = signal ?? "exit"));
|
|
22
|
+
const spawnFailed = new Promise((resolve) => host.on("error", (e) => resolve(e.code)));
|
|
23
|
+
|
|
24
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
25
|
+
async function connect() {
|
|
26
|
+
for (let i = 0; i < 50; i++) {
|
|
27
|
+
if (hostEnd !== undefined) return undefined;
|
|
28
|
+
const s = await new Promise((resolve) => {
|
|
29
|
+
const c = createConnection({ port, host: "127.0.0.1" }, () => resolve(c));
|
|
30
|
+
c.on("error", () => resolve(undefined));
|
|
31
|
+
});
|
|
32
|
+
if (s !== undefined) return s;
|
|
33
|
+
await sleep(100);
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function main() {
|
|
39
|
+
if ((await Promise.race([spawnFailed, sleep(200).then(() => undefined)])) === "ENOENT") return { installed: false, steps: [] };
|
|
40
|
+
const sock = await connect();
|
|
41
|
+
if (sock === undefined) return { installed: true, steps: [{ cmd: "add", died: hostEnd ?? "closed" }] };
|
|
42
|
+
let buffer = "";
|
|
43
|
+
let closed = false;
|
|
44
|
+
sock.on("data", (d) => (buffer += d.toString()));
|
|
45
|
+
sock.on("close", () => (closed = true));
|
|
46
|
+
sock.on("error", () => (closed = true));
|
|
47
|
+
const steps = [];
|
|
48
|
+
for (const [cmd, line] of COMMANDS) {
|
|
49
|
+
buffer = "";
|
|
50
|
+
sock.write(`${line}\0`);
|
|
51
|
+
const until = Date.now() + STEP_MS;
|
|
52
|
+
let resp;
|
|
53
|
+
while (Date.now() < until && resp === undefined && !closed && hostEnd === undefined) {
|
|
54
|
+
const m = /resp (-?\d+)/.exec(buffer);
|
|
55
|
+
if (m !== null) resp = Number(m[1]);
|
|
56
|
+
else await sleep(20);
|
|
57
|
+
}
|
|
58
|
+
if (resp === undefined) {
|
|
59
|
+
await sleep(100); // a host that dies on the command closes the socket a moment before it is reaped
|
|
60
|
+
steps.push({ cmd, died: hostEnd ?? (closed ? "closed" : "timeout") });
|
|
61
|
+
if (hostEnd === undefined && !closed) steps[steps.length - 1] = { cmd };
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
steps.push({ cmd, resp });
|
|
65
|
+
if (resp < 0) break;
|
|
66
|
+
}
|
|
67
|
+
sock.destroy();
|
|
68
|
+
return { installed: true, steps };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result = await main();
|
|
72
|
+
host.kill("SIGKILL");
|
|
73
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
74
|
+
process.exit(0);
|