From ef2991a117c45277915d0e3f589f53c50cc9828f Mon Sep 17 00:00:00 2001 From: archipelago Date: Tue, 16 Jun 2026 09:42:51 -0400 Subject: [PATCH] fix(chat): send Archipelago(Tor) group messages concurrently so 'sending' clears fast (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sendArchMessage looped over every federation node sequentially (await sendMessageToPeer per node), so the spinner stayed up until the slowest/offline node's Tor request finished — long after online peers had received the message. Send to all peers concurrently (Promise.allSettled); the spinner now clears after the slowest single delivery, not the sum. Co-Authored-By: Claude Opus 4.8 (1M context) --- neode-ui/src/views/Mesh.vue | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/neode-ui/src/views/Mesh.vue b/neode-ui/src/views/Mesh.vue index acc7dfb0..3a6e6dbb 100644 --- a/neode-ui/src/views/Mesh.vue +++ b/neode-ui/src/views/Mesh.vue @@ -183,16 +183,24 @@ async function sendArchMessage() { selfOnion = tor.tor_address } catch { /* non-fatal */ } const msg = messageText.value.trim() - let sent = 0 - for (const node of nodes.nodes) { - const nodeOnion = node.onion || node.did - // Skip sending to ourselves (would create duplicate received message) - if (selfOnion && (nodeOnion === selfOnion || nodeOnion === selfOnion.replace('.onion', '') || selfOnion === nodeOnion + '.onion')) continue - try { - await rpcClient.sendMessageToPeer(nodeOnion, msg) - sent++ - } catch { /* some peers may be offline */ } - } + const targets = nodes.nodes + .map((node) => node.onion || node.did) + // Skip sending to ourselves (would create a duplicate received message). + .filter( + (nodeOnion) => + !(selfOnion && + (nodeOnion === selfOnion || + nodeOnion === selfOnion.replace('.onion', '') || + selfOnion === nodeOnion + '.onion')) + ) + // Send to all peers CONCURRENTLY so the spinner clears after the slowest + // single delivery (one Tor round-trip) rather than the sum of all of them — + // previously a slow or offline node kept the "sending" spinner up long after + // the online peers had already received the message. + const results = await Promise.allSettled( + targets.map((nodeOnion) => rpcClient.sendMessageToPeer(nodeOnion, msg)) + ) + const sent = results.filter((r) => r.status === 'fulfilled').length try { await rpcClient.call({ method: 'node-store-sent', params: { message: msg } }) } catch { /* non-fatal */ }