Merge 7d72001bb94a91bfc895b98b6ec325fe2b1f5e58 into 9fb78453e088cd7b553d7779faa0de5c83708e70

This commit is contained in:
TioGlo 2026-03-20 22:01:34 -07:00 committed by GitHub
commit e802715000
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 7 deletions

View File

@ -0,0 +1,35 @@
import type { IrcClient } from "./client.js";
/**
* Registry of active IRC clients from the monitor.
* Keyed by accountId. Allows sendMessageIrc to use the persistent
* monitor client instead of creating a transient connection.
*/
const activeClients = new Map<string, IrcClient>();
export function setActiveClient(accountId: string, client: IrcClient): void {
activeClients.set(accountId, client);
}
export function getActiveClient(accountId: string): IrcClient | undefined {
const client = activeClients.get(accountId);
if (client && client.isReady()) {
return client;
}
return undefined;
}
export function removeActiveClient(accountId: string): void {
activeClients.delete(accountId);
}
/**
* Only remove the active client if it matches the expected instance.
* Prevents a stopping monitor from deregistering a newer monitor's
* healthy client during reconnect races.
*/
export function removeActiveClientIfMatch(accountId: string, expected: IrcClient): void {
if (activeClients.get(accountId) === expected) {
activeClients.delete(accountId);
}
}

View File

@ -1,5 +1,6 @@
import { resolveLoggerBackedRuntime } from "openclaw/plugin-sdk/extension-shared";
import { resolveIrcAccount } from "./accounts.js";
import { setActiveClient, removeActiveClientIfMatch } from "./active-clients.js";
import { connectIrcClient, type IrcClient } from "./client.js";
import { buildIrcConnectOptions } from "./connect-options.js";
import { handleIrcInbound } from "./inbound.js";
@ -136,8 +137,13 @@ export async function monitorIrcProvider(opts: IrcMonitorOptions): Promise<{ sto
`[${account.accountId}] connected to ${account.host}:${account.port}${account.tls ? " (tls)" : ""} as ${client.nick}`,
);
setActiveClient(account.accountId, client);
return {
stop: () => {
if (client) {
removeActiveClientIfMatch(account.accountId, client);
}
client?.quit("shutdown");
client = null;
},

View File

@ -1,4 +1,5 @@
import { resolveIrcAccount } from "./accounts.js";
import { getActiveClient } from "./active-clients.js";
import type { IrcClient } from "./client.js";
import { connectIrcClient } from "./client.js";
import { buildIrcConnectOptions } from "./connect-options.js";
@ -67,13 +68,19 @@ export async function sendMessageIrc(
if (client?.isReady()) {
client.sendPrivmsg(target, payload);
} else {
const transient = await connectIrcClient(
buildIrcConnectOptions(account, {
connectTimeoutMs: 12000,
}),
);
transient.sendPrivmsg(target, payload);
transient.quit("sent");
// Try the monitor's persistent client first (already connected and joined to channels)
const active = getActiveClient(account.accountId);
if (active) {
active.sendPrivmsg(target, payload);
} else {
const transient = await connectIrcClient(
buildIrcConnectOptions(account, {
connectTimeoutMs: 12000,
}),
);
transient.sendPrivmsg(target, payload);
transient.quit("sent");
}
}
runtime.channel.activity.record({