import json from typing import Any, Dict, List, Optional, Tuple from .comparator import compare_versions from .extractor import build_upstream_fallback, extract_version from .fetcher import authenticate_service, build_headers, fetch_response, fetch_socket_info from .models import ServiceConfig def check_service(service: ServiceConfig, timeout: float, user_agent: str) -> Dict[str, Any]: result: Dict[str, Any] = { "name": service.name, "current": None, "latest": None, "current_error": None, "latest_error": None, "upstream_url": service.upstream_latest_version_url, "release_notes": None, } if service.current_version_url and service.current_version_extract: try: headers = build_headers(service.current_version_headers) if service.login: login_cookie = authenticate_service(service, timeout, user_agent) if login_cookie: headers.setdefault("Cookie", login_cookie) body, response_headers = fetch_response(service.current_version_url, timeout, user_agent, headers) result["current"] = extract_version(body, service.current_version_extract, response_headers) except Exception as exc: result["current_error"] = str(exc) elif service.login_socket: try: result["current"] = fetch_socket_info(service, timeout) except Exception as exc: result["current_error"] = str(exc) if service.upstream_latest_version_url and service.upstream_latest_extract: headers = build_headers(service.upstream_latest_headers) try: body, response_headers = fetch_response( service.upstream_latest_version_url, timeout, user_agent, headers ) result["latest"] = extract_version(body, service.upstream_latest_extract, response_headers) if result["latest"] is None: raise ValueError("Latest version extraction returned empty") try: parsed = json.loads(body) if isinstance(parsed, dict): result["release_notes"] = parsed.get("body") or None except (json.JSONDecodeError, AttributeError): pass except Exception as exc: fallback = build_upstream_fallback(service.upstream_latest_version_url) if fallback: try: body, response_headers = fetch_response(fallback["url"], timeout, user_agent, headers) result["latest"] = extract_version(body, fallback["extract"], response_headers) except Exception as fallback_exc: result["latest_error"] = str(fallback_exc) else: result["latest_error"] = str(exc) return result def build_summary(results: List[Dict[str, Any]]) -> Tuple[str, bool]: updates = [r for r in results if compare_versions(r["current"], r["latest"]) == 1] errors = [r for r in results if r["current_error"] or r["latest_error"]] lines = [] if updates: lines.append("Updates available:") for r in updates: lines.append(f"- {r['name']}: {r['current'] or 'unknown'} -> {r['latest'] or 'unknown'}") if errors: lines.append("Errors:") for r in errors: if r["current_error"]: lines.append(f"- {r['name']}: current version error") if r["latest_error"]: lines.append(f"- {r['name']}: latest version error") if not lines: return "All services up to date.", False return "\n".join(lines), True