#!/usr/bin/env python3 from __future__ import annotations import argparse import json import sys import time from urllib.error import HTTPError, URLError from urllib.request import Request, urlopen def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Send one generic X-Financial Hermes callback.") parser.add_argument("--url", required=True) parser.add_argument("--token", required=True) parser.add_argument("--retries", type=int, default=3) parser.add_argument("--type", dest="task_type", default="") parser.add_argument("--run-id", default="") parser.add_argument("--status", choices=("running", "succeeded", "failed"), default="") parser.add_argument("--summary", default="") parser.add_argument("--error", default="") return parser.parse_args() def main() -> int: args = parse_args() payload = json.load(sys.stdin) if args.task_type and args.run_id and args.status: payload = { "type": args.task_type, "run_id": args.run_id, "status": args.status, "summary": args.summary, "payload": payload, **({"error": args.error} if args.error else {}), } body = json.dumps(payload, ensure_ascii=False).encode("utf-8") last_error = "" for attempt in range(1, max(1, args.retries) + 1): request = Request( args.url, data=body, headers={ "Authorization": f"Bearer {args.token}", "Content-Type": "application/json", }, method="POST", ) try: with urlopen(request, timeout=30) as response: response_body = response.read().decode("utf-8") if 200 <= response.status < 300: print(response_body) return 0 last_error = f"HTTP {response.status}: {response_body}" except HTTPError as exc: last_error = f"HTTP {exc.code}: {exc.read().decode('utf-8', errors='replace')}" except URLError as exc: last_error = str(exc.reason) if attempt < max(1, args.retries): time.sleep(min(attempt, 3)) print(last_error or "callback failed", file=sys.stderr) return 1 if __name__ == "__main__": raise SystemExit(main())