74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
from __future__ import annotations
|
||
|
||
from typing import List, Optional, Dict, Any, Literal
|
||
from pydantic import BaseModel, Field, validator
|
||
|
||
|
||
class SignedRequestHeaders(BaseModel):
|
||
"""Заголовки межузлового запроса с подписью Ed25519"""
|
||
x_node_communication: Literal["true"] = Field(alias="X-Node-Communication")
|
||
x_node_id: str = Field(alias="X-Node-ID")
|
||
x_node_public_key: str = Field(alias="X-Node-Public-Key")
|
||
x_node_signature: str = Field(alias="X-Node-Signature")
|
||
|
||
class Config:
|
||
populate_by_name = True
|
||
|
||
|
||
class ChunkRef(BaseModel):
|
||
chunk_id: str
|
||
content_id: str
|
||
chunk_index: int
|
||
chunk_hash: str
|
||
encrypted_data: str
|
||
signature: Optional[str] = None
|
||
created_at: Optional[str] = None
|
||
|
||
|
||
class ContentRequest(BaseModel):
|
||
action: Literal["content_sync"]
|
||
sync_type: Literal["content_request", "new_content", "content_list"]
|
||
content_info: Dict[str, Any] = Field(default_factory=dict)
|
||
timestamp: Optional[int] = None
|
||
|
||
@validator("content_info")
|
||
def validate_content_info(cls, v, values):
|
||
st = values.get("sync_type")
|
||
if st == "content_request":
|
||
# ожидаем content_id и indexes
|
||
if "content_id" not in v or "indexes" not in v:
|
||
raise ValueError("content_request requires content_info.content_id and content_info.indexes")
|
||
if not isinstance(v.get("indexes"), list):
|
||
raise ValueError("content_info.indexes must be a list")
|
||
elif st == "new_content":
|
||
if "content_id" not in v or "total_chunks" not in v:
|
||
raise ValueError("new_content requires content_info.content_id and content_info.total_chunks")
|
||
return v
|
||
|
||
|
||
class ContentProvideResponse(BaseModel):
|
||
success: bool = True
|
||
chunks: List[ChunkRef] = Field(default_factory=list)
|
||
errors: List[Dict[str, Any]] = Field(default_factory=list)
|
||
|
||
|
||
class ContentStatusResponse(BaseModel):
|
||
content_id: str
|
||
total_chunks: int
|
||
have_indexes: List[int] = Field(default_factory=list)
|
||
missing_indexes: List[int] = Field(default_factory=list)
|
||
verified: Optional[bool] = None
|
||
message: Optional[str] = None
|
||
|
||
|
||
class ContentVerifyRequest(BaseModel):
|
||
content_id: str
|
||
chunks: List[ChunkRef] = Field(default_factory=list)
|
||
verify_signatures: bool = True
|
||
|
||
|
||
class GenericSignedResponse(BaseModel):
|
||
success: bool
|
||
data: Dict[str, Any] = Field(default_factory=dict)
|
||
node_id: Optional[str] = None
|
||
timestamp: Optional[str] = None |