fix: iteration race, NID bounds check, and DRY delay parsing
gossip: _poll_loop_once iterated self.rids directly while _discover_rids could append to it from the same call — replaced with list(self.rids) snapshot to avoid RuntimeError on concurrent modification. gossip: _on_announce was missing the nid_len bounds clamp that bridge.py has, allowing a malformed truncated packet to slice beyond available bytes. Now consistent with bridge.py: nid_len = min(nid_len, available). cli: announce_retry_delays string→tuple parsing was copy-pasted three times across cmd_gossip, cmd_seed, and cmd_bridge. Extracted to _parse_delays(). cmd_seed now validates delays before starting any processes so it never needs to stop a running seed just to report a bad argument. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2ab81b525f
commit
05dc078f31
|
|
@ -49,6 +49,14 @@ def detect_radicle_nid() -> Optional[str]:
|
|||
return None
|
||||
|
||||
|
||||
def _parse_delays(s: str) -> Tuple[int, ...]:
|
||||
try:
|
||||
return tuple(int(x.strip()) for x in s.split(",") if x.strip())
|
||||
except ValueError:
|
||||
print("Error: --announce-retry-delays must be comma-separated integers.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def on_peer_discovered(peer: PeerInfo):
|
||||
"""Callback when a new peer is discovered."""
|
||||
print(f"[+] Discovered peer: {peer.identity.did}")
|
||||
|
|
@ -257,13 +265,7 @@ def cmd_gossip(args):
|
|||
if nid:
|
||||
print(f"Local NID: {nid}")
|
||||
|
||||
try:
|
||||
announce_retry_delays = tuple(
|
||||
int(x.strip()) for x in args.announce_retry_delays.split(",") if x.strip()
|
||||
)
|
||||
except ValueError:
|
||||
print("Error: --announce-retry-delays must be comma-separated integers.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
announce_retry_delays = _parse_delays(args.announce_retry_delays)
|
||||
|
||||
relay = GossipRelay(
|
||||
identity=identity,
|
||||
|
|
@ -318,6 +320,9 @@ def cmd_seed(args):
|
|||
"""Start a dedicated seed radicle-node, bridge, and gossip relay."""
|
||||
seed_home = Path(args.seed_home)
|
||||
|
||||
# Validate args before starting any processes
|
||||
announce_retry_delays = _parse_delays(args.announce_retry_delays)
|
||||
|
||||
seed = SeedNode(seed_home=seed_home, port=args.seed_port)
|
||||
|
||||
# First-time setup: guide the user
|
||||
|
|
@ -345,19 +350,9 @@ def cmd_seed(args):
|
|||
seed.stop()
|
||||
sys.exit(1)
|
||||
|
||||
# Start bridge pointing at the seed
|
||||
identity = RadicleIdentity.load_or_generate(args.identity)
|
||||
_print_identity_info(args.identity)
|
||||
|
||||
try:
|
||||
announce_retry_delays = tuple(
|
||||
int(x.strip()) for x in args.announce_retry_delays.split(",") if x.strip()
|
||||
)
|
||||
except ValueError:
|
||||
print("Error: --announce-retry-delays must be comma-separated integers.", file=sys.stderr)
|
||||
seed.stop()
|
||||
sys.exit(1)
|
||||
|
||||
bridge = RadicleBridge(
|
||||
identity=identity,
|
||||
listen_port=args.bridge_port,
|
||||
|
|
@ -452,13 +447,7 @@ def cmd_bridge(args):
|
|||
auto_connect = not args.no_auto_connect and not args.connect
|
||||
auto_seed = not args.no_auto_seed
|
||||
|
||||
try:
|
||||
announce_retry_delays = tuple(
|
||||
int(x.strip()) for x in args.announce_retry_delays.split(",") if x.strip()
|
||||
)
|
||||
except ValueError:
|
||||
print("Error: --announce-retry-delays must be comma-separated integers, e.g. 5,15,30", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
announce_retry_delays = _parse_delays(args.announce_retry_delays)
|
||||
|
||||
bridge = RadicleBridge(
|
||||
identity=identity,
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ class GossipRelay:
|
|||
if self.auto_discover:
|
||||
self._discover_rids()
|
||||
|
||||
for rid in self.rids:
|
||||
for rid in list(self.rids): # snapshot: _discover_rids may append mid-iteration
|
||||
try:
|
||||
refs = _read_refs(self.storage, rid)
|
||||
with self._refs_lock:
|
||||
|
|
@ -414,8 +414,9 @@ class GossipRelay:
|
|||
try:
|
||||
offset = len(GOSSIP_MAGIC)
|
||||
nid_len = struct.unpack("!H", app_data[offset:offset + 2])[0]
|
||||
raw = app_data[offset + 2: offset + 2 + nid_len]
|
||||
radicle_nid = raw.decode() or None
|
||||
offset += 2
|
||||
nid_len = min(nid_len, len(app_data) - offset)
|
||||
radicle_nid = app_data[offset:offset + nid_len].decode() or None
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue