make sure we don't do unecessary auth
This commit is contained in:
parent
cece602768
commit
28f2d081a0
1 changed files with 55 additions and 48 deletions
93
publish.py
93
publish.py
|
|
@ -4,6 +4,9 @@ Fetch ICS + RSS events from do.basspistol.org and publish them as
|
||||||
NIP-52 calendar events (kind 31923) to Nostr relays, requesting
|
NIP-52 calendar events (kind 31923) to Nostr relays, requesting
|
||||||
inclusion in a kind 31924 calendar.
|
inclusion in a kind 31924 calendar.
|
||||||
|
|
||||||
|
Only relays that accept the event kind without requiring NIP-42 auth
|
||||||
|
are used. Relays that send an AUTH challenge are skipped.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
publish.py # normal run
|
publish.py # normal run
|
||||||
publish.py --dry-run # log what would be published, no DB writes, no relay calls
|
publish.py --dry-run # log what would be published, no DB writes, no relay calls
|
||||||
|
|
@ -116,7 +119,6 @@ def ics_str(component: dict, key: str) -> str:
|
||||||
raw = str(val)
|
raw = str(val)
|
||||||
else:
|
else:
|
||||||
raw = str(val)
|
raw = str(val)
|
||||||
# Undo ICS text escaping: \, \; \n \\
|
|
||||||
raw = (
|
raw = (
|
||||||
raw.replace("\\,", ",")
|
raw.replace("\\,", ",")
|
||||||
.replace("\\;", ";")
|
.replace("\\;", ";")
|
||||||
|
|
@ -267,44 +269,53 @@ def make_calendar_event_nostr(cfg, pubkey_hex, title, start, end, location, url,
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Relay diagnostics
|
# Relay filtering
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def wait_for_relays(relay_manager, timeout: float = 10.0) -> bool:
|
def filter_relays_without_auth(relays: list[str], timeout: float = 8.0) -> list[str]:
|
||||||
"""Wait until all relays report connected=True, or timeout elapses.
|
"""Probe each relay for an AUTH challenge on connect.
|
||||||
|
|
||||||
Returns True if all connected, False otherwise.
|
Returns the list of relays that did NOT send AUTH within the timeout.
|
||||||
|
Relays that sent AUTH are logged and excluded.
|
||||||
"""
|
"""
|
||||||
|
accepted = []
|
||||||
|
for url in relays:
|
||||||
|
rm = RelayManager(timeout=timeout)
|
||||||
|
rm.add_relay(url)
|
||||||
|
log.info("Probing %s for AUTH requirement …", url)
|
||||||
|
|
||||||
|
# Give the relay a moment to connect and (maybe) send AUTH.
|
||||||
deadline = time.time() + timeout
|
deadline = time.time() + timeout
|
||||||
|
saw_auth = False
|
||||||
while time.time() < deadline:
|
while time.time() < deadline:
|
||||||
states = {url: r.connected for url, r in relay_manager.relays.items()}
|
relay = rm.relays.get(url)
|
||||||
if states and all(states.values()):
|
if relay is None:
|
||||||
log.info("All relays connected: %s", states)
|
break
|
||||||
return True
|
|
||||||
time.sleep(0.25)
|
|
||||||
|
|
||||||
states = {url: r.connected for url, r in relay_manager.relays.items()}
|
|
||||||
log.warning("Timed out waiting for relays. States: %s", states)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def log_relay_states(relay_manager):
|
|
||||||
"""Log connected state and any messages the relays sent back."""
|
|
||||||
for url, relay in relay_manager.relays.items():
|
|
||||||
log.info("Relay %s — connected=%s", url, relay.connected)
|
|
||||||
pool = getattr(relay, "message_pool", None)
|
pool = getattr(relay, "message_pool", None)
|
||||||
if pool is None:
|
queue = getattr(pool, "queue", None) if pool else None
|
||||||
continue
|
if queue:
|
||||||
queue = getattr(pool, "queue", None)
|
|
||||||
if not queue:
|
|
||||||
continue
|
|
||||||
while queue:
|
while queue:
|
||||||
msg = queue.pop(0)
|
msg = queue.pop(0)
|
||||||
|
if isinstance(msg, list) and len(msg) >= 1 and msg[0] == "AUTH":
|
||||||
|
log.info("Relay %s requires AUTH — skipping.", url)
|
||||||
|
saw_auth = True
|
||||||
|
break
|
||||||
|
if saw_auth:
|
||||||
|
break
|
||||||
|
time.sleep(0.25)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
log.info(" %s: %s", url, msg)
|
rm.close_all_relay_connections()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if not saw_auth:
|
||||||
|
log.info("Relay %s does not require AUTH — will publish.", url)
|
||||||
|
accepted.append(url)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
return accepted
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Main
|
# Main
|
||||||
|
|
@ -330,7 +341,7 @@ def main():
|
||||||
pubkey_hex = pk.public_key.hex()
|
pubkey_hex = pk.public_key.hex()
|
||||||
|
|
||||||
log.info("Using pubkey %s", pubkey_hex)
|
log.info("Using pubkey %s", pubkey_hex)
|
||||||
log.info("Relays: %s", ", ".join(relays))
|
log.info("Configured relays: %s", ", ".join(relays))
|
||||||
log.info("rss_only=%s", rss_only)
|
log.info("rss_only=%s", rss_only)
|
||||||
|
|
||||||
log.info("Fetching ICS …")
|
log.info("Fetching ICS …")
|
||||||
|
|
@ -410,6 +421,14 @@ def main():
|
||||||
log.info("Publishing %d new/changed events (skipped %d unchanged, %d without RSS)",
|
log.info("Publishing %d new/changed events (skipped %d unchanged, %d without RSS)",
|
||||||
len(to_publish), skipped, skipped_no_rss)
|
len(to_publish), skipped, skipped_no_rss)
|
||||||
|
|
||||||
|
# --- Filter relays: skip any that require AUTH ------------------------
|
||||||
|
accepted_relays = filter_relays_without_auth(relays)
|
||||||
|
if not accepted_relays:
|
||||||
|
log.error("No relays accept publishing without AUTH. Aborting.")
|
||||||
|
return
|
||||||
|
|
||||||
|
log.info("Publishing to: %s", ", ".join(accepted_relays))
|
||||||
|
|
||||||
# Build the full set of d-tags the calendar should reference:
|
# Build the full set of d-tags the calendar should reference:
|
||||||
# everything already in the DB, plus everything about to be published.
|
# everything already in the DB, plus everything about to be published.
|
||||||
rows = conn.execute("SELECT d_tag FROM published").fetchall()
|
rows = conn.execute("SELECT d_tag FROM published").fetchall()
|
||||||
|
|
@ -423,34 +442,22 @@ def main():
|
||||||
cal_ev = make_calendar_event(cfg, pubkey_hex, all_d_tags)
|
cal_ev = make_calendar_event(cfg, pubkey_hex, all_d_tags)
|
||||||
cal_ev.sign(pk.hex())
|
cal_ev.sign(pk.hex())
|
||||||
|
|
||||||
# Open relay connections and wait until they're actually connected
|
# --- Publish ----------------------------------------------------------
|
||||||
# before pushing messages over them.
|
relay_manager = RelayManager(timeout=5)
|
||||||
relay_manager = RelayManager(timeout=30)
|
for r in accepted_relays:
|
||||||
for r in relays:
|
|
||||||
relay_manager.add_relay(r)
|
relay_manager.add_relay(r)
|
||||||
|
|
||||||
if not wait_for_relays(relay_manager, timeout=10.0):
|
|
||||||
log.warning("Proceeding despite not all relays being connected.")
|
|
||||||
|
|
||||||
# Publish the calendar FIRST so it isn't stuck behind a queue of events.
|
|
||||||
# Relays don't enforce ordering between an `a` reference and the event
|
|
||||||
# it points to; clients resolve references when they query.
|
|
||||||
relay_manager.publish_event(cal_ev)
|
relay_manager.publish_event(cal_ev)
|
||||||
log.info("Queued calendar kind 31924 (d=%s) referencing %d events",
|
log.info("Queued calendar kind 31924 (d=%s) referencing %d events",
|
||||||
cfg["calendar"]["d"], len(all_d_tags))
|
cfg["calendar"]["d"], len(all_d_tags))
|
||||||
|
|
||||||
# Then publish the events.
|
|
||||||
for d_tag, chash, ev in to_publish:
|
for d_tag, chash, ev in to_publish:
|
||||||
ev.sign(pk.hex())
|
ev.sign(pk.hex())
|
||||||
relay_manager.publish_event(ev)
|
relay_manager.publish_event(ev)
|
||||||
log.info("Queued event %s — %s", d_tag, ev.content.split("\n", 1)[0])
|
log.info("Queued event %s — %s", d_tag, ev.content.split("\n", 1)[0])
|
||||||
|
|
||||||
relay_manager.run_sync()
|
relay_manager.run_sync()
|
||||||
time.sleep(10)
|
time.sleep(2)
|
||||||
|
|
||||||
# Show what the relays said before we tear down the connections.
|
|
||||||
log_relay_states(relay_manager)
|
|
||||||
|
|
||||||
relay_manager.close_all_relay_connections()
|
relay_manager.close_all_relay_connections()
|
||||||
|
|
||||||
for d_tag, chash, ev in to_publish:
|
for d_tag, chash, ev in to_publish:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue