"""Subject'ы NATS, заголовок дедупликации и идентификаторы сообщений контракта v1.0. Источник: `docs/context/03-architecture.md`, «Контракт обмена через NATS»; схема recognition-request (`Nats-Msg-Id = :`) и recognition-result-message (`ack::` / `result::`). Модуль намеренно совпадает с копией в arm-core. `request_subject`, `REQUEST_SUBJECTS`, `IMAGE_REQUEST_SUBJECT` и значение `"image"` в `Pipeline` tabular-parser не использует (он слушает только `tabular`) — это сознательный паритет с arm-core, а не мёртвый код. """ import uuid from collections.abc import Mapping from typing import Literal, get_args Pipeline = Literal["tabular", "image"] NATS_MSG_ID_HEADER = "Nats-Msg-Id" RESULT_SUBJECT = "files.tabular_parsed" TABULAR_REQUEST_SUBJECT = "files.tabular_uploaded" IMAGE_REQUEST_SUBJECT = "files.img_uploaded" REQUEST_SUBJECTS: Mapping[str, str] = { "tabular": TABULAR_REQUEST_SUBJECT, "image": IMAGE_REQUEST_SUBJECT, } def request_subject(pipeline: str, subjects: Mapping[str, str] = REQUEST_SUBJECTS) -> str: """Subject запроса по pipeline. `subjects` — карта `pipeline → subject` окружения (`NATSSettings.request_subjects()`); по умолчанию — имена контракта: `tabular` → `files.tabular_uploaded`, `image` → `files.img_uploaded`.""" try: return subjects[pipeline] except KeyError: raise ValueError(f"неизвестный pipeline {pipeline!r}: допустимы {', '.join(get_args(Pipeline))}") from None def request_msg_id(job_id: uuid.UUID | str, attempt: int) -> str: """`Nats-Msg-Id` запроса: `:`.""" return f"{job_id}:{attempt}" def ack_msg_id(job_id: uuid.UUID | str, attempt: int) -> str: """`Nats-Msg-Id` ack (`status = processing`) на `files.tabular_parsed`: `ack::`.""" return f"ack:{job_id}:{attempt}" def result_msg_id(job_id: uuid.UUID | str, attempt: int) -> str: """`Nats-Msg-Id` результата (`done | needs_check | error`) на `files.tabular_parsed`. Форма: `result::`. """ return f"result:{job_id}:{attempt}"