mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-16 08:00:49 +08:00
Revert "Fix WhatsApp connection test delivery without touching DSH sessions."
This reverts commit 0bc0992330.
This commit is contained in:
parent
0bc0992330
commit
dd2365407e
5 changed files with 206 additions and 396 deletions
400
lib/index.js
400
lib/index.js
File diff suppressed because one or more lines are too long
|
|
@ -3,7 +3,7 @@
|
||||||
* when Baileys only surfaces opaque @lid identities on the wire.
|
* when Baileys only surfaces opaque @lid identities on the wire.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { areJidsSameUser, jidDecode, jidNormalizedUser } from '@whiskeysockets/baileys';
|
import { areJidsSameUser, jidDecode } from '@whiskeysockets/baileys';
|
||||||
|
|
||||||
function isLidServer(server) {
|
function isLidServer(server) {
|
||||||
return server === 'lid' || server === 'hosted.lid';
|
return server === 'lid' || server === 'hosted.lid';
|
||||||
|
|
@ -76,56 +76,6 @@ async function lookupLidForPn(socket, pn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prefer the live WhatsApp self-chat JID (LID when available) for outbound
|
|
||||||
* probes. Sending only the stored PN often "succeeds" in Baileys but never
|
|
||||||
* syncs into the phone's Message Yourself thread after LID migration.
|
|
||||||
*
|
|
||||||
* @param {{ socket?: object, accountJid: string, lidPnCache?: Map<string, string> }} options
|
|
||||||
* @returns {Promise<string>}
|
|
||||||
*/
|
|
||||||
export async function resolveWhatsappSelfChatJid({
|
|
||||||
socket,
|
|
||||||
accountJid,
|
|
||||||
lidPnCache,
|
|
||||||
} = {}) {
|
|
||||||
const normalize = (value) => {
|
|
||||||
if (typeof value !== 'string' || !value.trim()) return null;
|
|
||||||
try {
|
|
||||||
return jidNormalizedUser(value.trim()) || value.trim();
|
|
||||||
} catch {
|
|
||||||
return value.trim();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const me = socket?.user;
|
|
||||||
for (const candidate of [me?.lid, me?.id]) {
|
|
||||||
const jid = normalize(candidate);
|
|
||||||
if (jid && isWhatsappLidJid(jid)) return jid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapped = await lookupLidForPn(socket, accountJid);
|
|
||||||
const mappedJid = normalize(mapped);
|
|
||||||
if (mappedJid && isWhatsappLidJid(mappedJid)) return mappedJid;
|
|
||||||
|
|
||||||
if (lidPnCache instanceof Map && typeof accountJid === 'string') {
|
|
||||||
for (const [lidUser, pn] of lidPnCache.entries()) {
|
|
||||||
try {
|
|
||||||
if (areJidsSameUser(pn, accountJid) === true && /^\d+$/.test(lidUser)) {
|
|
||||||
return `${lidUser}@lid`;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// keep scanning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fallback = normalize(accountJid);
|
|
||||||
if (!fallback) throw new TypeError('WhatsApp account JID is required');
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect local-part tokens for the linked bot account (PN and LID).
|
* Collect local-part tokens for the linked bot account (PN and LID).
|
||||||
* Used only to strip trigger @mentions from inbound text — not context injection.
|
* Used only to strip trigger @mentions from inbound text — not context injection.
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,11 @@ import {
|
||||||
|
|
||||||
import { emptyAccessGrant, ensureGroupBucket, normalizeAccessPhone, phoneFromWhatsappJid, resolveAccessAgentPreset } from '../shared/access-grant.mjs';
|
import { emptyAccessGrant, ensureGroupBucket, normalizeAccessPhone, phoneFromWhatsappJid, resolveAccessAgentPreset } from '../shared/access-grant.mjs';
|
||||||
import { splitMessageText } from '../shared/editable-message-stream.mjs';
|
import { splitMessageText } from '../shared/editable-message-stream.mjs';
|
||||||
import {
|
|
||||||
connectionTestTarget,
|
|
||||||
} from '../shared/connection-test.mjs';
|
|
||||||
import { t } from '../shared/i18n.mjs';
|
import { t } from '../shared/i18n.mjs';
|
||||||
import { ImagePromptError } from '../shared/image-prompt.mjs';
|
import { ImagePromptError } from '../shared/image-prompt.mjs';
|
||||||
import { trackOutboundArtifactProviderPromise } from '../shared/semantic/artifact.mjs';
|
import { trackOutboundArtifactProviderPromise } from '../shared/semantic/artifact.mjs';
|
||||||
import { createWhatsappBridgeStatus, WhatsappHarnessBridge } from './whatsapp-bridge.mjs';
|
import { createWhatsappBridgeStatus, WhatsappHarnessBridge } from './whatsapp-bridge.mjs';
|
||||||
import {
|
import { enrichWhatsappInboundIdentities, resolveWhatsappGroupSubject, resolveWhatsappGroupSubjects } from './whatsapp-identity.mjs';
|
||||||
enrichWhatsappInboundIdentities,
|
|
||||||
resolveWhatsappGroupSubject,
|
|
||||||
resolveWhatsappGroupSubjects,
|
|
||||||
resolveWhatsappSelfChatJid,
|
|
||||||
} from './whatsapp-identity.mjs';
|
|
||||||
import {
|
import {
|
||||||
gateWhatsappInbound,
|
gateWhatsappInbound,
|
||||||
loadWhatsappAccessGrant,
|
loadWhatsappAccessGrant,
|
||||||
|
|
@ -873,10 +865,6 @@ export class WhatsappRuntime {
|
||||||
return this.stop();
|
return this.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Channel-direct probe (no Harness / DSH session). Prefer the last bound
|
|
||||||
* private-chat reply target; otherwise Message Yourself via live LID/PN.
|
|
||||||
*/
|
|
||||||
async sendConnectionTest(text) {
|
async sendConnectionTest(text) {
|
||||||
if (!this.#status.ready || !this.#client) {
|
if (!this.#status.ready || !this.#client) {
|
||||||
const error = new Error(t('WhatsApp机器人尚未连接'));
|
const error = new Error(t('WhatsApp机器人尚未连接'));
|
||||||
|
|
@ -886,34 +874,13 @@ export class WhatsappRuntime {
|
||||||
if (typeof text !== 'string' || !text.trim()) {
|
if (typeof text !== 'string' || !text.trim()) {
|
||||||
throw new TypeError('WhatsApp connection test text is required');
|
throw new TypeError('WhatsApp connection test text is required');
|
||||||
}
|
}
|
||||||
const target = await this.#connectionTestSendTarget();
|
await this.#client.sendText({
|
||||||
await this.#client.sendText(target, text);
|
jid: this.#config.accountJid,
|
||||||
|
selfChat: true,
|
||||||
|
}, text);
|
||||||
return { sent: true };
|
return { sent: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
async #connectionTestSendTarget() {
|
|
||||||
const remembered = connectionTestTarget(this.#state);
|
|
||||||
const rememberedJid = typeof remembered?.jid === 'string' ? remembered.jid.trim() : '';
|
|
||||||
if (rememberedJid) {
|
|
||||||
let selfChat = remembered.selfChat === true;
|
|
||||||
if (!selfChat) {
|
|
||||||
try {
|
|
||||||
selfChat = areJidsSameUser(rememberedJid, this.#config.accountJid) === true;
|
|
||||||
} catch {
|
|
||||||
selfChat = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Bound chat only — drop quoted/key so this is a fresh probe, not a reply.
|
|
||||||
return { jid: rememberedJid, selfChat };
|
|
||||||
}
|
|
||||||
const jid = await resolveWhatsappSelfChatJid({
|
|
||||||
socket: this.#session?.socket,
|
|
||||||
accountJid: this.#config.accountJid,
|
|
||||||
lidPnCache: this.#lidPnCache,
|
|
||||||
});
|
|
||||||
return { jid, selfChat: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync WhatsApp group subjects into accessGrant.groups[*].title.
|
* Sync WhatsApp group subjects into accessGrant.groups[*].title.
|
||||||
* @param {string[]|null|undefined} groupJids
|
* @param {string[]|null|undefined} groupJids
|
||||||
|
|
|
||||||
|
|
@ -5,37 +5,11 @@ import {
|
||||||
enrichWhatsappInboundIdentities,
|
enrichWhatsappInboundIdentities,
|
||||||
isWhatsappLidJid,
|
isWhatsappLidJid,
|
||||||
rememberWhatsappLidPnPairs,
|
rememberWhatsappLidPnPairs,
|
||||||
resolveWhatsappSelfChatJid,
|
|
||||||
stripWhatsappBotMentionText,
|
stripWhatsappBotMentionText,
|
||||||
whatsappBotMentionTokens,
|
whatsappBotMentionTokens,
|
||||||
} from '../../../src/channels/whatsapp/whatsapp-identity.mjs';
|
} from '../../../src/channels/whatsapp/whatsapp-identity.mjs';
|
||||||
|
|
||||||
describe('whatsapp-identity', () => {
|
describe('whatsapp-identity', () => {
|
||||||
|
|
||||||
it('resolves self-chat jid to live LID before stored PN', async () => {
|
|
||||||
const accountJid = '8615601877957@s.whatsapp.net';
|
|
||||||
const lid = '111222333444555@lid';
|
|
||||||
assert.equal(await resolveWhatsappSelfChatJid({
|
|
||||||
accountJid,
|
|
||||||
socket: { user: { id: accountJid, lid } },
|
|
||||||
}), lid);
|
|
||||||
assert.equal(await resolveWhatsappSelfChatJid({
|
|
||||||
accountJid,
|
|
||||||
socket: {
|
|
||||||
signalRepository: {
|
|
||||||
lidMapping: {
|
|
||||||
getLIDForPN: async (pn) => (pn === accountJid ? lid : null),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}), lid);
|
|
||||||
assert.equal(await resolveWhatsappSelfChatJid({
|
|
||||||
accountJid,
|
|
||||||
lidPnCache: new Map([['111222333444555', accountJid]]),
|
|
||||||
}), lid);
|
|
||||||
assert.equal(await resolveWhatsappSelfChatJid({ accountJid }), accountJid);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('recognizes lid jids', () => {
|
it('recognizes lid jids', () => {
|
||||||
assert.equal(isWhatsappLidJid('91010910658657@lid'), true);
|
assert.equal(isWhatsappLidJid('91010910658657@lid'), true);
|
||||||
assert.equal(isWhatsappLidJid('8618142387786@s.whatsapp.net'), false);
|
assert.equal(isWhatsappLidJid('8618142387786@s.whatsapp.net'), false);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ import {
|
||||||
OutboundArtifactRegistry,
|
OutboundArtifactRegistry,
|
||||||
createOutboundArtifactTool,
|
createOutboundArtifactTool,
|
||||||
} from '../../../src/channels/shared/semantic/artifact.mjs';
|
} from '../../../src/channels/shared/semantic/artifact.mjs';
|
||||||
import { rememberConnectionTestTarget } from '../../../src/channels/shared/connection-test.mjs';
|
|
||||||
import {
|
import {
|
||||||
WHATSAPP_ACCESS_MODES,
|
WHATSAPP_ACCESS_MODES,
|
||||||
WhatsappConfigStore,
|
WhatsappConfigStore,
|
||||||
|
|
@ -1482,86 +1481,6 @@ test('WhatsApp runtime sends a connection test to self and suppresses its outbou
|
||||||
await runtime.stop();
|
await runtime.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('WhatsApp connection test prefers bound private chat then live LID, never Harness ask', async () => {
|
|
||||||
const sent = [];
|
|
||||||
const accountLid = '987654321098765@lid';
|
|
||||||
const peerJid = '16505550999@s.whatsapp.net';
|
|
||||||
const state = {
|
|
||||||
hasSeen: () => false,
|
|
||||||
markSeen: async () => {},
|
|
||||||
sessionFor: () => 'session-connection-test-bound',
|
|
||||||
sessionExists: async () => true,
|
|
||||||
};
|
|
||||||
rememberConnectionTestTarget(state, { jid: peerJid, selfChat: false });
|
|
||||||
let askCount = 0;
|
|
||||||
const runtime = new WhatsappRuntime({
|
|
||||||
config: linkedConfig(),
|
|
||||||
authDir: '/tmp/test-whatsapp-connection-test-bound',
|
|
||||||
harness: {
|
|
||||||
ensureRunning: async () => {},
|
|
||||||
sessionExists: async () => true,
|
|
||||||
ask: async () => { askCount += 1; return 'unexpected'; },
|
|
||||||
},
|
|
||||||
state,
|
|
||||||
createSession: async () => ({
|
|
||||||
socket: {
|
|
||||||
user: { id: ACCOUNT_JID, lid: accountLid },
|
|
||||||
sendPresenceUpdate: async () => {},
|
|
||||||
readMessages: async () => {},
|
|
||||||
sendMessage: async (jid, content) => {
|
|
||||||
sent.push([jid, content]);
|
|
||||||
return { key: { id: `ct-${sent.length}` } };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ready: Promise.resolve({ accountJid: ACCOUNT_JID, name: 'Harness WhatsApp' }),
|
|
||||||
close: async () => {},
|
|
||||||
logout: async () => {},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
await runtime.start();
|
|
||||||
assert.deepEqual(await runtime.sendConnectionTest('bound probe'), { sent: true });
|
|
||||||
assert.deepEqual(sent, [[peerJid, { text: 'bound probe' }]]);
|
|
||||||
assert.equal(askCount, 0);
|
|
||||||
|
|
||||||
const unbound = {
|
|
||||||
hasSeen: () => false,
|
|
||||||
markSeen: async () => {},
|
|
||||||
sessionFor: () => 'session-connection-test-lid',
|
|
||||||
sessionExists: async () => true,
|
|
||||||
};
|
|
||||||
const lidRuntime = new WhatsappRuntime({
|
|
||||||
config: linkedConfig(),
|
|
||||||
authDir: '/tmp/test-whatsapp-connection-test-lid',
|
|
||||||
harness: {
|
|
||||||
ensureRunning: async () => {},
|
|
||||||
sessionExists: async () => true,
|
|
||||||
ask: async () => { askCount += 1; return 'unexpected'; },
|
|
||||||
},
|
|
||||||
state: unbound,
|
|
||||||
createSession: async () => ({
|
|
||||||
socket: {
|
|
||||||
user: { id: ACCOUNT_JID, lid: accountLid },
|
|
||||||
sendPresenceUpdate: async () => {},
|
|
||||||
readMessages: async () => {},
|
|
||||||
sendMessage: async (jid, content) => {
|
|
||||||
sent.push([jid, content]);
|
|
||||||
return { key: { id: `ct-${sent.length}` } };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ready: Promise.resolve({ accountJid: ACCOUNT_JID, name: 'Harness WhatsApp' }),
|
|
||||||
close: async () => {},
|
|
||||||
logout: async () => {},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
await lidRuntime.start();
|
|
||||||
assert.deepEqual(await lidRuntime.sendConnectionTest('lid probe'), { sent: true });
|
|
||||||
assert.deepEqual(sent.at(-1), [accountLid, { text: 'lid probe' }]);
|
|
||||||
assert.equal(askCount, 0);
|
|
||||||
await runtime.stop();
|
|
||||||
await lidRuntime.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('WhatsApp controller delegates connection test copy to the current runtime', async (t) => {
|
test('WhatsApp controller delegates connection test copy to the current runtime', async (t) => {
|
||||||
const root = await mkdtemp(join(tmpdir(), 'dsh-im-whatsapp-test-message-'));
|
const root = await mkdtemp(join(tmpdir(), 'dsh-im-whatsapp-test-message-'));
|
||||||
const configStore = await new WhatsappConfigStore(join(root, 'config.json')).load();
|
const configStore = await new WhatsappConfigStore(join(root, 'config.json')).load();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue