Initial commit: webmail client (M0/M1)
Three-pane webmail client. - Backend: FastAPI + async SQLAlchemy + arq worker (Postgres/Redis), IMAP/SMTP sync, threading, search, drafts/outbox with undo, attachments, 2FA. - Frontend: React 18 + Vite + TypeScript + TanStack Query + Tailwind; three-pane UI with rich-text composer, light/dark themes, resizable panels. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""Content-addressed blob store (SPEC §4 "Blob store", §6.4).
|
||||
|
||||
Layout: ``${BLOB_ROOT}/{user_id}/{sha256[:2]}/{sha256}`` (filesystem default).
|
||||
Content-addressed, so identical payloads dedupe. Postgres holds metadata only;
|
||||
deleting a user removes their blob subtree.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
from app.config import get_settings
|
||||
|
||||
|
||||
def _root() -> Path:
|
||||
return Path(get_settings().blob_root)
|
||||
|
||||
|
||||
def sha256_hex(data: bytes) -> str:
|
||||
"""Return the hex sha256 digest of ``data``."""
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def blob_path(user_id: uuid.UUID, sha: str) -> Path:
|
||||
"""Return the on-disk path for a user's blob (does not create it)."""
|
||||
return _root() / str(user_id) / sha[:2] / sha
|
||||
|
||||
|
||||
def store(user_id: uuid.UUID, data: bytes) -> str:
|
||||
"""Store ``data`` content-addressed; return its sha256. Idempotent (dedupes)."""
|
||||
sha = sha256_hex(data)
|
||||
path = blob_path(user_id, sha)
|
||||
if not path.exists():
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp = path.with_suffix(".tmp")
|
||||
tmp.write_bytes(data)
|
||||
tmp.replace(path) # atomic within the same directory
|
||||
return sha
|
||||
|
||||
|
||||
def load(user_id: uuid.UUID, sha: str) -> bytes:
|
||||
"""Load a blob by sha256. Raises FileNotFoundError if absent."""
|
||||
return blob_path(user_id, sha).read_bytes()
|
||||
|
||||
|
||||
def exists(user_id: uuid.UUID, sha: str) -> bool:
|
||||
"""Return True if the blob is present."""
|
||||
return blob_path(user_id, sha).exists()
|
||||
|
||||
|
||||
def remove(user_id: uuid.UUID, sha: str) -> None:
|
||||
"""Delete a blob if present (used by account/user deletion). Idempotent."""
|
||||
blob_path(user_id, sha).unlink(missing_ok=True)
|
||||
Reference in New Issue
Block a user