Peter Steinberger af9d76b79a fix: honor explicit Synology Chat rate-limit env values
Landed from contributor PR #39197 by @scoootscooob.

Co-authored-by: scoootscooob <zhentongfan@gmail.com>
2026-03-08 02:34:19 +00:00

97 lines
3.4 KiB
TypeScript

/**
* Account resolution: reads config from channels.synology-chat,
* merges per-account overrides, falls back to environment variables.
*/
import type { SynologyChatChannelConfig, ResolvedSynologyChatAccount } from "./types.js";
/** Extract the channel config from the full OpenClaw config object. */
function getChannelConfig(cfg: any): SynologyChatChannelConfig | undefined {
return cfg?.channels?.["synology-chat"];
}
/** Parse allowedUserIds from string or array to string[]. */
function parseAllowedUserIds(raw: string | string[] | undefined): string[] {
if (!raw) return [];
if (Array.isArray(raw)) return raw.filter(Boolean);
return raw
.split(",")
.map((s) => s.trim())
.filter(Boolean);
}
function parseRateLimitPerMinute(raw: string | undefined): number {
if (raw == null) {
return 30;
}
const trimmed = raw.trim();
if (!/^-?\d+$/.test(trimmed)) {
return 30;
}
return Number.parseInt(trimmed, 10);
}
/**
* List all configured account IDs for this channel.
* Returns ["default"] if there's a base config, plus any named accounts.
*/
export function listAccountIds(cfg: any): string[] {
const channelCfg = getChannelConfig(cfg);
if (!channelCfg) return [];
const ids = new Set<string>();
// If base config has a token, there's a "default" account
const hasBaseToken = channelCfg.token || process.env.SYNOLOGY_CHAT_TOKEN;
if (hasBaseToken) {
ids.add("default");
}
// Named accounts
if (channelCfg.accounts) {
for (const id of Object.keys(channelCfg.accounts)) {
ids.add(id);
}
}
return Array.from(ids);
}
/**
* Resolve a specific account by ID with full defaults applied.
* Falls back to env vars for the "default" account.
*/
export function resolveAccount(cfg: any, accountId?: string | null): ResolvedSynologyChatAccount {
const channelCfg = getChannelConfig(cfg) ?? {};
const id = accountId || "default";
// Account-specific overrides (if named account exists)
const accountOverride = channelCfg.accounts?.[id] ?? {};
// Env var fallbacks (primarily for the "default" account)
const envToken = process.env.SYNOLOGY_CHAT_TOKEN ?? "";
const envIncomingUrl = process.env.SYNOLOGY_CHAT_INCOMING_URL ?? "";
const envNasHost = process.env.SYNOLOGY_NAS_HOST ?? "localhost";
const envAllowedUserIds = process.env.SYNOLOGY_ALLOWED_USER_IDS ?? "";
const envRateLimitValue = parseRateLimitPerMinute(process.env.SYNOLOGY_RATE_LIMIT);
const envBotName = process.env.OPENCLAW_BOT_NAME ?? "OpenClaw";
// Merge: account override > base channel config > env var
return {
accountId: id,
enabled: accountOverride.enabled ?? channelCfg.enabled ?? true,
token: accountOverride.token ?? channelCfg.token ?? envToken,
incomingUrl: accountOverride.incomingUrl ?? channelCfg.incomingUrl ?? envIncomingUrl,
nasHost: accountOverride.nasHost ?? channelCfg.nasHost ?? envNasHost,
webhookPath: accountOverride.webhookPath ?? channelCfg.webhookPath ?? "/webhook/synology",
dmPolicy: accountOverride.dmPolicy ?? channelCfg.dmPolicy ?? "allowlist",
allowedUserIds: parseAllowedUserIds(
accountOverride.allowedUserIds ?? channelCfg.allowedUserIds ?? envAllowedUserIds,
),
rateLimitPerMinute:
accountOverride.rateLimitPerMinute ?? channelCfg.rateLimitPerMinute ?? envRateLimitValue,
botName: accountOverride.botName ?? channelCfg.botName ?? envBotName,
allowInsecureSsl: accountOverride.allowInsecureSsl ?? channelCfg.allowInsecureSsl ?? false,
};
}