Files
Browser/ren_browser/pages/page_request.py
2025-09-22 13:55:52 -05:00

98 lines
2.7 KiB
Python

"""Page fetching functionality for Ren Browser.
Handles downloading pages from the Reticulum network using
the nomadnetwork protocol.
"""
import threading
import time
from dataclasses import dataclass
import RNS
@dataclass
class PageRequest:
"""Represents a request for a page from the Reticulum network.
Contains the destination hash, page path, and optional field data.
"""
destination_hash: str
page_path: str
field_data: dict | None = None
class PageFetcher:
"""Fetcher to download pages from the Reticulum network."""
def __init__(self):
"""Initialize the page fetcher and Reticulum connection."""
# RNS should already be initialized by main app
@staticmethod
def fetch_page(req: PageRequest) -> str:
"""Download page content for the given PageRequest.
Args:
req: PageRequest containing destination and path information.
Returns:
str: The downloaded page content.
Raises:
Exception: If no path to destination or identity not found.
"""
RNS.log(
f"PageFetcher: starting fetch of {req.page_path} from {req.destination_hash}"
)
dest_bytes = bytes.fromhex(req.destination_hash)
if not RNS.Transport.has_path(dest_bytes):
RNS.Transport.request_path(dest_bytes)
start = time.time()
while not RNS.Transport.has_path(dest_bytes):
if time.time() - start > 30:
raise Exception(f"No path to destination {req.destination_hash}")
time.sleep(0.1)
identity = RNS.Identity.recall(dest_bytes)
if not identity:
raise Exception("Identity not found")
destination = RNS.Destination(
identity,
RNS.Destination.OUT,
RNS.Destination.SINGLE,
"nomadnetwork",
"node",
)
link = RNS.Link(destination)
result = {"data": None}
ev = threading.Event()
def on_response(receipt):
data = receipt.response
if isinstance(data, bytes):
result["data"] = data.decode("utf-8")
else:
result["data"] = str(data)
ev.set()
def on_failed(_):
ev.set()
link.set_link_established_callback(
lambda link: link.request(
req.page_path,
req.field_data,
response_callback=on_response,
failed_callback=on_failed,
)
)
ev.wait(timeout=15)
data_str = result["data"] or "No content received"
RNS.log(
f"PageFetcher: received data for {req.destination_hash}:{req.page_path}"
)
return data_str