# retoor from __future__ import annotations from dataclasses import dataclass from typing import Literal WorkersSpec = int | Literal["auto"] @dataclass(frozen=True) class ServiceSpec: name: str module: str port: int tier: int workers: WorkersSpec stateful: bool depends_on: tuple[str, ...] health_client_timeout: float = 2.0 @dataclass(frozen=True) class IngressRoute: prefix: str service: str websocket: bool = False SERVICE_SPECS: tuple[ServiceSpec, ...] = ( ServiceSpec("database", "devplacepy_services.database.main:app", 10601, 1, 1, True, ()), ServiceSpec("pubsub", "devplacepy_services.pubsub.main:app", 10602, 1, 1, True, ("database",)), ServiceSpec( "web", "devplacepy_services.web.main:app", 10500, 2, "auto", False, ("database", "pubsub"), health_client_timeout=4.0, ), ServiceSpec( "gateway", "devplacepy_services.gateway.main:app", 10620, 2, "auto", False, ("database",), health_client_timeout=4.0, ), ServiceSpec( "jobs", "devplacepy_services.jobs.main:app", 10630, 3, 1, True, ("database", "pubsub", "gateway"), health_client_timeout=8.0, ), ServiceSpec( "devii", "devplacepy_services.devii.main:app", 10631, 3, 2, True, ("database", "pubsub", "gateway"), health_client_timeout=4.0, ), ServiceSpec("bot", "devplacepy_services.bot.main:app", 10632, 3, 1, True, ("database", "gateway")), ServiceSpec("backup", "devplacepy_services.backup.main:app", 10633, 3, 1, True, ("database",)), ServiceSpec( "containers", "devplacepy_services.containers.main:app", 10634, 3, 1, True, ("database",), health_client_timeout=4.0, ), ServiceSpec("telegram", "devplacepy_services.telegram.main:app", 10635, 3, 1, True, ("database", "pubsub")), ServiceSpec("email", "devplacepy_services.email.main:app", 10636, 3, 1, True, ("database",)), ServiceSpec( "news", "devplacepy_services.news.main:app", 10637, 3, 1, True, ("database", "gateway"), ), ServiceSpec("gitea", "devplacepy_services.gitea.main:app", 10638, 3, 1, True, ("database", "gateway")), ServiceSpec("audit", "devplacepy_services.audit.main:app", 10639, 3, 1, True, ("database",)), ServiceSpec("xmlrpc", "devplacepy_services.xmlrpc.main:app", 10649, 3, 1, True, ("database",)), ) SERVICES: dict[str, ServiceSpec] = {spec.name: spec for spec in SERVICE_SPECS} TIER_ORDER: dict[int, tuple[str, ...]] = { 1: ("database", "pubsub"), 2: ("web", "gateway"), 3: ( "jobs", "devii", "bot", "backup", "containers", "telegram", "email", "news", "gitea", "audit", "xmlrpc", ), } SERVICE_URL_ENV: dict[str, str] = { "web": "DEVPLACE_WEB_URL", "database": "DEVPLACE_DB_SERVICE_URL", "pubsub": "DEVPLACE_PUBSUB_URL", "gateway": "DEVPLACE_GATEWAY_URL", "jobs": "DEVPLACE_JOBS_URL", "devii": "DEVPLACE_DEVII_URL", "bot": "DEVPLACE_BOT_URL", "backup": "DEVPLACE_BACKUP_URL", "containers": "DEVPLACE_CONTAINERS_URL", "telegram": "DEVPLACE_TELEGRAM_URL", "email": "DEVPLACE_EMAIL_URL", "news": "DEVPLACE_NEWS_URL", "gitea": "DEVPLACE_GITEA_URL", "audit": "DEVPLACE_AUDIT_URL", "xmlrpc": "DEVPLACE_XMLRPC_URL", } INGRESS_ROUTES: tuple[IngressRoute, ...] = ( IngressRoute("/openai", "gateway"), IngressRoute("/devii", "devii", websocket=True), IngressRoute("/pubsub", "pubsub", websocket=True), IngressRoute("/zips", "jobs"), IngressRoute("/forks", "jobs"), IngressRoute("/tools", "jobs", websocket=True), IngressRoute("/xmlrpc", "xmlrpc"), ) INGRESS_WS_PREFIXES: tuple[tuple[str, str], ...] = ( ( "/projects/", "containers", ), ) FORBIDDEN_GAPS: tuple[tuple[int, int], ...] = ( (10520, 10599), (10610, 10619), (10650, 10699), (10750, 10799), (20550, 20599), (20650, 20699), ) PORT_HINTS: dict[int, str] = { 10500: "web service", 20500: "test orchestrator", 10502: "locust", } _MICRO_DEV_PORTS: dict[str, int] = {spec.name: spec.port for spec in SERVICE_SPECS} XMLRPC_RAW_SOCKET_PORT_DEV = 10648 def xmlrpc_raw_socket_port(profile: str) -> int: if profile == "micro-test": return XMLRPC_RAW_SOCKET_PORT_DEV + 10000 if profile == "micro-prod": return XMLRPC_RAW_SOCKET_PORT_DEV + 100 return XMLRPC_RAW_SOCKET_PORT_DEV def build_profiles() -> dict[str, dict[str, int]]: return { "micro-dev": dict(_MICRO_DEV_PORTS), "micro-test": { k: (20500 if k == "web" else v + 10000) for k, v in _MICRO_DEV_PORTS.items() }, "micro-prod": { k: (10500 if k == "web" else v + 100) for k, v in _MICRO_DEV_PORTS.items() }, "locust": {"app": 10502, "ui": 10503}, } def orchestrator_services_dict() -> dict[str, dict]: return { spec.name: { "module": spec.module, "port": spec.port, "tier": spec.tier, "workers": spec.workers, "stateful": spec.stateful, "depends_on": list(spec.depends_on), } for spec in SERVICE_SPECS } def health_client_timeout(name: str) -> float: spec = SERVICES.get(name) if spec is None: return 2.0 return spec.health_client_timeout