mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-29 21:17:05 +02:00
fix(bluebubbles): move attachment retry before rawBody guard, fix stale log
Move the attachment retry block (2s BB API refetch for empty attachments) before the !rawBody early-return guard. Previously, image-only messages with text='' and attachments=[] would be dropped by the !rawBody check before the retry could fire, making fix #4 dead code for its primary use-case. Now the retry runs first and recomputes the placeholder from resolved attachments so rawBody becomes non-empty when media is found. Also fix stale log message that still said 'without reaction' after the filter was expanded to pass through attachment updates.
This commit is contained in:
@@ -696,7 +696,51 @@ async function processMessageAfterDedupe(
|
||||
|
||||
const text = message.text.trim();
|
||||
let attachments = message.attachments ?? [];
|
||||
let placeholder = buildMessagePlaceholder(message);
|
||||
const baseUrl = normalizeSecretInputString(account.config.serverUrl);
|
||||
const password = normalizeSecretInputString(account.config.password);
|
||||
|
||||
// BlueBubbles may fire the webhook before attachment indexing is complete,
|
||||
// so the initial `attachments` array can be empty for messages that actually
|
||||
// have media. When the message text is empty (image-only) or this is an
|
||||
// `updated-message` event, wait briefly and re-fetch from the BB API as a
|
||||
// fallback for cases where BB doesn't send a follow-up webhook. (#65430, #67437)
|
||||
// This must run before the !rawBody guard below, otherwise image-only messages
|
||||
// with empty attachments are dropped before the retry can fire.
|
||||
const retryMessageId = message.messageId?.trim();
|
||||
const shouldRetryAttachments =
|
||||
attachments.length === 0 &&
|
||||
retryMessageId &&
|
||||
baseUrl &&
|
||||
password &&
|
||||
(text.length === 0 || message.eventType === "updated-message");
|
||||
if (shouldRetryAttachments) {
|
||||
try {
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 2_000));
|
||||
const fetched = await fetchBlueBubblesMessageAttachments(retryMessageId, {
|
||||
baseUrl,
|
||||
password,
|
||||
timeoutMs: 10_000,
|
||||
allowPrivateNetwork: isPrivateNetworkOptInEnabled(account.config),
|
||||
});
|
||||
if (fetched.length > 0) {
|
||||
logVerbose(
|
||||
core,
|
||||
runtime,
|
||||
`attachment retry found ${fetched.length} attachment(s) for msgId=${message.messageId}`,
|
||||
);
|
||||
attachments = fetched;
|
||||
}
|
||||
} catch (err) {
|
||||
logVerbose(
|
||||
core,
|
||||
runtime,
|
||||
`attachment retry failed for msgId=${message.messageId}: ${String(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Recompute placeholder from resolved attachments (may have been updated by retry).
|
||||
const placeholder = buildMessagePlaceholder({ ...message, attachments });
|
||||
// Check if text is a tapback pattern (e.g., 'Loved "hello"') and transform to emoji format
|
||||
// For tapbacks, we'll append [[reply_to:N]] at the end; for regular messages, prepend it
|
||||
const tapbackContext = resolveTapbackContext(message);
|
||||
@@ -1074,9 +1118,6 @@ async function processMessageAfterDedupe(
|
||||
return;
|
||||
}
|
||||
|
||||
const baseUrl = normalizeSecretInputString(account.config.serverUrl);
|
||||
const password = normalizeSecretInputString(account.config.password);
|
||||
|
||||
if (isGroup && !message.participants?.length && baseUrl && password) {
|
||||
try {
|
||||
const fetchedParticipants = await fetchBlueBubblesParticipantsForInboundMessage({
|
||||
@@ -1120,53 +1161,14 @@ async function processMessageAfterDedupe(
|
||||
? account.config.mediaMaxMb * 1024 * 1024
|
||||
: 8 * 1024 * 1024;
|
||||
|
||||
// BlueBubbles may fire the webhook before attachment indexing is complete,
|
||||
// so the initial `attachments` array can be empty for messages that actually
|
||||
// have media. When the message text is empty (image-only) or this is an
|
||||
// `updated-message` event, wait briefly and re-fetch from the BB API as a
|
||||
// fallback for cases where BB doesn't send a follow-up webhook. (#65430, #67437)
|
||||
let resolvedAttachments = attachments;
|
||||
const retryMessageId = message.messageId?.trim();
|
||||
const shouldRetryAttachments =
|
||||
resolvedAttachments.length === 0 &&
|
||||
retryMessageId &&
|
||||
baseUrl &&
|
||||
password &&
|
||||
(text.length === 0 || message.eventType === "updated-message");
|
||||
if (shouldRetryAttachments) {
|
||||
try {
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 2_000));
|
||||
const fetched = await fetchBlueBubblesMessageAttachments(retryMessageId, {
|
||||
baseUrl,
|
||||
password,
|
||||
timeoutMs: 10_000,
|
||||
allowPrivateNetwork: isPrivateNetworkOptInEnabled(account.config),
|
||||
});
|
||||
if (fetched.length > 0) {
|
||||
logVerbose(
|
||||
core,
|
||||
runtime,
|
||||
`attachment retry found ${fetched.length} attachment(s) for msgId=${message.messageId}`,
|
||||
);
|
||||
resolvedAttachments = fetched;
|
||||
}
|
||||
} catch (err) {
|
||||
logVerbose(
|
||||
core,
|
||||
runtime,
|
||||
`attachment retry failed for msgId=${message.messageId}: ${String(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mediaUrls: string[] = [];
|
||||
let mediaPaths: string[] = [];
|
||||
let mediaTypes: string[] = [];
|
||||
if (resolvedAttachments.length > 0) {
|
||||
if (attachments.length > 0) {
|
||||
if (!baseUrl || !password) {
|
||||
logVerbose(core, runtime, "attachment download skipped (missing serverUrl/password)");
|
||||
} else {
|
||||
for (const attachment of resolvedAttachments) {
|
||||
for (const attachment of attachments) {
|
||||
if (!attachment.guid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user