mirror of
https://github.com/Such-Software/adaptive-multi-protocol-gateway.git
synced 2026-10-17 07:31:32 +02:00
124 lines
3.8 KiB
Python
124 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from .config import GatewayConfig, SiteConfig
|
|
from .manifest import fixture_manifest
|
|
from .preview import preview_endpoints, preview_fixture_manifest
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class HealthCheck:
|
|
site_id: str
|
|
protocol: str
|
|
mode: str
|
|
url: str
|
|
output_root: Path
|
|
output_path: str
|
|
transport: str
|
|
profile: str
|
|
address_status: str
|
|
route: str
|
|
status: str
|
|
action: str
|
|
command: str
|
|
message: str
|
|
|
|
|
|
def health_plan(
|
|
config: GatewayConfig,
|
|
*,
|
|
mode: str = "published",
|
|
base_port: int = 19080,
|
|
host: str = "127.0.0.1",
|
|
) -> list[HealthCheck]:
|
|
if mode not in {"published", "preview"}:
|
|
raise ValueError(f"unsupported health mode {mode!r}")
|
|
|
|
endpoints = preview_endpoints(config, base_port=base_port, host=host) if mode == "preview" else []
|
|
checks: list[HealthCheck] = []
|
|
for site in config.sites:
|
|
manifest = _manifest_for_mode(config, site, mode=mode, endpoints=endpoints)
|
|
for fixture in manifest["fixtures"]:
|
|
checks.append(_health_check(site, fixture, mode=mode))
|
|
return checks
|
|
|
|
|
|
def blocked_health_checks(checks: list[HealthCheck]) -> list[HealthCheck]:
|
|
return [check for check in checks if check.status == "blocked"]
|
|
|
|
|
|
def _manifest_for_mode(
|
|
config: GatewayConfig,
|
|
site: SiteConfig,
|
|
*,
|
|
mode: str,
|
|
endpoints,
|
|
) -> dict[str, Any]:
|
|
if mode == "preview":
|
|
return preview_fixture_manifest(config, site, endpoints)
|
|
return fixture_manifest(config, site)
|
|
|
|
|
|
def _health_check(site: SiteConfig, fixture: dict[str, Any], *, mode: str) -> HealthCheck:
|
|
protocol = str(fixture["protocol"])
|
|
output_root = site.outputs.root / protocol
|
|
route = str(fixture.get("route", {}).get("fixture_path", "/"))
|
|
transport = str(fixture["checks"]["transport"])
|
|
profile = str(fixture["checks"].get("context", fixture["checks"].get("profile", transport)))
|
|
address_status = str(fixture["address_status"])
|
|
output_ready = (output_root / ".ampg-output").exists()
|
|
preview_status = fixture.get("preview", {}).get("status")
|
|
|
|
if not output_ready or preview_status == "missing-output":
|
|
status = "blocked"
|
|
action = "build-output"
|
|
message = f"generated output is missing: {output_root}"
|
|
elif address_status == "placeholder":
|
|
status = "review"
|
|
action = "configure-address"
|
|
message = "fixture uses a placeholder address; update protocol URL after daemon identity exists"
|
|
else:
|
|
status = "planned"
|
|
action = "check-fixture"
|
|
message = (
|
|
"verify fixture through the local preview server"
|
|
if mode == "preview"
|
|
else "verify fixture through the selected transport/profile after services start"
|
|
)
|
|
|
|
return HealthCheck(
|
|
site_id=site.id,
|
|
protocol=protocol,
|
|
mode=mode,
|
|
url=str(fixture["url"]),
|
|
output_root=output_root,
|
|
output_path=str(fixture["output_path"]),
|
|
transport=transport,
|
|
profile=profile,
|
|
address_status=address_status,
|
|
route=route,
|
|
status=status,
|
|
action=action,
|
|
command=_check_command(str(fixture["url"]), transport=transport, profile=profile),
|
|
message=message,
|
|
)
|
|
|
|
|
|
def _check_command(url: str, *, transport: str, profile: str) -> str:
|
|
if transport == "clearnet":
|
|
return f"curl -fsSL {url}"
|
|
if transport == "tor":
|
|
return f"curl --proxy socks5h://127.0.0.1:9050 -fsSL {url}"
|
|
if transport == "i2p":
|
|
return f"curl --proxy http://127.0.0.1:4444 -fsSL {url}"
|
|
if transport == "gemini":
|
|
return f"gemini fetch {url}"
|
|
if transport == "ipfs":
|
|
return f"ipfs cat {url}"
|
|
if transport == "reticulum":
|
|
return f"rns-fetch {url}"
|
|
return f"fetch {url} with {profile}"
|