req_neighbours

This commit is contained in:
Florent
2025-11-09 16:51:54 +01:00
parent dea2f74eae
commit 307e517f5e
6 changed files with 155 additions and 6 deletions

View File

@@ -163,7 +163,7 @@ class CommandHandlerBase:
return Event(EventType.OK, {})
# attached at base because its a common method
async def send_binary_req(self, dst: DestinationType, request_type: BinaryReqType, data: Optional[bytes] = None, timeout=None, min_timeout=0) -> Event:
async def send_binary_req(self, dst: DestinationType, request_type: BinaryReqType, data: Optional[bytes] = None, context={}, timeout=None, min_timeout=0) -> Event:
dst_bytes = _validate_destination(dst, prefix_length=32)
pubkey_prefix = _validate_destination(dst, prefix_length=6)
logger.debug(f"Binary request to {dst_bytes.hex()}")
@@ -180,6 +180,6 @@ class CommandHandlerBase:
# Use provided timeout or fallback to suggested timeout (with 5s default)
actual_timeout = timeout if timeout is not None and timeout > 0 else result.payload.get("suggested_timeout", 4000) / 800.0
actual_timeout = min_timeout if actual_timeout < min_timeout else actual_timeout
self._reader.register_binary_request(pubkey_prefix.hex(), exp_tag, request_type, actual_timeout)
self._reader.register_binary_request(pubkey_prefix.hex(), exp_tag, request_type, actual_timeout, context=context)
return result

View File

@@ -1,4 +1,6 @@
import asyncio
import logging
import random
from .base import CommandHandlerBase
from ..events import EventType
@@ -131,3 +133,112 @@ class BinaryCommandHandler(CommandHandlerBase):
)
return acl_event.payload["acl_data"] if acl_event else None
async def req_neighbours_async(self,
contact,
count=255,
offset=0,
order_by=0,
pubkey_prefix_length=4,
timeout=0,
min_timeout=0
):
req = (b"\x00" # version : 0
+ count.to_bytes(1, "little", signed=False)
+ offset.to_bytes(2, "little", signed=False)
+ order_by.to_bytes(1, "little", signed=False)
+ pubkey_prefix_length.to_bytes(1, "little", signed=False)
+ random.randint(1, 0xFFFFFFFF).to_bytes(4, "little", signed=False)
)
logger.debug(f"Sending binary neighbours req, count: {count}, offset: {offset} {req.hex()}")
return await self.send_binary_req (
contact,
BinaryReqType.NEIGHBOURS,
data=req,
timeout=timeout,
context={"pubkey_prefix_length": pubkey_prefix_length}
)
async def req_neighbours_sync(self,
contact,
count=255,
offset=0,
order_by=0,
pubkey_prefix_length=4,
timeout=0,
min_timeout=0
):
res = await self.req_neighbours_async(contact,
count=count,
offset=offset,
order_by=order_by,
pubkey_prefix_length=pubkey_prefix_length,
timeout=timeout,
min_timeout=min_timeout)
if res is None or res.type == EventType.ERROR:
return None
timeout = res.payload["suggested_timeout"] / 800 if timeout == 0 else timeout
timeout = timeout if min_timeout < timeout else min_timeout
if self.dispatcher is None:
return None
# Listen for NEIGHBOUR_RESPONSE
neighbours_event = await self.dispatcher.wait_for_event(
EventType.NEIGHBOURS_RESPONSE,
attribute_filters={"tag": res.payload["expected_ack"].hex()},
timeout=timeout,
)
return neighbours_event.payload if neighbours_event else None
# do several queries if not all neighbours have been obtained
async def fetch_all_neighbours(self,
contact,
order_by=0,
pubkey_prefix_length=4,
timeout=0,
min_timeout=0
):
# Initial request
res = await self.req_neighbours_sync(contact,
count=255,
offset=0,
order_by=order_by,
pubkey_prefix_length=pubkey_prefix_length,
timeout=timeout,
min_timeout=min_timeout)
if res is None:
return None
neighbours_count = res["neighbours_count"] # total neighbours
results_count = res["results_count"] # obtained neighbours
del res["tag"]
while results_count < neighbours_count:
#await asyncio.sleep(2) # wait 2s before next fetch
next_res = await self.req_neighbours_sync(contact,
count=255,
offset=results_count,
order_by=order_by,
pubkey_prefix_length=pubkey_prefix_length,
timeout=timeout,
min_timeout=min_timeout+5) # requests are close, so let's have some more timeout
if next_res is None :
return res # caller should check it has everything
results_count = results_count + next_res["results_count"]
res["results_count"] = results_count
res["neighbours"] += next_res["neighbours"]
return res