Use httpx for Telegram onboarding worker calls
This commit is contained in:
+23
-17
@@ -3385,6 +3385,7 @@ def _write_platform_enabled(platform_id: str, enabled: bool) -> None:
|
|||||||
|
|
||||||
|
|
||||||
_TELEGRAM_ONBOARDING_DEFAULT_URL = "https://setup.hermes-agent.nousresearch.com"
|
_TELEGRAM_ONBOARDING_DEFAULT_URL = "https://setup.hermes-agent.nousresearch.com"
|
||||||
|
_TELEGRAM_ONBOARDING_USER_AGENT = f"HermesDashboard/{__version__}"
|
||||||
_TELEGRAM_USER_ID_RE = re.compile(r"^\d+$")
|
_TELEGRAM_USER_ID_RE = re.compile(r"^\d+$")
|
||||||
|
|
||||||
|
|
||||||
@@ -3457,27 +3458,32 @@ def _telegram_onboarding_request_sync(
|
|||||||
body: dict[str, Any] | None = None,
|
body: dict[str, Any] | None = None,
|
||||||
bearer_token: str | None = None,
|
bearer_token: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
data = None
|
import httpx
|
||||||
headers = {"Accept": "application/json"}
|
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"User-Agent": _TELEGRAM_ONBOARDING_USER_AGENT,
|
||||||
|
}
|
||||||
|
request_kwargs: dict[str, Any] = {}
|
||||||
if body is not None:
|
if body is not None:
|
||||||
data = json.dumps(body).encode("utf-8")
|
|
||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
|
request_kwargs["json"] = body
|
||||||
if bearer_token:
|
if bearer_token:
|
||||||
headers["Authorization"] = f"Bearer {bearer_token}"
|
headers["Authorization"] = f"Bearer {bearer_token}"
|
||||||
|
|
||||||
request = urllib.request.Request(
|
url = f"{_telegram_onboarding_base_url()}{path}"
|
||||||
f"{_telegram_onboarding_base_url()}{path}",
|
|
||||||
data=data,
|
|
||||||
headers=headers,
|
|
||||||
method=method,
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(request, timeout=10) as response:
|
with httpx.Client(timeout=httpx.Timeout(10.0)) as client:
|
||||||
payload = response.read()
|
response = client.request(
|
||||||
except urllib.error.HTTPError as exc:
|
method,
|
||||||
payload = exc.read()
|
url,
|
||||||
|
headers=headers,
|
||||||
|
**request_kwargs,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
except httpx.HTTPStatusError as exc:
|
||||||
try:
|
try:
|
||||||
parsed = json.loads(payload.decode("utf-8"))
|
parsed = exc.response.json()
|
||||||
except Exception:
|
except Exception:
|
||||||
parsed = {}
|
parsed = {}
|
||||||
error = str(parsed.get("error") or parsed.get("status") or "")
|
error = str(parsed.get("error") or parsed.get("status") or "")
|
||||||
@@ -3485,18 +3491,18 @@ def _telegram_onboarding_request_sync(
|
|||||||
error,
|
error,
|
||||||
"Telegram setup service returned an error.",
|
"Telegram setup service returned an error.",
|
||||||
)
|
)
|
||||||
status_code = 404 if exc.code == 404 else 502
|
status_code = 404 if exc.response.status_code == 404 else 502
|
||||||
if error in {"expired", "claimed"}:
|
if error in {"expired", "claimed"}:
|
||||||
status_code = 410
|
status_code = 410
|
||||||
raise HTTPException(status_code=status_code, detail=detail) from exc
|
raise HTTPException(status_code=status_code, detail=detail) from exc
|
||||||
except Exception as exc:
|
except httpx.RequestError as exc:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=502,
|
status_code=502,
|
||||||
detail="Telegram setup service is unavailable. Try again shortly.",
|
detail="Telegram setup service is unavailable. Try again shortly.",
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parsed = json.loads(payload.decode("utf-8"))
|
parsed = response.json()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=502,
|
status_code=502,
|
||||||
|
|||||||
@@ -1134,6 +1134,54 @@ class TestWebServerEndpoints:
|
|||||||
assert data["state"] == "not_configured"
|
assert data["state"] == "not_configured"
|
||||||
assert "DISCORD_BOT_TOKEN" in data["message"]
|
assert "DISCORD_BOT_TOKEN" in data["message"]
|
||||||
|
|
||||||
|
def test_telegram_onboarding_worker_request_uses_httpx(self, monkeypatch):
|
||||||
|
import httpx
|
||||||
|
import hermes_cli.web_server as ws
|
||||||
|
|
||||||
|
calls = {}
|
||||||
|
|
||||||
|
def fail_urlopen(*_args, **_kwargs):
|
||||||
|
raise AssertionError("Telegram onboarding should not use urllib")
|
||||||
|
|
||||||
|
class FakeHttpxClient:
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
calls["client_kwargs"] = kwargs
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *_exc_info):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def request(self, method, url, **kwargs):
|
||||||
|
calls["request"] = (method, url, kwargs)
|
||||||
|
return httpx.Response(
|
||||||
|
201,
|
||||||
|
json={"ok": True},
|
||||||
|
request=httpx.Request(method, url),
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setenv("TELEGRAM_ONBOARDING_URL", "https://worker.example")
|
||||||
|
monkeypatch.setattr(ws.urllib.request, "urlopen", fail_urlopen)
|
||||||
|
monkeypatch.setattr(httpx, "Client", FakeHttpxClient)
|
||||||
|
|
||||||
|
payload = ws._telegram_onboarding_request_sync(
|
||||||
|
"POST",
|
||||||
|
"/v1/telegram/pairings",
|
||||||
|
body={"bot_name": "Hermes Agent"},
|
||||||
|
bearer_token="poll-secret",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert payload == {"ok": True}
|
||||||
|
method, url, kwargs = calls["request"]
|
||||||
|
assert method == "POST"
|
||||||
|
assert url == "https://worker.example/v1/telegram/pairings"
|
||||||
|
assert kwargs["json"] == {"bot_name": "Hermes Agent"}
|
||||||
|
assert kwargs["headers"]["Accept"] == "application/json"
|
||||||
|
assert kwargs["headers"]["Authorization"] == "Bearer poll-secret"
|
||||||
|
assert kwargs["headers"]["Content-Type"] == "application/json"
|
||||||
|
assert kwargs["headers"]["User-Agent"].startswith("HermesDashboard/")
|
||||||
|
|
||||||
def test_telegram_onboarding_start_strips_poll_token(self, monkeypatch):
|
def test_telegram_onboarding_start_strips_poll_token(self, monkeypatch):
|
||||||
import hermes_cli.web_server as ws
|
import hermes_cli.web_server as ws
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user