mirror of
https://github.com/meshcore-dev/meshcore_py.git
synced 2026-06-16 23:08:14 +00:00
timeout for each contact in get_contacts
This commit is contained in:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "meshcore"
|
||||
version = "2.1.12"
|
||||
version = "2.1.13"
|
||||
authors = [
|
||||
{ name="Florent de Lamotte", email="florent@frizoncorrea.fr" },
|
||||
{ name="Alex Wolden", email="awolden@gmail.com" },
|
||||
|
||||
@@ -80,36 +80,11 @@ class CommandHandlerBase:
|
||||
)-> None:
|
||||
self._get_contact_by_prefix = func
|
||||
|
||||
async def send(
|
||||
async def wait_for_events(
|
||||
self,
|
||||
data: bytes,
|
||||
expected_events: Optional[Union[EventType, List[EventType]]] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> Event:
|
||||
"""
|
||||
Send a command and wait for expected event responses.
|
||||
|
||||
Args:
|
||||
data: The data to send
|
||||
expected_events: EventType or list of EventTypes to wait for
|
||||
timeout: Timeout in seconds, or None to use default_timeout
|
||||
|
||||
Returns:
|
||||
Event: The full event object that was received in response to the command
|
||||
"""
|
||||
if not self.dispatcher:
|
||||
raise RuntimeError("Dispatcher not set, cannot send commands")
|
||||
|
||||
# Use the provided timeout or fall back to default_timeout
|
||||
timeout = timeout if timeout is not None else self.default_timeout
|
||||
|
||||
if self._sender_func:
|
||||
logger.debug(
|
||||
f"Sending raw data: {data.hex() if isinstance(data, bytes) else data}"
|
||||
)
|
||||
await self._sender_func(data)
|
||||
|
||||
if expected_events:
|
||||
try:
|
||||
# Convert single event to list if needed
|
||||
if not isinstance(expected_events, list):
|
||||
@@ -148,7 +123,43 @@ class CommandHandlerBase:
|
||||
except Exception as e:
|
||||
logger.debug(f"Command error: {e}")
|
||||
return Event(EventType.ERROR, {"error": str(e)})
|
||||
|
||||
return Event(EventType.ERROR, {})
|
||||
|
||||
|
||||
async def send(
|
||||
self,
|
||||
data: bytes,
|
||||
expected_events: Optional[Union[EventType, List[EventType]]] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> Event:
|
||||
"""
|
||||
Send a command and wait for expected event responses.
|
||||
|
||||
Args:
|
||||
data: The data to send
|
||||
expected_events: EventType or list of EventTypes to wait for
|
||||
timeout: Timeout in seconds, or None to use default_timeout
|
||||
|
||||
Returns:
|
||||
Event: The full event object that was received in response to the command
|
||||
"""
|
||||
if not self.dispatcher:
|
||||
raise RuntimeError("Dispatcher not set, cannot send commands")
|
||||
|
||||
# Use the provided timeout or fall back to default_timeout
|
||||
timeout = timeout if timeout is not None else self.default_timeout
|
||||
|
||||
if self._sender_func:
|
||||
logger.debug(
|
||||
f"Sending raw data: {data.hex() if isinstance(data, bytes) else data}"
|
||||
)
|
||||
await self._sender_func(data)
|
||||
|
||||
if expected_events:
|
||||
# For commands that don't expect events, return a success event
|
||||
return await self.wait_for_events(expected_events, timeout)
|
||||
|
||||
return Event(EventType.OK, {})
|
||||
|
||||
# attached at base because its a common method
|
||||
|
||||
@@ -8,12 +8,35 @@ logger = logging.getLogger("meshcore")
|
||||
|
||||
|
||||
class ContactCommands(CommandHandlerBase):
|
||||
async def get_contacts(self, lastmod=0) -> Event:
|
||||
async def get_contacts(self, lastmod=0, anim=False) -> Event:
|
||||
logger.debug("Getting contacts")
|
||||
data = b"\x04"
|
||||
if lastmod > 0:
|
||||
data = data + lastmod.to_bytes(4, "little")
|
||||
return await self.send(data, [EventType.CONTACTS, EventType.ERROR], timeout=30)
|
||||
if anim:
|
||||
print("Fetching contacts ", end="", flush=True)
|
||||
# wait first event
|
||||
res = await self.send(data)
|
||||
while True:
|
||||
# wait next event
|
||||
res = await self.wait_for_events(
|
||||
[EventType.NEXT_CONTACT, EventType.CONTACTS, EventType.ERROR],
|
||||
timeout=5)
|
||||
if res is None: # Timeout
|
||||
if anim:
|
||||
print(" Timeout")
|
||||
return res
|
||||
if res.type == EventType.ERROR:
|
||||
if anim:
|
||||
print(" Error")
|
||||
return res
|
||||
elif res.type == EventType.CONTACTS:
|
||||
if anim:
|
||||
print(" Done")
|
||||
return res
|
||||
elif res.type == EventType.NEXT_CONTACT:
|
||||
if anim:
|
||||
print(".", end="", flush=True)
|
||||
|
||||
async def reset_path(self, key: DestinationType) -> Event:
|
||||
key_bytes = _validate_destination(key, prefix_length=32)
|
||||
|
||||
@@ -21,6 +21,7 @@ class EventType(Enum):
|
||||
DEVICE_INFO = "device_info"
|
||||
MSG_SENT = "message_sent"
|
||||
NEW_CONTACT = "new_contact"
|
||||
NEXT_CONTACT = "next_contact"
|
||||
|
||||
# Push notifications
|
||||
ADVERTISEMENT = "advertisement"
|
||||
|
||||
@@ -99,6 +99,7 @@ class MessageReader:
|
||||
if packet_type_value == PacketType.PUSH_CODE_NEW_ADVERT.value:
|
||||
await self.dispatcher.dispatch(Event(EventType.NEW_CONTACT, c))
|
||||
else:
|
||||
await self.dispatcher.dispatch(Event(EventType.NEXT_CONTACT, c))
|
||||
self.contacts[c["public_key"]] = c
|
||||
|
||||
elif packet_type_value == PacketType.CONTACT_END.value:
|
||||
|
||||
Reference in New Issue
Block a user