were missing contacts event

This commit is contained in:
Florent 2025-10-22 23:48:25 +02:00
parent d619423078
commit caabf6dfd9
2 changed files with 61 additions and 21 deletions

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "meshcore" name = "meshcore"
version = "2.1.13" version = "2.1.14"
authors = [ authors = [
{ name="Florent de Lamotte", email="florent@frizoncorrea.fr" }, { name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
{ name="Alex Wolden", email="awolden@gmail.com" }, { name="Alex Wolden", email="awolden@gmail.com" },

View file

@ -1,7 +1,8 @@
import logging import logging
import asyncio
from typing import Optional from typing import Optional
from ..events import Event, EventType from ..events import Event, EventDispatcher, EventType
from .base import CommandHandlerBase, DestinationType, _validate_destination from .base import CommandHandlerBase, DestinationType, _validate_destination
logger = logging.getLogger("meshcore") logger = logging.getLogger("meshcore")
@ -17,26 +18,65 @@ class ContactCommands(CommandHandlerBase):
print("Fetching contacts ", end="", flush=True) print("Fetching contacts ", end="", flush=True)
# wait first event # wait first event
res = await self.send(data) res = await self.send(data)
while True: timeout = 5
# wait next event # Inline wait for events to continue waiting for CONTACTS event
res = await self.wait_for_events( # while receiving NEXT_CONTACTs (or it might be missed over serial)
[EventType.NEXT_CONTACT, EventType.CONTACTS, EventType.ERROR], try:
timeout=5) # Create futures for all expected events
if res is None: # Timeout futures = []
if anim: for event_type in [EventType.ERROR, EventType.NEXT_CONTACT, EventType.CONTACTS] :
future = asyncio.create_task(
self.dispatcher.wait_for_event(event_type, {}, timeout)
)
futures.append(future)
while True:
# Wait for the first event to complete or all to timeout
done, pending = await asyncio.wait(
futures, timeout=timeout, return_when=asyncio.FIRST_COMPLETED
)
# Check if any future completed successfully
if len(done) == 0:
print(" Timeout") print(" Timeout")
return res for future in pending: # cancel all futures
if res.type == EventType.ERROR: future.cancel()
if anim: return None
print(" Error")
return res for future in done:
elif res.type == EventType.CONTACTS: event = await future
if anim:
print(" Done") if event:
return res if event.type == EventType.NEXT_CONTACT:
elif res.type == EventType.NEXT_CONTACT: if anim:
if anim: print(".", end="", flush=True)
print(".", end="", flush=True) else: # Done or Error ... cancel pending and return
if anim:
print(" Done" if event.type == EventType.CONTACTS else " Error")
for future in pending:
future.cancel()
return event
futures = []
for future in pending: # put back pending
futures.append(future)
future = asyncio.create_task( # and recreate NEXT_CONTACT
self.dispatcher.wait_for_event(EventType.NEXT_CONTACT, {}, timeout)
)
futures.append(future)
except asyncio.TimeoutError:
logger.debug(f"Timeout receiving contacts")
if anim:
print(" Timeout")
return None
except Exception as e:
logger.debug(f"Command error: {e}")
if anim:
print(" Error")
return Event(EventType.ERROR, {"error": str(e)})
async def reset_path(self, key: DestinationType) -> Event: async def reset_path(self, key: DestinationType) -> Event:
key_bytes = _validate_destination(key, prefix_length=32) key_bytes = _validate_destination(key, prefix_length=32)