mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-24 23:21:30 +00:00
Zalo: lazy-load channel runtime paths
This commit is contained in:
1
extensions/zalo/src/actions.runtime.ts
Normal file
1
extensions/zalo/src/actions.runtime.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { sendMessageZalo } from "./send.js";
|
||||
@@ -5,7 +5,13 @@ import type {
|
||||
} from "openclaw/plugin-sdk/zalo";
|
||||
import { extractToolSend, jsonResult, readStringParam } from "openclaw/plugin-sdk/zalo";
|
||||
import { listEnabledZaloAccounts } from "./accounts.js";
|
||||
import { sendMessageZalo } from "./send.js";
|
||||
|
||||
let zaloActionsRuntimePromise: Promise<typeof import("./actions.runtime.js")> | null = null;
|
||||
|
||||
async function loadZaloActionsRuntime() {
|
||||
zaloActionsRuntimePromise ??= import("./actions.runtime.js");
|
||||
return zaloActionsRuntimePromise;
|
||||
}
|
||||
|
||||
const providerId = "zalo";
|
||||
|
||||
@@ -35,6 +41,7 @@ export const zaloMessageActions: ChannelMessageActionAdapter = {
|
||||
});
|
||||
const mediaUrl = readStringParam(params, "media", { trim: false });
|
||||
|
||||
const { sendMessageZalo } = await loadZaloActionsRuntime();
|
||||
const result = await sendMessageZalo(to ?? "", content ?? "", {
|
||||
accountId: accountId ?? undefined,
|
||||
mediaUrl: mediaUrl ?? undefined,
|
||||
|
||||
91
extensions/zalo/src/channel.runtime.ts
Normal file
91
extensions/zalo/src/channel.runtime.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { createAccountStatusSink } from "openclaw/plugin-sdk/compat";
|
||||
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/zalo";
|
||||
import { probeZalo } from "./probe.js";
|
||||
import { resolveZaloProxyFetch } from "./proxy.js";
|
||||
import { normalizeSecretInputString } from "./secret-input.js";
|
||||
import { sendMessageZalo } from "./send.js";
|
||||
|
||||
export async function notifyZaloPairingApproval(params: {
|
||||
cfg: import("openclaw/plugin-sdk/zalo").OpenClawConfig;
|
||||
id: string;
|
||||
}) {
|
||||
const { resolveZaloAccount } = await import("./accounts.js");
|
||||
const account = resolveZaloAccount({ cfg: params.cfg });
|
||||
if (!account.token) {
|
||||
throw new Error("Zalo token not configured");
|
||||
}
|
||||
await sendMessageZalo(params.id, PAIRING_APPROVED_MESSAGE, {
|
||||
token: account.token,
|
||||
});
|
||||
}
|
||||
|
||||
export async function sendZaloText(
|
||||
params: Parameters<typeof sendMessageZalo>[2] & {
|
||||
to: string;
|
||||
text: string;
|
||||
},
|
||||
) {
|
||||
return await sendMessageZalo(params.to, params.text, params);
|
||||
}
|
||||
|
||||
export async function probeZaloAccount(params: {
|
||||
account: import("./accounts.js").ResolvedZaloAccount;
|
||||
timeoutMs?: number;
|
||||
}) {
|
||||
return await probeZalo(
|
||||
params.account.token,
|
||||
params.timeoutMs,
|
||||
resolveZaloProxyFetch(params.account.config.proxy),
|
||||
);
|
||||
}
|
||||
|
||||
export async function startZaloGatewayAccount(
|
||||
ctx: Parameters<
|
||||
NonNullable<import("openclaw/plugin-sdk/zalo").ChannelPlugin["gateway"]>["startAccount"]
|
||||
>[0],
|
||||
) {
|
||||
const account = ctx.account;
|
||||
const token = account.token.trim();
|
||||
const mode = account.config.webhookUrl ? "webhook" : "polling";
|
||||
let zaloBotLabel = "";
|
||||
const fetcher = resolveZaloProxyFetch(account.config.proxy);
|
||||
try {
|
||||
const probe = await probeZalo(token, 2500, fetcher);
|
||||
const name = probe.ok ? probe.bot?.name?.trim() : null;
|
||||
if (name) {
|
||||
zaloBotLabel = ` (${name})`;
|
||||
}
|
||||
if (!probe.ok) {
|
||||
ctx.log?.warn?.(
|
||||
`[${account.accountId}] Zalo probe failed before provider start (${String(probe.elapsedMs)}ms): ${probe.error}`,
|
||||
);
|
||||
}
|
||||
ctx.setStatus({
|
||||
accountId: account.accountId,
|
||||
bot: probe.bot,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.log?.warn?.(
|
||||
`[${account.accountId}] Zalo probe threw before provider start: ${err instanceof Error ? (err.stack ?? err.message) : String(err)}`,
|
||||
);
|
||||
}
|
||||
const statusSink = createAccountStatusSink({
|
||||
accountId: ctx.accountId,
|
||||
setStatus: ctx.setStatus,
|
||||
});
|
||||
ctx.log?.info(`[${account.accountId}] starting provider${zaloBotLabel} mode=${mode}`);
|
||||
const { monitorZaloProvider } = await import("./monitor.js");
|
||||
return monitorZaloProvider({
|
||||
token,
|
||||
account,
|
||||
config: ctx.cfg,
|
||||
runtime: ctx.runtime,
|
||||
abortSignal: ctx.abortSignal,
|
||||
useWebhook: Boolean(account.config.webhookUrl),
|
||||
webhookUrl: account.config.webhookUrl,
|
||||
webhookSecret: normalizeSecretInputString(account.config.webhookSecret),
|
||||
webhookPath: account.config.webhookPath,
|
||||
fetcher,
|
||||
statusSink,
|
||||
});
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
buildOpenGroupPolicyRestrictSendersWarning,
|
||||
buildOpenGroupPolicyWarning,
|
||||
collectOpenProviderGroupPolicyWarnings,
|
||||
createAccountStatusSink,
|
||||
mapAllowFromEntries,
|
||||
} from "openclaw/plugin-sdk/compat";
|
||||
import type {
|
||||
@@ -22,8 +21,6 @@ import {
|
||||
formatAllowFromLowercase,
|
||||
listDirectoryUserEntriesFromAllowFrom,
|
||||
isNumericTargetId,
|
||||
PAIRING_APPROVED_MESSAGE,
|
||||
resolveOutboundMediaUrls,
|
||||
sendPayloadWithChunkedTextAndMedia,
|
||||
setAccountEnabledInConfigSection,
|
||||
} from "openclaw/plugin-sdk/zalo";
|
||||
@@ -35,10 +32,6 @@ import {
|
||||
} from "./accounts.js";
|
||||
import { zaloMessageActions } from "./actions.js";
|
||||
import { ZaloConfigSchema } from "./config-schema.js";
|
||||
import { probeZalo } from "./probe.js";
|
||||
import { resolveZaloProxyFetch } from "./proxy.js";
|
||||
import { normalizeSecretInputString } from "./secret-input.js";
|
||||
import { sendMessageZalo } from "./send.js";
|
||||
import { zaloSetupAdapter } from "./setup-core.js";
|
||||
import { zaloSetupWizard } from "./setup-surface.js";
|
||||
import { collectZaloStatusIssues } from "./status-issues.js";
|
||||
@@ -63,6 +56,13 @@ function normalizeZaloMessagingTarget(raw: string): string | undefined {
|
||||
return trimmed.replace(/^(zalo|zl):/i, "");
|
||||
}
|
||||
|
||||
let zaloChannelRuntimePromise: Promise<typeof import("./channel.runtime.js")> | null = null;
|
||||
|
||||
async function loadZaloChannelRuntime() {
|
||||
zaloChannelRuntimePromise ??= import("./channel.runtime.js");
|
||||
return zaloChannelRuntimePromise;
|
||||
}
|
||||
|
||||
export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
|
||||
id: "zalo",
|
||||
meta,
|
||||
@@ -190,13 +190,8 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
|
||||
pairing: {
|
||||
idLabel: "zaloUserId",
|
||||
normalizeAllowEntry: (entry) => entry.replace(/^(zalo|zl):/i, ""),
|
||||
notifyApproval: async ({ cfg, id }) => {
|
||||
const account = resolveZaloAccount({ cfg: cfg });
|
||||
if (!account.token) {
|
||||
throw new Error("Zalo token not configured");
|
||||
}
|
||||
await sendMessageZalo(id, PAIRING_APPROVED_MESSAGE, { token: account.token });
|
||||
},
|
||||
notifyApproval: async (params) =>
|
||||
await (await loadZaloChannelRuntime()).notifyZaloPairingApproval(params),
|
||||
},
|
||||
outbound: {
|
||||
deliveryMode: "direct",
|
||||
@@ -213,14 +208,22 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
|
||||
emptyResult: { channel: "zalo", messageId: "" },
|
||||
}),
|
||||
sendText: async ({ to, text, accountId, cfg }) => {
|
||||
const result = await sendMessageZalo(to, text, {
|
||||
const result = await (
|
||||
await loadZaloChannelRuntime()
|
||||
).sendZaloText({
|
||||
to,
|
||||
text,
|
||||
accountId: accountId ?? undefined,
|
||||
cfg: cfg,
|
||||
});
|
||||
return buildChannelSendResult("zalo", result);
|
||||
},
|
||||
sendMedia: async ({ to, text, mediaUrl, accountId, cfg }) => {
|
||||
const result = await sendMessageZalo(to, text, {
|
||||
const result = await (
|
||||
await loadZaloChannelRuntime()
|
||||
).sendZaloText({
|
||||
to,
|
||||
text,
|
||||
accountId: accountId ?? undefined,
|
||||
mediaUrl,
|
||||
cfg: cfg,
|
||||
@@ -239,7 +242,7 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
|
||||
collectStatusIssues: collectZaloStatusIssues,
|
||||
buildChannelSummary: ({ snapshot }) => buildTokenChannelStatusSummary(snapshot),
|
||||
probeAccount: async ({ account, timeoutMs }) =>
|
||||
probeZalo(account.token, timeoutMs, resolveZaloProxyFetch(account.config.proxy)),
|
||||
await (await loadZaloChannelRuntime()).probeZaloAccount({ account, timeoutMs }),
|
||||
buildAccountSnapshot: ({ account, runtime }) => {
|
||||
const configured = Boolean(account.token?.trim());
|
||||
const base = buildBaseAccountStatusSnapshot({
|
||||
@@ -260,51 +263,7 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
|
||||
},
|
||||
},
|
||||
gateway: {
|
||||
startAccount: async (ctx) => {
|
||||
const account = ctx.account;
|
||||
const token = account.token.trim();
|
||||
const mode = account.config.webhookUrl ? "webhook" : "polling";
|
||||
let zaloBotLabel = "";
|
||||
const fetcher = resolveZaloProxyFetch(account.config.proxy);
|
||||
try {
|
||||
const probe = await probeZalo(token, 2500, fetcher);
|
||||
const name = probe.ok ? probe.bot?.name?.trim() : null;
|
||||
if (name) {
|
||||
zaloBotLabel = ` (${name})`;
|
||||
}
|
||||
if (!probe.ok) {
|
||||
ctx.log?.warn?.(
|
||||
`[${account.accountId}] Zalo probe failed before provider start (${String(probe.elapsedMs)}ms): ${probe.error}`,
|
||||
);
|
||||
}
|
||||
ctx.setStatus({
|
||||
accountId: account.accountId,
|
||||
bot: probe.bot,
|
||||
});
|
||||
} catch (err) {
|
||||
ctx.log?.warn?.(
|
||||
`[${account.accountId}] Zalo probe threw before provider start: ${err instanceof Error ? (err.stack ?? err.message) : String(err)}`,
|
||||
);
|
||||
}
|
||||
const statusSink = createAccountStatusSink({
|
||||
accountId: ctx.accountId,
|
||||
setStatus: ctx.setStatus,
|
||||
});
|
||||
ctx.log?.info(`[${account.accountId}] starting provider${zaloBotLabel} mode=${mode}`);
|
||||
const { monitorZaloProvider } = await import("./monitor.js");
|
||||
return monitorZaloProvider({
|
||||
token,
|
||||
account,
|
||||
config: ctx.cfg,
|
||||
runtime: ctx.runtime,
|
||||
abortSignal: ctx.abortSignal,
|
||||
useWebhook: Boolean(account.config.webhookUrl),
|
||||
webhookUrl: account.config.webhookUrl,
|
||||
webhookSecret: normalizeSecretInputString(account.config.webhookSecret),
|
||||
webhookPath: account.config.webhookPath,
|
||||
fetcher,
|
||||
statusSink,
|
||||
});
|
||||
},
|
||||
startAccount: async (ctx) =>
|
||||
await (await loadZaloChannelRuntime()).startZaloGatewayAccount(ctx),
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user