File size: 2,048 Bytes
6a49f21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
"""
Pydantic models for sync operations.

These models are generic and used by all sync implementations.
"""

from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional, Literal


class SyncStatusResponse(BaseModel):
    """Response model for sync status check (O(1) operation)."""
    needs_sync: bool
    local_version: int
    remote_version: int
    unsynced_count: int
    last_sync_time: Optional[datetime] = None
    sync_in_progress: bool = False


class SyncRequest(BaseModel):
    """Request model for sync operations."""
    force: bool = Field(
        default=False,
        description="Force sync even if quick check indicates no changes needed"
    )


class ConflictInfo(BaseModel):
    """Information about a file conflict."""
    file_id: str
    stable_id: str
    filename: str
    doc_id: str
    local_modified_at: datetime
    local_hash: str
    remote_modified_at: Optional[datetime]
    remote_hash: Optional[str]
    conflict_type: Literal['modified_both', 'deleted_remote', 'deleted_local']


class SyncSummary(BaseModel):
    """Summary of sync operation results."""
    skipped: bool = False
    uploaded: int = 0
    downloaded: int = 0
    deleted_local: int = 0
    deleted_remote: int = 0
    metadata_synced: int = 0
    conflicts: int = 0
    errors: int = 0
    new_version: Optional[int] = None
    duration_ms: int = 0
    message: Optional[str] = None


class ConflictListResponse(BaseModel):
    """Response model for listing conflicts."""
    conflicts: list[ConflictInfo]
    total: int


class ConflictResolution(BaseModel):
    """Request model for resolving a conflict."""
    file_id: str
    resolution: Literal['local_wins', 'remote_wins', 'keep_both']
    new_variant: Optional[str] = Field(
        default=None,
        description="Variant name when using 'keep_both' resolution"
    )


class SSEMessage(BaseModel):
    """Model for Server-Sent Events messages."""
    event: str  # 'syncProgress', 'syncMessage', 'syncComplete', 'syncError'
    data: str