drives initial plan
This commit is contained in:
1 parent
75dac1e459
commit
6ad0a461e4
5 files changed
+534
No files matched your search
@@ -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: ...}`.
|
||||
Reference in new issue
Block a user