drives initial plan

This commit is contained in:
Shivering Ocelot committed 2026-09-21 16:18:42 -05:00
1 parent 75dac1e459
commit 6ad0a461e4
5 files changed
+534

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
# Phase 3: Server Integration
## Objective
Attach drive operations to the Quart application's routing layer and WebSocket handlers. This phase implements the API endpoints (`/files/<int:id>` and `/files/<int:id>/meta`) and handles WebSocket binary uploads and list requests.
## Concepts
### Server Actions & Protocol
We leverage the existing WebSocket action protocol for interactions and REST for byte streams:
| Action | Method | Payload | Description |
|--------|--------|---------|-------------|
| `list-drives` | WS | `{}` | Lists available drives for the logged-in user. |
| `list-files` | WS | `{driveName: "..."}` | Returns array of DB metadata objects for the specified drive. |
| `upload-file` | WS Binary | `{driveName, fileName, mime?}` | Sends JSON header followed by binary stream. Returns `fileId`. |
| `/files/<int:id>` | GET | N/A | Serves raw file download. Uses resolved path. Auth required. |
| `/files/<int:id>/meta` | GET | N/A | Lightweight metadata endpoint for existence checks. |
**WebSocket Upload Sequence Example:**
```javascript
// 1. Send metadata
ws.send(JSON.stringify({action: "upload-file", nonce: "n1", body: {driveName: "Docs", fileName: "report.pdf"}}));
// 2. Immediately follow with binary payload
ws.send(blob);
// 3. Server responds
{action: "file-uploaded", fileId: 42, nonce: "n1"}
```
## Tasks
### 3.1 Register Routes
Extend `backend/src/app.py` with the following route handlers:
```python
from quart import Quart, request, send_file, make_response
from . import drive_service
app = Quart(__name__)
@app.route("/files/<int:id>", methods=["GET"])
async def serve_file(id):
try:
current_user_id = request.headers.get("Authorization").split(" ")[1] # or via auth middleware
file_path, mime_type = await drive_service.resolve_drive_file_for_serving(id, current_user_id)
return await send_file(file_path, mimetype=mime_type)
except FileNotFoundError as e:
return make_response("Not found", 404)
except PermissionError:
return make_response("Forbidden", 403)
@app.route("/files/<int:id>/meta", methods=["GET"])
async def get_file_meta(id):
try:
current_user_id = ... # same auth logic
# Verify ownership briefly before returning meta
file = await db.DriveFile.filter(id=id).select_related("drive__user").get_or_none()
if not file or file.drive.user_id != current_user_id:
raise Exception("Denied")
return drive_service.get_drive_file_metadata(id)
except Exception as e:
return make_response({"error": str(e)}, 404)
```
*Note: Replace explicit auth extraction with your framework's actual token validation mechanism.*
### 3.2 Extend WebSocket Handler
In `backend/src/app.py`, update the existing `server.websocket('/ws')` handler to cover new actions:
- `list-drives`: Query `db.Drive.filter(user_id=user_id)`. Return a list of names and IDs.
- `list-files`: Query `db.DriveFile.filter(drive__name=drive_name)` filtered by the authenticated user.
- `upload-file`: Parse the first message for JSON headers (`driveName`, `fileName`, `mime`). Open the stream, call `drive_service.upload_file(...)`. Reply with `{action: "file-uploaded", fileId: ..., nonce: ...}`.