Реализованы сервисы ВМ2 - проверка сообщений и синхронизация с Б24 (деплой еще без перевода в боевой режим)

This commit is contained in:
mi
2026-08-13 18:52:42 +03:00
parent 5100ba9fc3
commit 99605b1c77
144 changed files with 15295 additions and 1120 deletions
+34 -10
View File
@@ -737,7 +737,14 @@ async def complete_attachment(
raise DomainError("dependency_unavailable", 503, "Object storage is unavailable") from exc
if int(head["ContentLength"]) != item.size_bytes or head.get("ContentType") != item.mime_type:
raise DomainError("attachment_checksum_mismatch", 400, "Uploaded metadata does not match")
version_id, etag = head.get("VersionId"), head.get("ETag")
if not version_id or not etag:
raise DomainError(
"dependency_unavailable", 503, "Versioned object metadata is unavailable"
)
item.checksum_sha256 = checksum
item.quarantine_version_id = str(version_id)
item.quarantine_etag = str(etag)
item.completed_at = datetime.now(UTC)
session.add(
audit(
@@ -886,6 +893,8 @@ async def send_message(
payload["attachment"] = {
"attachment_id": str(attachment.id),
"quarantine_object_key": attachment.quarantine_object_key,
"quarantine_version_id": attachment.quarantine_version_id,
"quarantine_etag": attachment.quarantine_etag,
"checksum": f"sha256:{attachment.checksum_sha256}",
"mime_type": attachment.mime_type,
"size_bytes": attachment.size_bytes,
@@ -893,14 +902,20 @@ async def send_message(
outbox: DeliveryOutbox | None = None
try:
verdict = await safety.check(payload, context.request_id)
if verdict["_status"] == 203:
task: SafetyTask | None = None
if verdict["_status"] == 202:
task_id = verdict["task_id"]
task = SafetyTask(
task_id=task_id,
poll_location=verdict["_location"],
message_id=message.id,
attachment_id=attachment.id if attachment else None,
quarantine_object_key=attachment.quarantine_object_key if attachment else None,
status="polling",
processing_mode=verdict["processing_mode"],
config_version=verdict["config_version"],
rules_version=verdict["rules_version"],
expires_at=datetime.fromisoformat(verdict["expires_at"].replace("Z", "+00:00")),
deadline_at=now
+ timedelta(seconds=settings.message_safety_task_poll_max_sec + 900),
next_poll_at=now,
@@ -910,16 +925,18 @@ async def send_message(
deadline = time_monotonic() + settings.message_safety_task_poll_max_sec
while time_monotonic() < deadline:
await sleep(settings.message_safety_task_poll_interval_sec)
verdict = await safety.poll(task_id, context.request_id)
if verdict["_status"] != 203:
verdict = await safety.poll(task.poll_location, context.request_id)
if verdict["_status"] != 202:
break
task.poll_location = verdict["_location"]
else:
raise DependencyFailure(timeout=True)
if verdict["_status"] == 403 or (
verdict["_status"] == 400
and verdict.get("error", {}).get("code") == "stub_final_error"
and verdict.get("verdict") == "deny"
):
message.safety_processing_mode = verdict["processing_mode"]
message.safety_config_version = verdict["config_version"]
message.safety_rules_version = verdict["rules_version"]
if task:
task.status = "completed"
if verdict["_status"] == 403:
message.text = ""
message.safety_status = "blocked"
message.delivery_status = "rejected"
@@ -957,11 +974,18 @@ async def send_message(
raise DependencyFailure()
if attachment and attachment.quarantine_object_key:
destination = f"attachments/dialogs/{dialog_id}/{attachment.id}"
await s3.promote(attachment.quarantine_object_key, destination)
await s3.promote(
attachment.quarantine_object_key,
destination,
version_id=attachment.quarantine_version_id or "",
etag=attachment.quarantine_etag or "",
)
attachment.storage_bucket = settings.selectel_s3_bucket_attachments
attachment.object_key = destination
attachment.quarantine_object_key = None
attachment.scan_status = "clean"
attachment.scan_status = (
"bypassed" if verdict["processing_mode"] == "mock" else "clean"
)
message.safety_status = "allowed"
outbox = DeliveryOutbox(
message_id=message.id,