Files
mesh-catalog/modules/nextcloud/index.ts
T
jochen edb6d3b7d3 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.
2026-10-22 16:28:35 +02:00

76 lines
3.1 KiB
TypeScript

// nextcloud's events. The tool runtime imports this once the broker is bound. It watches the user
// list and the share list and announces new arrivals.
//
// Emits (novox/hq ADR 0041/0042):
// module.nextcloud.user.created — a user account appeared (occ user:list)
// module.nextcloud.share.created — a share appeared (OCS shares)
//
// Both are diffed and primed silently on the first look, so a restart does not re-announce every
// existing user and share as freshly created.
import { emit } from "@novox/mesh-sdk/events";
import { NextcloudClient } from "./client.js";
// Constructed lazily so an unconfigured node (no admin password) loads this entrypoint without
// crashing the events host — it simply watches nothing.
let nextcloud: NextcloudClient | undefined;
try {
nextcloud = NextcloudClient.fromEnv();
} catch (err) {
console.log(`[nextcloud] not configured, not watching: ${err}`);
}
const knownUsers = new Set<string>();
let usersPrimed = false;
async function pollUsers(client: NextcloudClient): Promise<void> {
const users = client.listUsers();
for (const u of users) {
if (knownUsers.has(u.uid)) continue;
if (usersPrimed) await emit("user.created", { uid: u.uid, displayName: u.displayName });
knownUsers.add(u.uid);
}
usersPrimed = true;
}
const knownShares = new Set<string>();
let sharesPrimed = false;
async function pollShares(client: NextcloudClient): Promise<void> {
const shares = await client.listShares();
for (const s of shares) {
if (knownShares.has(s.id)) continue;
if (sharesPrimed) await emit("share.created", { id: s.id, path: s.path, shareType: s.shareType, shareWith: s.shareWith, owner: s.owner });
knownShares.add(s.id);
}
sharesPrimed = true;
}
// 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. 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) 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) {
const client = nextcloud;
const tick = (fn: (c: NextcloudClient) => Promise<void>): void => {
const run = (): void => void fn(client).catch((err) => console.error(`[nextcloud] ${err}`));
setInterval(run, 60_000);
run();
};
tick(pollUsers);
tick(pollShares);
tick(applyOnlyOffice);
console.log("[nextcloud] watching users, shares and onlyoffice settings");
}