324 lines
12 KiB
TypeScript
324 lines
12 KiB
TypeScript
import type { Config } from '../config/index.js';
|
|
import type { HookEngine } from '../hooks/index.js';
|
|
import { ChannelRegistry, TelegramAdapter, WebChatAdapter, DiscordAdapter, SlackAdapter, WhatsAppAdapter, MatrixAdapter, SignalAdapter, MattermostAdapter, TeamsAdapter, GoogleChatAdapter, BlueBubblesAdapter, LineAdapter, FeishuAdapter, ZaloAdapter, PairingManager } from '../channels/index.js';
|
|
import { CronScheduler, WebhookHandler, GmailWatcher, buildPresetCronJobs } from '../automation/index.js';
|
|
import type { GatewayServer } from '../gateway/index.js';
|
|
|
|
export interface ChannelsDeps {
|
|
config: Config;
|
|
channelRegistry: ChannelRegistry;
|
|
hookEngine: HookEngine;
|
|
pairingManager?: PairingManager;
|
|
gateway: GatewayServer;
|
|
}
|
|
|
|
export interface ChannelsResult {
|
|
cronScheduler?: CronScheduler;
|
|
webhookHandler?: WebhookHandler;
|
|
gmailWatcher?: GmailWatcher;
|
|
}
|
|
|
|
function resolveChannelMinioShare(config: Config): {
|
|
enabled: boolean;
|
|
endpoint: string;
|
|
accessKey: string;
|
|
secretKey: string;
|
|
bucket: string;
|
|
prefix: string;
|
|
secure: boolean;
|
|
expires?: string;
|
|
mcPath?: string;
|
|
} | undefined {
|
|
const minio = config.backup.minio;
|
|
if (!minio.enabled || !minio.endpoint || !minio.access_key || !minio.secret_key || !minio.bucket) {
|
|
return undefined;
|
|
}
|
|
return {
|
|
enabled: true,
|
|
endpoint: minio.endpoint,
|
|
accessKey: minio.access_key,
|
|
secretKey: minio.secret_key,
|
|
bucket: minio.bucket,
|
|
prefix: minio.prefix,
|
|
secure: minio.secure,
|
|
};
|
|
}
|
|
|
|
function resolveChannelMinioShareWithOverrides(
|
|
base: ReturnType<typeof resolveChannelMinioShare>,
|
|
override: {
|
|
enabled: boolean;
|
|
endpoint?: string;
|
|
access_key?: string;
|
|
secret_key?: string;
|
|
bucket?: string;
|
|
prefix: string;
|
|
secure: boolean;
|
|
expires: string;
|
|
mc_path?: string;
|
|
} | undefined,
|
|
): {
|
|
enabled: boolean;
|
|
endpoint: string;
|
|
accessKey: string;
|
|
secretKey: string;
|
|
bucket: string;
|
|
prefix: string;
|
|
secure: boolean;
|
|
expires?: string;
|
|
mcPath?: string;
|
|
} | undefined {
|
|
if (!override?.enabled) {
|
|
return base;
|
|
}
|
|
|
|
const endpoint = override.endpoint ?? base?.endpoint;
|
|
const accessKey = override.access_key ?? base?.accessKey;
|
|
const secretKey = override.secret_key ?? base?.secretKey;
|
|
const bucket = override.bucket ?? base?.bucket;
|
|
if (!endpoint || !accessKey || !secretKey || !bucket) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
enabled: true,
|
|
endpoint,
|
|
accessKey,
|
|
secretKey,
|
|
bucket,
|
|
prefix: override.prefix,
|
|
secure: override.secure,
|
|
expires: override.expires,
|
|
mcPath: override.mc_path,
|
|
};
|
|
}
|
|
|
|
export function registerChannels(deps: ChannelsDeps): ChannelsResult {
|
|
const { config, channelRegistry, hookEngine, pairingManager, gateway } = deps;
|
|
const channelMinioShare = resolveChannelMinioShare(config);
|
|
|
|
// Register Telegram adapter (if configured)
|
|
if (config.telegram) {
|
|
const telegramAdapter = new TelegramAdapter({
|
|
botToken: config.telegram.bot_token,
|
|
allowedChatIds: config.telegram.allowed_chat_ids,
|
|
requireMention: config.telegram.require_mention,
|
|
hookEngine,
|
|
pairingManager,
|
|
});
|
|
channelRegistry.register(telegramAdapter);
|
|
}
|
|
|
|
// Register Discord adapter (if configured)
|
|
if (config.discord) {
|
|
const discordAdapter = new DiscordAdapter({
|
|
botToken: config.discord.bot_token,
|
|
allowedGuildIds: config.discord.allowed_guild_ids.length > 0 ? config.discord.allowed_guild_ids : undefined,
|
|
allowedChannelIds: config.discord.allowed_channel_ids.length > 0 ? config.discord.allowed_channel_ids : undefined,
|
|
requireMention: config.discord.require_mention,
|
|
pairingManager,
|
|
});
|
|
channelRegistry.register(discordAdapter);
|
|
}
|
|
|
|
// Register Slack adapter (if configured)
|
|
if (config.slack) {
|
|
const slackAdapter = new SlackAdapter({
|
|
botToken: config.slack.bot_token,
|
|
appToken: config.slack.app_token,
|
|
signingSecret: config.slack.signing_secret,
|
|
allowedChannelIds: config.slack.allowed_channel_ids.length > 0 ? config.slack.allowed_channel_ids : undefined,
|
|
requireMention: config.slack.require_mention,
|
|
pairingManager,
|
|
});
|
|
channelRegistry.register(slackAdapter);
|
|
}
|
|
|
|
// Register WhatsApp adapter (if configured)
|
|
if (config.whatsapp) {
|
|
const whatsappAdapter = new WhatsAppAdapter({
|
|
allowedNumbers: config.whatsapp.allowed_numbers.length > 0 ? config.whatsapp.allowed_numbers : undefined,
|
|
allowedGroupIds: config.whatsapp.allowed_group_ids.length > 0 ? config.whatsapp.allowed_group_ids : undefined,
|
|
requireMention: config.whatsapp.require_mention,
|
|
dataDir: config.whatsapp.data_dir,
|
|
pairingManager,
|
|
allowNoSandbox: config.whatsapp.no_sandbox,
|
|
});
|
|
channelRegistry.register(whatsappAdapter);
|
|
}
|
|
|
|
// Register Matrix adapter (if configured)
|
|
if (config.matrix) {
|
|
const matrixAdapter = new MatrixAdapter({
|
|
homeserverUrl: config.matrix.homeserver_url,
|
|
accessToken: config.matrix.access_token,
|
|
allowedRoomIds: config.matrix.allowed_room_ids.length > 0 ? config.matrix.allowed_room_ids : undefined,
|
|
requireMention: config.matrix.require_mention,
|
|
syncTimeoutMs: config.matrix.sync_timeout_ms,
|
|
displayName: config.matrix.display_name,
|
|
pairingManager,
|
|
});
|
|
channelRegistry.register(matrixAdapter);
|
|
}
|
|
|
|
// Register Signal adapter (if configured)
|
|
if (config.signal) {
|
|
const signalAdapter = new SignalAdapter({
|
|
account: config.signal.account,
|
|
signalCliPath: config.signal.signal_cli_path,
|
|
allowedNumbers: config.signal.allowed_numbers.length > 0 ? config.signal.allowed_numbers : undefined,
|
|
allowedGroupIds: config.signal.allowed_group_ids.length > 0 ? config.signal.allowed_group_ids : undefined,
|
|
requireMention: config.signal.require_mention,
|
|
mentionName: config.signal.mention_name,
|
|
pollIntervalMs: config.signal.poll_interval_ms,
|
|
sendTimeoutMs: config.signal.send_timeout_ms,
|
|
pairingManager,
|
|
});
|
|
channelRegistry.register(signalAdapter);
|
|
}
|
|
|
|
// Register Mattermost adapter (if configured)
|
|
if (config.mattermost) {
|
|
const mattermostAdapter = new MattermostAdapter({
|
|
serverUrl: config.mattermost.server_url,
|
|
botToken: config.mattermost.bot_token,
|
|
allowedChannelIds: config.mattermost.allowed_channel_ids.length > 0 ? config.mattermost.allowed_channel_ids : undefined,
|
|
requireMention: config.mattermost.require_mention,
|
|
mentionName: config.mattermost.mention_name,
|
|
pollIntervalMs: config.mattermost.poll_interval_ms,
|
|
pairingManager,
|
|
});
|
|
channelRegistry.register(mattermostAdapter);
|
|
}
|
|
|
|
// Register Microsoft Teams adapter (if configured)
|
|
if (config.teams) {
|
|
const teamsAdapter = new TeamsAdapter({
|
|
appId: config.teams.app_id,
|
|
appPassword: config.teams.app_password,
|
|
allowedConversationIds: config.teams.allowed_conversation_ids.length > 0 ? config.teams.allowed_conversation_ids : undefined,
|
|
requireMention: config.teams.require_mention,
|
|
});
|
|
channelRegistry.register(teamsAdapter);
|
|
gateway.setTeamsHandler(teamsAdapter);
|
|
}
|
|
|
|
// Register Google Chat adapter (if configured)
|
|
if (config.google_chat) {
|
|
const googleChatAdapter = new GoogleChatAdapter({
|
|
serviceAccountKeyFile: config.google_chat.service_account_key_file,
|
|
serviceAccountJson: config.google_chat.service_account_json,
|
|
webhookToken: config.google_chat.webhook_token,
|
|
allowedSpaceNames: config.google_chat.allowed_space_names.length > 0 ? config.google_chat.allowed_space_names : undefined,
|
|
requireMention: config.google_chat.require_mention,
|
|
});
|
|
channelRegistry.register(googleChatAdapter);
|
|
gateway.setGoogleChatHandler(googleChatAdapter);
|
|
}
|
|
|
|
// Register BlueBubbles adapter (if configured)
|
|
if (config.bluebubbles) {
|
|
const blueBubblesAdapter = new BlueBubblesAdapter({
|
|
endpoint: config.bluebubbles.endpoint,
|
|
apiKey: config.bluebubbles.api_key,
|
|
webhookToken: config.bluebubbles.webhook_token,
|
|
allowedChatGuids: config.bluebubbles.allowed_chat_guids.length > 0 ? config.bluebubbles.allowed_chat_guids : undefined,
|
|
requireMention: config.bluebubbles.require_mention,
|
|
mentionName: config.bluebubbles.mention_name,
|
|
});
|
|
channelRegistry.register(blueBubblesAdapter);
|
|
gateway.setBlueBubblesHandler(blueBubblesAdapter);
|
|
}
|
|
|
|
// Register LINE adapter (if configured)
|
|
if (config.line) {
|
|
const lineMinioShare = resolveChannelMinioShareWithOverrides(channelMinioShare, config.line.minio);
|
|
const effectiveLineMinioShare = lineMinioShare && !config.line.minio.enabled
|
|
? { ...lineMinioShare, prefix: `${lineMinioShare.prefix.replace(/\/+$/, '')}/channels/line` }
|
|
: lineMinioShare;
|
|
const lineAdapter = new LineAdapter({
|
|
channelAccessToken: config.line.channel_access_token,
|
|
channelSecret: config.line.channel_secret,
|
|
allowedSourceIds: config.line.allowed_source_ids.length > 0 ? config.line.allowed_source_ids : undefined,
|
|
requireMention: config.line.require_mention,
|
|
mentionName: config.line.mention_name,
|
|
minio: effectiveLineMinioShare,
|
|
});
|
|
channelRegistry.register(lineAdapter);
|
|
gateway.setLineHandler(lineAdapter);
|
|
}
|
|
|
|
// Register Feishu adapter (if configured)
|
|
if (config.feishu) {
|
|
const feishuAdapter = new FeishuAdapter({
|
|
appId: config.feishu.app_id,
|
|
appSecret: config.feishu.app_secret,
|
|
webhookToken: config.feishu.webhook_token,
|
|
allowedChatIds: config.feishu.allowed_chat_ids.length > 0 ? config.feishu.allowed_chat_ids : undefined,
|
|
requireMention: config.feishu.require_mention,
|
|
mentionName: config.feishu.mention_name,
|
|
endpoint: config.feishu.endpoint,
|
|
});
|
|
channelRegistry.register(feishuAdapter);
|
|
gateway.setFeishuHandler(feishuAdapter);
|
|
}
|
|
|
|
// Register Zalo adapter (if configured)
|
|
if (config.zalo) {
|
|
const zaloMinioShare = resolveChannelMinioShareWithOverrides(channelMinioShare, config.zalo.minio);
|
|
const effectiveZaloMinioShare = zaloMinioShare && !config.zalo.minio.enabled
|
|
? { ...zaloMinioShare, prefix: `${zaloMinioShare.prefix.replace(/\/+$/, '')}/channels/zalo` }
|
|
: zaloMinioShare;
|
|
const zaloAdapter = new ZaloAdapter({
|
|
oaAccessToken: config.zalo.oa_access_token,
|
|
endpoint: config.zalo.endpoint,
|
|
webhookToken: config.zalo.webhook_token,
|
|
allowedUserIds: config.zalo.allowed_user_ids.length > 0 ? config.zalo.allowed_user_ids : undefined,
|
|
requireMention: config.zalo.require_mention,
|
|
mentionName: config.zalo.mention_name,
|
|
minio: effectiveZaloMinioShare,
|
|
});
|
|
channelRegistry.register(zaloAdapter);
|
|
gateway.setZaloHandler(zaloAdapter);
|
|
}
|
|
|
|
// Register WebChat adapter (wraps the gateway)
|
|
const webChatAdapter = new WebChatAdapter({ gateway });
|
|
channelRegistry.register(webChatAdapter);
|
|
|
|
// Register cron scheduler adapter (if any cron jobs configured)
|
|
let cronScheduler: CronScheduler | undefined;
|
|
const presetCronJobs = buildPresetCronJobs(config);
|
|
const cronJobs = [...config.automation.cron, ...presetCronJobs];
|
|
if (cronJobs.length > 0) {
|
|
cronScheduler = new CronScheduler(cronJobs, channelRegistry, config.automation.delivery_mode);
|
|
channelRegistry.register(cronScheduler);
|
|
console.log(`Registered ${cronJobs.length} cron job(s)`);
|
|
}
|
|
|
|
// Register webhook handler adapter (if any webhooks configured)
|
|
let webhookHandler: WebhookHandler | undefined;
|
|
if (config.automation.webhooks.length > 0) {
|
|
webhookHandler = new WebhookHandler(
|
|
config.automation.webhooks,
|
|
channelRegistry,
|
|
config.automation.delivery_mode,
|
|
config.server.max_request_body_bytes,
|
|
);
|
|
channelRegistry.register(webhookHandler);
|
|
gateway.setWebhookHandler(webhookHandler);
|
|
console.log(`Registered ${config.automation.webhooks.length} webhook(s)`);
|
|
}
|
|
|
|
// Register Gmail watcher adapter (if configured and enabled)
|
|
let gmailWatcher: GmailWatcher | undefined;
|
|
if (config.automation.gmail?.enabled) {
|
|
gmailWatcher = new GmailWatcher(config.automation.gmail, channelRegistry);
|
|
channelRegistry.register(gmailWatcher);
|
|
gateway.setGmailHandler(gmailWatcher);
|
|
console.log('Registered Gmail watcher');
|
|
}
|
|
|
|
return { cronScheduler, webhookHandler, gmailWatcher };
|
|
}
|