Made-with: Cursor
5.5 KiB
HTTP API
1. High-Level Overview
Purpose: FastAPI application that exposes HTTP endpoints for health monitoring, user authentication, encrypted resource loading/uploading, and a background Docker image unlock workflow.
Architectural Pattern: Thin controller — delegates all business logic to Resource Management (03) and binary_split.
Upstream dependencies: Core Models (01) — UnlockState enum; Resource Management (03) — ApiClient, binary_split functions
Downstream consumers: None — this is the system entry point, consumed by external HTTP clients.
2. Internal Interfaces
Interface: Module-level Functions
| Function | Input | Output | Description |
|---|---|---|---|
get_api_client |
— | ApiClient | Lazy singleton accessor |
_run_unlock |
str email, str password |
— | Background task: full unlock flow |
3. External API Specification
| Endpoint | Method | Auth | Rate Limit | Description |
|---|---|---|---|---|
/health |
GET | Public | — | Liveness probe |
/status |
GET | Public | — | Auth status + model cache dir |
/login |
POST | Public | — | Set user credentials |
/load/{filename} |
POST | Implicit | — | Download + decrypt resource |
/upload/{filename} |
POST | Implicit | — | Encrypt + upload resource (big/small) |
/unlock |
POST | Public | — | Start background Docker unlock |
/unlock/status |
GET | Public | — | Poll unlock workflow progress |
"Implicit" auth = credentials must have been set via /login first; enforced by ApiClient's auto-login on token absence.
Request/Response Schemas
POST /login
// Request
{"email": "user@example.com", "password": "secret"}
// Response 200
{"status": "ok"}
// Response 401
{"detail": "error message"}
POST /load/{filename}
// Request
{"filename": "model.bin", "folder": "models"}
// Response 200 — binary octet-stream
// Response 500
{"detail": "error message"}
POST /upload/{filename}
// Request — multipart/form-data
data: <file>
folder: "models" (form field, default "models")
// Response 200
{"status": "ok"}
POST /unlock
// Request
{"email": "user@example.com", "password": "secret"}
// Response 200
{"state": "authenticating"}
// Response 404
{"detail": "Encrypted archive not found"}
GET /unlock/status
// Response 200
{"state": "decrypting", "error": null}
4. Data Access Patterns
Caching Strategy
| Data | Cache Type | TTL | Invalidation |
|---|---|---|---|
| ApiClient | In-memory singleton | Process life | Never |
| unlock_state | Module global | Until next unlock | State machine transition |
5. Implementation Details
State Management: Module-level globals (api_client, unlock_state, unlock_error) protected by threading.Lock for unlock state mutations.
Key Dependencies:
| Library | Version | Purpose |
|---|---|---|
| fastapi | latest | HTTP framework |
| uvicorn | latest | ASGI server |
| pydantic | (via fastapi) | Request/response models |
| python-multipart | latest | File upload support |
Error Handling Strategy:
/login— catches all exceptions, returns 401/load,/upload— catches all exceptions, returns 500/unlock— checks preconditions (archive exists, not already in progress), then delegates to background task- Background task (
_run_unlock) catches all exceptions, setsunlock_state = errorwith error message
6. Extensions and Helpers
None.
7. Caveats & Edge Cases
Known limitations:
- No authentication middleware — endpoints rely on prior
/logincall having set credentials on the singleton get_api_client()uses a global without locking — race on first concurrent access/load/{filename}has a path parameterfilenamebut also takesreq.filenamefrom the body — the path param is unused_run_unlocksilently ignoresOSErrorwhen removing tar file (acceptable cleanup behavior)
Potential race conditions:
unlock_statemutations are lock-protected, butapi_clientsingleton creation is not- Concurrent
/unlockcalls: the lock check prevents duplicate starts, but there's a small TOCTOU window between the check and thebackground_tasks.add_taskcall
Performance bottlenecks:
/loadand/uploadare synchronous — large files block the worker thread_run_unlockruns as a background task (single thread) — only one unlock can run at a time
8. Dependency Graph
Must be implemented after: Core Models (01), Resource Management (03)
Can be implemented in parallel with: —
Blocks: — (entry point)
9. Logging Strategy
No direct logging in this component — all logging is handled by downstream components via constants.log() / constants.logerror().
Log format: N/A (delegates)
Log storage: N/A (delegates)