Add --debug flag, dual-mode logging, and auto-run on startup
- logger.py: root-level handlers; normal mode shows only user-facing INFO (sync, export, push, MBOX) plus WARNING/ERROR; --debug shows all DEBUG with full context (module.func:line). Third-party loggers silenced to WARNING. - main.py: add --debug CLI flag, call configure_logging() at startup, auto-trigger sync on first run or when last sync is overdue by the interval - database.py: add metadata table with record_sync_time() / get_last_sync_time() so startup knows whether a sync is due; sync time recorded on success - forwarder.py: INFO at push start and push complete with counts - packager.py: INFO before MBOX conversion begins - exporter.py: INFO when Proton Mail export starts https://claude.ai/code/session_01KjaNo9RXevw6x1DjJD8mj6
This commit is contained in:
+30
-1
@@ -2,8 +2,9 @@
|
||||
|
||||
import sqlite3
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Generator, Iterable
|
||||
from typing import Generator, Iterable, Optional
|
||||
|
||||
DB_PATH = Path(__file__).parent.parent / "data" / "mailrelay.db"
|
||||
|
||||
@@ -48,6 +49,12 @@ def init_db() -> None:
|
||||
conn.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_state ON messages(state)
|
||||
""")
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS metadata (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
def is_known(message_id: str) -> bool:
|
||||
@@ -127,6 +134,28 @@ def get_pending_mboxes() -> list[dict]:
|
||||
return [{"mbox_path": path, "message_ids": ids} for path, ids in by_path.items()]
|
||||
|
||||
|
||||
def get_last_sync_time() -> Optional[datetime]:
|
||||
"""Return the UTC timestamp of the last completed sync, or None."""
|
||||
with _db() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT value FROM metadata WHERE key = 'last_sync_at'"
|
||||
).fetchone()
|
||||
if not row:
|
||||
return None
|
||||
return datetime.fromisoformat(row["value"]).replace(tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def record_sync_time() -> None:
|
||||
"""Record that a sync cycle just completed."""
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
with _db() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO metadata (key, value) VALUES ('last_sync_at', ?) "
|
||||
"ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
||||
(now,),
|
||||
)
|
||||
|
||||
|
||||
def clear_pending_for_mbox(mbox_path: str) -> list[str]:
|
||||
"""Remove pending state for a given MBOX (used on cleanup/re-process).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user