31 lines
987 B
Python
31 lines
987 B
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import json
|
||
|
|
from datetime import UTC, datetime
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
class Checkpoint:
|
||
|
|
"""Per-account cursor persistence.
|
||
|
|
|
||
|
|
File shape: `{"cursor": "...", "updated_at": "2026-04-17T12:00:00+00:00"}`
|
||
|
|
One file per (provider, account_id) at `<dir>/<provider>-<account_id>.json`.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, directory: Path, *, provider: str, account_id: str) -> None:
|
||
|
|
self._path = directory / f"{provider}-{account_id}.json"
|
||
|
|
|
||
|
|
def load(self) -> str | None:
|
||
|
|
if not self._path.exists():
|
||
|
|
return None
|
||
|
|
raw = json.loads(self._path.read_text())
|
||
|
|
cursor = raw.get("cursor")
|
||
|
|
if not isinstance(cursor, str):
|
||
|
|
return None
|
||
|
|
return cursor
|
||
|
|
|
||
|
|
def save(self, cursor: str) -> None:
|
||
|
|
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
payload = {"cursor": cursor, "updated_at": datetime.now(UTC).isoformat()}
|
||
|
|
self._path.write_text(json.dumps(payload))
|