fix inter instance config broken stuffs

This commit is contained in:
legop3
2026-09-14 20:52:01 -04:00
parent 9ce6550f13
commit 470e95b0f9
3 changed files with 88 additions and 3 deletions
+3 -2
View File
@@ -465,11 +465,12 @@ Implemented on 2026-09-14:
- Fixed production WAL-mode snapshots creating unmanifested SQLite `-wal` and `-shm` files during schema inspection. Backup and restore validation now remove only those temporary staged sidecars before archiving or applying data, and the regression fixture uses WAL mode to match the real databases.
- Added the early streaming `/video` middleware with `http-proxy-middleware`. Express removes the public prefix before forwarding WHEP/WHIP requests to `127.0.0.1:8889`, while root-relative MediaMTX session locations receive the prefix again so subsequent browser `PATCH` and `DELETE` requests follow the same path. MediaMTX signaling now binds to loopback; its ICE UDP/TCP listener remains directly reachable on port 8189.
- Replaced Discord's `siteUrl`, the inter-instance profile's `publicUrl`, and media `whepBaseUrl` with one top-level `publicUrl`. A numbered internal database migration transforms every saved configuration revision before current validation, and the media section now contains only optional additional ICE hosts. WHEP and microphone WHIP URLs are fixed relative paths, so they work through the current origin without knowing its hostname.
- Fixed inter-instance public payload generation to read feature flags and social links from the same live configuration revision. Social links enabled through the new configuration system no longer trigger an undefined legacy-config reference and an HTTP 500 response.
Local verification completed:
- All 118 server tests passed, including populated legacy-style default coverage, complete schema-description and input-example coverage, file-backed setup-code lifecycle and symlink rejection, service-definition-derived feature projection, schema-derived secret paths, configuration defaults and strict validation, full-document revision conflicts, secret preservation, administrator invariants, setup and initialized-server YAML import safety, recursive removal of nonexistent fields, and the earlier filesystem coverage.
- All 26 server test files passed after live application, backup/restore, and the internal media proxy were added. The media tests stream exact SDP and trickle-ICE bodies through `POST`, `PATCH`, and `DELETE`, preserve headers, verify prefix and session-location rewriting, confirm loopback-only signaling, and derive the public ICE hostname from the canonical URL. The database migration and production-style WAL backup/restore paths are also covered. Application restart was not signaled on the development machine.
- All 119 server tests passed, including populated legacy-style default coverage, complete schema-description and input-example coverage, file-backed setup-code lifecycle and symlink rejection, service-definition-derived feature projection, schema-derived secret paths, configuration defaults and strict validation, full-document revision conflicts, secret preservation, administrator invariants, setup and initialized-server YAML import safety, recursive removal of nonexistent fields, inter-instance payload generation with social links enabled, and the earlier filesystem coverage.
- All 27 server test files passed after live application, backup/restore, the internal media proxy, and the inter-instance regression coverage were added. The media tests stream exact SDP and trickle-ICE bodies through `POST`, `PATCH`, and `DELETE`, preserve headers, verify prefix and session-location rewriting, confirm loopback-only signaling, and derive the public ICE hostname from the canonical URL. The database migration and production-style WAL backup/restore paths are also covered. Application restart was not signaled on the development machine.
- Focused admin, route, and identity UI lint passed.
- All 20 existing focused web UI tests passed.
- The production web UI build completed successfully and regenerated the checked-in server assets.
@@ -190,7 +190,15 @@ function filterPublicUsers(users = [], publicIds) {
function buildLocalInfo() {
const mode = getMode();
const lockdown = isLockdownMode();
const features = getFeatureFlags();
/*
Build every configuration-derived part of one public response from the
same immutable revision. Besides preventing a revision change from mixing
feature flags with newer social links, this supplies the explicit snapshot
required by getConfiguredSocials instead of relying on the removed legacy
global configuration object.
*/
const config = loadConfig();
const features = getFeatureFlags(config);
const publicRoster = getPublicRoster();
const publicIds = publicRoverIdSet(publicRoster);
const roster = publicRoster.map((rover) => (lockdown ? rover : addRoverSnapshotLinks(rover)));
@@ -0,0 +1,76 @@
// Inter-Instance Public Payload Tests
// Purpose: Verifies that configuration-backed public metadata can be assembled for peer servers.
// Scope: Runs the service in an isolated child process so its socket gateways, timers, and configuration singleton never touch another test's runtime.
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { execFileSync } = require('node:child_process');
test('builds the inter-instance payload when social links are enabled', () => {
const dataRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'multirover-inter-instance-'));
const serverRoot = path.resolve(__dirname, '../../..');
try {
/*
Enabling Social links is essential to this regression: disabled links
short-circuit before the configuration argument is read and therefore
cannot expose a stale or missing configuration reference. The child
process loads the real service graph and calls the same payload builder
used by GET /api/inter-instance/info.
*/
const script = `
const configuration = require('./src/configuration');
const database = configuration.getConfigurationDatabase();
const current = database.getClientConfiguration();
const next = structuredClone(current.config);
next.socials.enabled = true;
next.socials.links = [{
id: 'community',
label: 'Community',
url: 'https://community.example.test',
icon: 'FaUsers',
color: '#38bdf8'
}];
database.updateConfiguration({
value: next,
expectedRevision: current.revision,
actor: 'inter-instance-test'
});
configuration.applyCommittedConfiguration().then(() => {
const { buildLocalInfo } = require('./src/services/interInstanceService');
const payload = buildLocalInfo();
// Production services may write startup logs to stdout. A unique
// marker separates the assertion payload from that expected noise.
process.stdout.write('\\n__INTER_INSTANCE_RESULT__' + JSON.stringify(payload.socials));
database.close();
// Requiring the production service intentionally registers persistent
// Socket.IO gateways. The disposable child has completed its one real
// payload assertion, so it must not wait for those server-owned handles.
process.exit(0);
}).catch((error) => {
console.error(error);
process.exit(1);
});
`;
const output = execFileSync(process.execPath, ['-e', script], {
cwd: serverRoot,
env: { ...process.env, SERVER_DATA_DIR: dataRoot },
encoding: 'utf8',
});
const resultMarker = '__INTER_INSTANCE_RESULT__';
const resultOffset = output.lastIndexOf(resultMarker);
assert.notEqual(resultOffset, -1, 'child process did not emit its inter-instance result');
assert.deepEqual(JSON.parse(output.slice(resultOffset + resultMarker.length)), [{
id: 'community',
label: 'Community',
url: 'https://community.example.test',
icon: 'FaUsers',
color: '#38bdf8',
}]);
} finally {
fs.rmSync(dataRoot, { recursive: true, force: true });
}
});