elo-node 0.4.4__tar.gz → 0.4.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {elo_node-0.4.4 → elo_node-0.4.5}/PKG-INFO +1 -1
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/node.py +49 -26
- {elo_node-0.4.4 → elo_node-0.4.5}/elo_node.egg-info/PKG-INFO +1 -1
- {elo_node-0.4.4 → elo_node-0.4.5}/elo_node.egg-info/SOURCES.txt +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo_node.egg-info/dependency_links.txt +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo_node.egg-info/requires.txt +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo_node.egg-info/top_level.txt +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/pyproject.toml +1 -1
- {elo_node-0.4.4 → elo_node-0.4.5}/README.md +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/__init__.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/__main__.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/security.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/transport/__init__.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/transport/protocol.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/transport/routing.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/transport/tcp.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/transport/tracker.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo/types.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/elo_node.egg-info/entry_points.txt +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/setup.cfg +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/tests/test_security.py +0 -0
- {elo_node-0.4.4 → elo_node-0.4.5}/tests/test_unit.py +0 -0
|
@@ -78,7 +78,7 @@ class Node:
|
|
|
78
78
|
peers: list[str] | None = None,
|
|
79
79
|
tracker: str = "public",
|
|
80
80
|
allowlist: list[str] | None = None,
|
|
81
|
-
version: str = "0.4.
|
|
81
|
+
version: str = "0.4.5",
|
|
82
82
|
identity: EphemeralIdentity | None = None,
|
|
83
83
|
verify_peers: bool = True,
|
|
84
84
|
heartbeat_interval_s: int = 30,
|
|
@@ -110,7 +110,7 @@ class Node:
|
|
|
110
110
|
self._task_handler: Callable[[Task], Awaitable[dict[str, Any]]] | None = None
|
|
111
111
|
self._shutdown_event = asyncio.Event()
|
|
112
112
|
self._pending_results: dict[str, asyncio.Future] = {}
|
|
113
|
-
self._pending_queries: dict[str, tuple[asyncio.
|
|
113
|
+
self._pending_queries: dict[str, tuple[list[dict[str, Any]], asyncio.Event, float]] = {}
|
|
114
114
|
|
|
115
115
|
# Cache de pubkeys para verificação de assinatura
|
|
116
116
|
self._pubkey_cache: dict[str, tuple[Any, float]] = {}
|
|
@@ -330,34 +330,41 @@ class Node:
|
|
|
330
330
|
return await self.get_known_peers_local()
|
|
331
331
|
|
|
332
332
|
async def discover_peers_network(self, timeout: float = 5.0) -> list[dict[str, Any]]:
|
|
333
|
-
"""Discover peers on the network via QUERY broadcast
|
|
333
|
+
"""Discover peers on the network via QUERY broadcast.
|
|
334
334
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
Args:
|
|
339
|
-
timeout: seconds to wait for responses (default 5.0)
|
|
340
|
-
|
|
341
|
-
Returns:
|
|
342
|
-
List of dicts with 'addr' and optionally 'node_id'
|
|
335
|
+
Envia QUERY com capability vazia e agrega todas as respostas
|
|
336
|
+
dentro do timeout. Modelo BitTorrent: o tracker retorna todos
|
|
337
|
+
os peers conhecidos, não só quem matcha a capability.
|
|
343
338
|
"""
|
|
344
339
|
query_id = str(uuid.uuid4())[:8]
|
|
345
|
-
|
|
346
|
-
|
|
340
|
+
collected: list[dict[str, Any]] = []
|
|
341
|
+
event = asyncio.Event()
|
|
342
|
+
self._pending_queries[query_id] = (collected, event, time.time())
|
|
347
343
|
discovered: dict[str, dict[str, Any]] = {}
|
|
348
344
|
|
|
349
345
|
# Broadcast QUERY for any capability
|
|
350
346
|
await self._tcp.broadcast(query_msg("", query_id, ttl=3))
|
|
351
347
|
|
|
352
348
|
try:
|
|
353
|
-
|
|
354
|
-
if result_addr:
|
|
355
|
-
discovered[result_addr] = {"addr": result_addr, "connected": False, "caps": [], "via": "network"}
|
|
349
|
+
await asyncio.wait_for(event.wait(), timeout=timeout)
|
|
356
350
|
except asyncio.TimeoutError:
|
|
357
351
|
pass
|
|
358
352
|
finally:
|
|
359
353
|
self._pending_queries.pop(query_id, None)
|
|
360
354
|
|
|
355
|
+
# Merge collected peers from all responses
|
|
356
|
+
known_addrs: set[str] = set()
|
|
357
|
+
for entry in collected:
|
|
358
|
+
addr = entry.get("addr", "")
|
|
359
|
+
if addr and addr not in discovered:
|
|
360
|
+
discovered[addr] = {
|
|
361
|
+
"addr": addr,
|
|
362
|
+
"caps": entry.get("caps", []),
|
|
363
|
+
"connected": False,
|
|
364
|
+
"via": "network",
|
|
365
|
+
}
|
|
366
|
+
known_addrs.add(addr)
|
|
367
|
+
|
|
361
368
|
# Merge with locally known peers
|
|
362
369
|
local = await self.get_known_peers_local()
|
|
363
370
|
for entry in local:
|
|
@@ -460,12 +467,23 @@ class Node:
|
|
|
460
467
|
capability = msg.get("capability", "")
|
|
461
468
|
query_id = msg.get("id", "")
|
|
462
469
|
ttl = msg.get("ttl", 5)
|
|
463
|
-
nodes = []
|
|
470
|
+
nodes: list[dict[str, Any]] = []
|
|
471
|
+
|
|
472
|
+
# Modelo BitTorrent: tracker retorna SEMPRE todos os peers conhecidos,
|
|
473
|
+
# não só quem matcha a capability. Isso permite que qualquer nó
|
|
474
|
+
# descubra a mesh completa com discover_peers_network().
|
|
475
|
+
for addr in self._routing.known_peers:
|
|
476
|
+
info = self._routing.get_peer_caps(addr)
|
|
477
|
+
if addr != peer_addr:
|
|
478
|
+
nodes.append({
|
|
479
|
+
"addr": addr,
|
|
480
|
+
"caps": list(info.get("caps", set())),
|
|
481
|
+
})
|
|
482
|
+
|
|
464
483
|
if self._tracker.has_capability(capability):
|
|
465
484
|
# Usa peer_addr (addr real do TCP) em vez de localhost — necessário para WAN/Tailscale
|
|
466
485
|
nodes.append({"node_id": self._node_id[:12], "addr": peer_addr})
|
|
467
|
-
|
|
468
|
-
nodes.append({"addr": p})
|
|
486
|
+
|
|
469
487
|
if nodes:
|
|
470
488
|
try:
|
|
471
489
|
await self._tcp.send_to(peer_addr, query_resp_msg(query_id, nodes))
|
|
@@ -477,10 +495,11 @@ class Node:
|
|
|
477
495
|
async def _on_query_resp(self, peer_addr: str, msg: dict) -> None:
|
|
478
496
|
query_id = msg.get("id", "")
|
|
479
497
|
if query_id in self._pending_queries:
|
|
480
|
-
|
|
498
|
+
collected, event, _ts = self._pending_queries[query_id]
|
|
481
499
|
nodes = msg.get("nodes", [])
|
|
482
|
-
if nodes
|
|
483
|
-
|
|
500
|
+
if nodes:
|
|
501
|
+
collected.extend(nodes)
|
|
502
|
+
event.set()
|
|
484
503
|
|
|
485
504
|
async def _on_interest_update(self, peer_addr: str, msg: dict) -> None:
|
|
486
505
|
existing = self._routing.get_peer_caps(peer_addr)
|
|
@@ -609,15 +628,19 @@ class Node:
|
|
|
609
628
|
async def _query_capability(self, capability: str, ttl: int = 5,
|
|
610
629
|
timeout: float = 5.0) -> str | None:
|
|
611
630
|
query_id = str(uuid.uuid4())[:8]
|
|
612
|
-
|
|
613
|
-
|
|
631
|
+
collected: list[dict[str, Any]] = []
|
|
632
|
+
event = asyncio.Event()
|
|
633
|
+
self._pending_queries[query_id] = (collected, event, time.time())
|
|
614
634
|
await self._tcp.broadcast(query_msg(capability, query_id, ttl))
|
|
615
635
|
try:
|
|
616
|
-
|
|
636
|
+
await asyncio.wait_for(event.wait(), timeout=timeout)
|
|
617
637
|
except asyncio.TimeoutError:
|
|
618
|
-
|
|
638
|
+
pass
|
|
619
639
|
finally:
|
|
620
640
|
self._pending_queries.pop(query_id, None)
|
|
641
|
+
if collected:
|
|
642
|
+
return collected[0].get("addr", None)
|
|
643
|
+
return None
|
|
621
644
|
|
|
622
645
|
async def _get_caller_pubkey(self, node_id: str) -> Any | None:
|
|
623
646
|
now = time.time()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|