Files

59 lines
2.0 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from urllib.parse import urlparse
@dataclass(frozen=True)
class Route:
original: str
normalized: str
transport: str
profile: str
reason: str
def route_url(raw_url: str) -> Route:
path_route = _route_path_address(raw_url)
if path_route:
return path_route
normalized = _normalize_url(raw_url)
parsed = urlparse(normalized)
scheme = parsed.scheme.lower()
host = (parsed.hostname or "").lower()
if scheme == "gemini":
return Route(raw_url, normalized, "gemini", "gemini", "gemini scheme")
if scheme in {"ipfs", "ipns"}:
return Route(raw_url, normalized, "ipfs", "ipfs", f"{scheme} scheme")
if scheme in {"rns", "lxmf", "nomad"}:
return Route(raw_url, normalized, "reticulum", "reticulum", f"{scheme} scheme")
if host.endswith(".onion"):
return Route(raw_url, normalized, "tor", "tor", ".onion host")
if host.endswith(".i2p"):
return Route(raw_url, normalized, "i2p", "i2p", ".i2p host")
if scheme in {"http", "https"}:
return Route(raw_url, normalized, "clearnet", "clearnet", "http(s) URL")
return Route(raw_url, normalized, "unknown", "unknown", "no route rule matched")
def _normalize_url(raw_url: str) -> str:
value = raw_url.strip()
if "://" not in value and not value.startswith(("rns:", "lxmf:", "ipfs:", "ipns:")):
value = "https://" + value
return value
def _route_path_address(raw_url: str) -> Route | None:
value = raw_url.strip()
if value.startswith("/ipfs/"):
cid = value.removeprefix("/ipfs/").strip("/")
normalized = f"ipfs://{cid}" if cid else "ipfs://"
return Route(raw_url, normalized, "ipfs", "ipfs", "/ipfs path")
if value.startswith("/ipns/"):
name = value.removeprefix("/ipns/").strip("/")
normalized = f"ipns://{name}" if name else "ipns://"
return Route(raw_url, normalized, "ipfs", "ipfs", "/ipns path")
return None