1
0

swaps: handle timeouts in send_direct_message

Adds logic to retry sending a direct message in
`NostrTransport.send_direct_message()` on `TimeoutError`.
Handles `TimeoutError` exception more gracefully by catching it and
returning `None`.
This commit is contained in:
f321x
2025-08-19 14:58:23 +02:00
parent 6ffaa55813
commit 37614e9092

View File

@@ -1567,25 +1567,37 @@ class NostrTransport(SwapServerTransport):
tags = [['d', f'electrum-swapserver-{self.NOSTR_EVENT_VERSION}'], tags = [['d', f'electrum-swapserver-{self.NOSTR_EVENT_VERSION}'],
['r', 'net:' + constants.net.NET_NAME], ['r', 'net:' + constants.net.NET_NAME],
['expiration', str(int(time.time() + self.OFFER_UPDATE_INTERVAL_SEC + 10))]] ['expiration', str(int(time.time() + self.OFFER_UPDATE_INTERVAL_SEC + 10))]]
event_id = await aionostr._add_event( try:
self.relay_manager, event_id = await aionostr._add_event(
kind=self.USER_STATUS_NIP38, self.relay_manager,
tags=tags, kind=self.USER_STATUS_NIP38,
content=json.dumps(offer), tags=tags,
private_key=self.nostr_private_key) content=json.dumps(offer),
self.logger.info(f"published offer {event_id}") private_key=self.nostr_private_key)
self.logger.info(f"published offer {event_id}")
except asyncio.TimeoutError as e:
self.logger.warning(f"failed to publish swap offer: {str(e)}")
async def send_direct_message(self, pubkey: str, content: str) -> str: @ignore_exceptions
@log_exceptions
async def send_direct_message(self, pubkey: str, content: str, retries: int = 0) -> Optional[str]:
assert retries < 25, "Use a sane retry amount"
our_private_key = aionostr.key.PrivateKey(self.private_key) our_private_key = aionostr.key.PrivateKey(self.private_key)
recv_pubkey_hex = aionostr.util.from_nip19(pubkey)['object'].hex() if pubkey.startswith('npub') else pubkey recv_pubkey_hex = aionostr.util.from_nip19(pubkey)['object'].hex() if pubkey.startswith('npub') else pubkey
encrypted_msg = our_private_key.encrypt_message(content, recv_pubkey_hex) encrypted_msg = our_private_key.encrypt_message(content, recv_pubkey_hex)
event_id = await aionostr._add_event( try:
self.relay_manager, event_id = await aionostr._add_event(
kind=self.EPHEMERAL_REQUEST, self.relay_manager,
content=encrypted_msg, kind=self.EPHEMERAL_REQUEST,
private_key=self.nostr_private_key, content=encrypted_msg,
tags=[['p', recv_pubkey_hex]], private_key=self.nostr_private_key,
) tags=[['p', recv_pubkey_hex]],
)
except asyncio.TimeoutError:
self.logger.warning(f"sending message to {pubkey} failed: timeout. {retries=}")
if retries > 0:
return await self.send_direct_message(pubkey, content, retries - 1)
return None
return event_id return event_id
@log_exceptions @log_exceptions
@@ -1593,7 +1605,9 @@ class NostrTransport(SwapServerTransport):
self.logger.debug(f"swapserver req: method: {method} relays: {self.relays}") self.logger.debug(f"swapserver req: method: {method} relays: {self.relays}")
request_data['method'] = method request_data['method'] = method
server_npub = self.config.SWAPSERVER_NPUB server_npub = self.config.SWAPSERVER_NPUB
event_id = await self.send_direct_message(server_npub, json.dumps(request_data)) event_id = await self.send_direct_message(server_npub, json.dumps(request_data), retries=1)
if not event_id:
raise SwapServerError()
response = await self.dm_replies[event_id] response = await self.dm_replies[event_id]
if 'error' in response: if 'error' in response:
self.logger.warning(f"error from swap server [DO NOT TRUST THIS MESSAGE]: {response['error']}") self.logger.warning(f"error from swap server [DO NOT TRUST THIS MESSAGE]: {response['error']}")
@@ -1725,7 +1739,7 @@ class NostrTransport(SwapServerTransport):
"error": str(e)[:100], "error": str(e)[:100],
"reply_to": event.id, "reply_to": event.id,
}) })
await self.send_direct_message(event.pubkey, error_response) await self.taskgroup.spawn(self.send_direct_message(event.pubkey, error_response))
else: else:
self.logger.info(f'unknown message {content}') self.logger.info(f'unknown message {content}')
@@ -1747,7 +1761,7 @@ class NostrTransport(SwapServerTransport):
raise Exception(method) raise Exception(method)
r['reply_to'] = event_id r['reply_to'] = event_id
self.logger.debug(f'sending response id={event_id}') self.logger.debug(f'sending response id={event_id}')
await self.send_direct_message(event_pubkey, json.dumps(r)) await self.taskgroup.spawn(self.send_direct_message(event_pubkey, json.dumps(r), retries=2))
def _store_last_swapserver_relays(self, relays: Sequence[str]): def _store_last_swapserver_relays(self, relays: Sequence[str]):
self._last_swapserver_relays = relays self._last_swapserver_relays = relays