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 */ }