nextcloud: keep checking onlyoffice's connection while the last check failed (issue 1832)

applyOnlyOffice only ran the connection check when a setting changed, so
once it failed while settings matched, nothing checked again and the
failure was logged once and forgotten. The client now remembers whether
the last check failed and re-runs it on every tick until it passes;
index.ts logs every failing tick and one line when it recovers.
This commit is contained in:
jochen
2026-10-22 16:28:35 +02:00
parent 8928e6f972
commit edb6d3b7d3
3 changed files with 60 additions and 5 deletions
+8 -1
View File
@@ -62,6 +62,10 @@ const ONLYOFFICE_KEYS: ReadonlyArray<readonly [occKey: string, configKey: string
let saidOnlyOfficeNotGiven = false;
export class NextcloudClient {
// Whether the last connection check failed (novox/hq issue 1832): while it did, every tick runs
// the check again, even when nothing changed, until it passes.
private lastCheckFailed = false;
constructor(
private readonly container: string,
private readonly ocsUrl: string,
@@ -144,7 +148,9 @@ export class NextcloudClient {
changed.push(occKey);
}
}
if (changed.length === 0) return { changed };
// Nothing changed, and the last check (if any) passed: there is nothing to check again
// (novox/hq issue 1832). Otherwise — something changed, or the last check failed — run it.
if (changed.length === 0 && !this.lastCheckFailed) return { changed };
let checkOk = true;
try {
@@ -152,6 +158,7 @@ export class NextcloudClient {
} catch {
checkOk = false;
}
this.lastCheckFailed = !checkOk;
return { changed, checkOk };
}
+12 -4
View File
@@ -45,12 +45,20 @@ async function pollShares(client: NextcloudClient): Promise<void> {
}
// Keeps Nextcloud's onlyoffice settings matched to the document server the mesh bound (novox/hq
// issue 1830). The client never logs; this says what it did.
// issue 1830). The client never logs; this says what it did. A failed connection check is run
// again on every later tick until it passes (issue 1832): every failing tick is logged, and one
// line marks it passing again; nothing is logged while the last check passed and nothing changed.
let onlyOfficeCheckWasFailing = false;
async function applyOnlyOffice(client: NextcloudClient): Promise<void> {
const result = client.applyOnlyOffice();
if (result.changed.length === 0) return;
console.log(`[nextcloud] onlyoffice: set ${result.changed.join(", ")}`);
if (result.checkOk === false) console.error("[nextcloud] onlyoffice: connection check failed after applying settings");
if (result.changed.length > 0) console.log(`[nextcloud] onlyoffice: set ${result.changed.join(", ")}`);
if (result.checkOk === false) {
onlyOfficeCheckWasFailing = true;
console.error("[nextcloud] onlyoffice: connection check failed" + (result.changed.length > 0 ? " after applying settings" : ""));
} else if (result.checkOk === true && onlyOfficeCheckWasFailing) {
onlyOfficeCheckWasFailing = false;
console.log("[nextcloud] onlyoffice: connection check passes again");
}
}
if (nextcloud) {
+40
View File
@@ -110,6 +110,46 @@ test("the jwt_secret is set by stdin of config:import, never in an argv", () =>
assert.equal(current.jwt_secret, SECRET, "the secret was actually applied");
});
// 1832/AC1: a failed check keeps running on every later tick, even with nothing changed, reporting
// checkOk false each time, until it passes — then nothing runs again while nothing changes
// (novox/hq issue 1832).
test("a failed check is re-run every tick until it passes, then nothing runs while unchanged", () => {
const c = client();
const current: Record<string, string> = {}; // every key unset, so tick 1 changes all four
const checkOpts: { checkFails?: boolean } = { checkFails: true };
const stand = standInOcc(current, checkOpts);
mock.method(c, "occ", stand.impl);
const checkCalls = () => stand.calls.filter((a) => a[0] === "onlyoffice:documentserver").length;
const file = configFile(FULL_CONFIG);
// Tick 1: everything changes, the check runs and fails (1832/AC1c: reported on a failing tick).
const tick1 = c.applyOnlyOffice(file);
assert.deepEqual(tick1.changed.sort(), ["DocumentServerInternalUrl", "DocumentServerUrl", "StorageUrl", "jwt_secret"].sort());
assert.equal(tick1.checkOk, false);
assert.equal(checkCalls(), 1);
// Tick 2: nothing changed, but the last check failed — it is run again (1832/AC1a), and fails
// again, reported again (1832/AC1c).
const tick2 = c.applyOnlyOffice(file);
assert.deepEqual(tick2.changed, []);
assert.equal(tick2.checkOk, false);
assert.equal(checkCalls(), 2, "the check ran again though nothing changed");
// Tick 3: the document server now answers; still nothing changed, but the last check had
// failed, so it is run again — and this time it passes.
checkOpts.checkFails = false;
const tick3 = c.applyOnlyOffice(file);
assert.deepEqual(tick3.changed, []);
assert.equal(tick3.checkOk, true);
assert.equal(checkCalls(), 3);
// Tick 4: nothing changed, and the last check passed — no check runs (1832/AC1b).
const tick4 = c.applyOnlyOffice(file);
assert.deepEqual(tick4.changed, []);
assert.equal(tick4.checkOk, undefined);
assert.equal(checkCalls(), 3, "no further check ran once the last one passed");
});
// 1830/AC3b: when they match, it changes nothing and runs no check.
test("changes nothing and runs no check when every value already matches", () => {
const c = client();