67 lines
2.0 KiB
Python
67 lines
2.0 KiB
Python
"""Pydantic-модели и перечисления доменного слоя."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import uuid
|
||
from datetime import datetime, timezone
|
||
from enum import Enum
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
class DownloadStatus(str, Enum):
|
||
PENDING = "pending"
|
||
DOWNLOADING = "downloading"
|
||
DONE = "done"
|
||
FAILED = "failed"
|
||
PAUSED = "paused" # задел на будущее
|
||
|
||
|
||
def _now() -> datetime:
|
||
return datetime.now(timezone.utc)
|
||
|
||
|
||
def _new_id() -> str:
|
||
return uuid.uuid4().hex
|
||
|
||
|
||
class Download(BaseModel):
|
||
id: str = Field(default_factory=_new_id)
|
||
url: str
|
||
filename: str | None = None
|
||
status: DownloadStatus = DownloadStatus.PENDING
|
||
progress: float = 0.0 # 0.0–100.0
|
||
size_bytes: int | None = None
|
||
downloaded_bytes: int = 0
|
||
speed: float | None = None # байт/сек
|
||
eta: float | None = None # секунд до конца, оценка
|
||
error: str | None = None
|
||
created_at: datetime = Field(default_factory=_now)
|
||
finished_at: datetime | None = None # момент перехода в done/failed
|
||
|
||
|
||
class CreateDownloads(BaseModel):
|
||
"""Тело запроса POST /api/downloads — список ссылок (по одной на строку или массивом)."""
|
||
|
||
urls: list[str] = Field(default_factory=list, min_length=1)
|
||
|
||
|
||
class DownloaderInfo(BaseModel):
|
||
"""Зарегистрированная стратегия скачивания — для страницы «Загрузчики»."""
|
||
|
||
name: str
|
||
kind: str # "direct" | "extractor" | "fallback"
|
||
priority: int
|
||
description: str | None = None
|
||
|
||
|
||
# --- События шины (то, что улетает в SSE) ---
|
||
|
||
|
||
class DownloadEvent(BaseModel):
|
||
"""Обёртка над снимком загрузки, транслируемая в браузер через SSE."""
|
||
|
||
type: str # "created" | "progress" | "done" | "failed" | "deleted"
|
||
download: Download | None = None
|
||
id: str | None = None # для type="deleted" хватает id
|