Files
romm/backend/handler/sync/comparison.py
T
Georges-Antoine Assi e6ddc5da11 bot attempt at save sync
2026-03-14 22:13:38 -04:00

74 lines
2.4 KiB
Python

from __future__ import annotations
from datetime import datetime
from typing import Literal, NamedTuple
from utils.datetime import to_utc
SyncAction = Literal["upload", "download", "conflict", "no_op"]
class SyncComparisonResult(NamedTuple):
action: SyncAction
reason: str
def compare_save_state(
*,
client_hash: str | None,
client_updated_at: datetime,
server_hash: str | None,
server_updated_at: datetime,
device_last_synced_at: datetime | None,
) -> SyncComparisonResult:
"""Compare client and server save state to determine the sync action.
Returns a (action, reason) tuple where action is one of:
- upload: client save should be uploaded to server
- download: server save should be downloaded to client
- conflict: both sides changed, needs resolution
- no_op: saves are in sync
"""
client_ts = to_utc(client_updated_at)
server_ts = to_utc(server_updated_at)
# If hashes match, saves are identical
if client_hash and server_hash and client_hash == server_hash:
return SyncComparisonResult("no_op", "Content is identical")
# If we have a last sync timestamp, use it to determine which side changed
if device_last_synced_at:
synced_ts = to_utc(device_last_synced_at)
client_changed = client_ts > synced_ts
server_changed = server_ts > synced_ts
if client_changed and server_changed:
return SyncComparisonResult(
"conflict", "Both sides changed since last sync"
)
if client_changed:
return SyncComparisonResult("upload", "Client save is newer than last sync")
if server_changed:
return SyncComparisonResult(
"download", "Server save is newer than last sync"
)
return SyncComparisonResult("no_op", "No changes since last sync")
# No sync history: fall back to timestamp comparison
if client_ts > server_ts:
return SyncComparisonResult("upload", "Client save is newer (no sync history)")
if server_ts > client_ts:
return SyncComparisonResult(
"download", "Server save is newer (no sync history)"
)
# Same timestamp, different hashes (or missing hashes)
if client_hash != server_hash:
return SyncComparisonResult("conflict", "Same timestamp but different content")
return SyncComparisonResult("no_op", "Saves appear identical")