Task 4.4: Update WebSocket API Endpoints to use key identifier
- Updated src/server/api/websocket.py docstrings to document key as primary series identifier - Updated src/server/models/websocket.py with detailed docstrings explaining key and folder fields in message payloads - Updated src/server/services/websocket_service.py broadcast method docstrings to document key field usage - Added WebSocket message example with key in infrastructure.md - All 83 WebSocket tests pass - Task 4.4 marked as complete in instructions.md
This commit is contained in:
parent
f4d14cf17e
commit
3c8ba1d48c
@ -103,6 +103,23 @@ Real-time updates for downloads, scans, and queue operations.
|
|||||||
|
|
||||||
**Message Types**: `download_progress`, `download_complete`, `download_failed`, `queue_status`, `scan_progress`, `scan_complete`, `scan_failed`
|
**Message Types**: `download_progress`, `download_complete`, `download_failed`, `queue_status`, `scan_progress`, `scan_complete`, `scan_failed`
|
||||||
|
|
||||||
|
**Series Identifier in Messages:**
|
||||||
|
All series-related WebSocket events include `key` as the primary identifier in their data payload:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "download_progress",
|
||||||
|
"timestamp": "2025-10-17T10:30:00.000Z",
|
||||||
|
"data": {
|
||||||
|
"download_id": "abc123",
|
||||||
|
"key": "attack-on-titan",
|
||||||
|
"folder": "Attack on Titan (2013)",
|
||||||
|
"percent": 45.2,
|
||||||
|
"speed_mbps": 2.5,
|
||||||
|
"eta_seconds": 180
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Database Models
|
## Database Models
|
||||||
|
|
||||||
| Model | Purpose |
|
| Model | Purpose |
|
||||||
|
|||||||
@ -166,34 +166,7 @@ For each task completed:
|
|||||||
|
|
||||||
#### Task 4.3: Update Queue API Endpoints to Use Key ✅ (November 27, 2025)
|
#### Task 4.3: Update Queue API Endpoints to Use Key ✅ (November 27, 2025)
|
||||||
|
|
||||||
---
|
#### Task 4.4: Update WebSocket API Endpoints to Use Key ✅ (November 27, 2025)
|
||||||
|
|
||||||
#### Task 4.4: Update WebSocket API Endpoints to Use Key
|
|
||||||
|
|
||||||
**File:** `src/server/api/websocket.py`
|
|
||||||
|
|
||||||
**Objective:** Ensure WebSocket API endpoint handlers use `key` for series identification.
|
|
||||||
|
|
||||||
**Steps:**
|
|
||||||
|
|
||||||
1. Open `src/server/api/websocket.py`
|
|
||||||
2. Review all WebSocket message handlers
|
|
||||||
3. Ensure messages use `key` for series identification
|
|
||||||
4. Update message schemas to include `key` field
|
|
||||||
5. Keep `folder` for display purposes
|
|
||||||
6. Update docstrings
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
|
|
||||||
- [ ] All WebSocket handlers use `key`
|
|
||||||
- [ ] Message schemas include `key`
|
|
||||||
- [ ] All WebSocket API tests pass
|
|
||||||
|
|
||||||
**Test Command:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda run -n AniWorld python -m pytest tests/api/ -k "websocket" -v
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -828,7 +801,7 @@ conda run -n AniWorld python -m pytest tests/integration/test_identifier_consist
|
|||||||
- [x] Task 4.1: Update Anime API Endpoints ✅ **Completed November 27, 2025**
|
- [x] Task 4.1: Update Anime API Endpoints ✅ **Completed November 27, 2025**
|
||||||
- [x] Task 4.2: Update Download API Endpoints ✅ **Completed November 27, 2025**
|
- [x] Task 4.2: Update Download API Endpoints ✅ **Completed November 27, 2025**
|
||||||
- [x] Task 4.3: Update Queue API Endpoints ✅ **Completed November 27, 2025**
|
- [x] Task 4.3: Update Queue API Endpoints ✅ **Completed November 27, 2025**
|
||||||
- [ ] Task 4.4: Update WebSocket API Endpoints
|
- [x] Task 4.4: Update WebSocket API Endpoints ✅ **Completed November 27, 2025**
|
||||||
- [ ] Task 4.5: Update Pydantic Models
|
- [ ] Task 4.5: Update Pydantic Models
|
||||||
- [ ] Task 4.6: Update Validators
|
- [ ] Task 4.6: Update Validators
|
||||||
- [ ] Task 4.7: Update Template Helpers
|
- [ ] Task 4.7: Update Template Helpers
|
||||||
|
|||||||
@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
This module provides WebSocket endpoints for clients to connect and receive
|
This module provides WebSocket endpoints for clients to connect and receive
|
||||||
real-time updates about downloads, queue status, and system events.
|
real-time updates about downloads, queue status, and system events.
|
||||||
|
|
||||||
|
Series Identifier Convention:
|
||||||
|
- `key`: Primary identifier for series (provider-assigned, URL-safe)
|
||||||
|
e.g., "attack-on-titan"
|
||||||
|
- `folder`: Display metadata only (e.g., "Attack on Titan (2013)")
|
||||||
|
|
||||||
|
All series-related WebSocket events include `key` as the primary identifier
|
||||||
|
in their data payload. The `folder` field is optional for display purposes.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@ -58,19 +66,25 @@ async def websocket_endpoint(
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Server message format:
|
Server message format (series-related events include 'key' identifier):
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "download_progress",
|
"type": "download_progress",
|
||||||
"timestamp": "2025-10-17T10:30:00.000Z",
|
"timestamp": "2025-10-17T10:30:00.000Z",
|
||||||
"data": {
|
"data": {
|
||||||
"download_id": "abc123",
|
"download_id": "abc123",
|
||||||
|
"key": "attack-on-titan",
|
||||||
|
"folder": "Attack on Titan (2013)",
|
||||||
"percent": 45.2,
|
"percent": 45.2,
|
||||||
"speed_mbps": 2.5,
|
"speed_mbps": 2.5,
|
||||||
"eta_seconds": 180
|
"eta_seconds": 180
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note:
|
||||||
|
- `key` is the primary series identifier (provider-assigned, URL-safe)
|
||||||
|
- `folder` is optional display metadata
|
||||||
"""
|
"""
|
||||||
connection_id = str(uuid.uuid4())
|
connection_id = str(uuid.uuid4())
|
||||||
user_id: Optional[str] = None
|
user_id: Optional[str] = None
|
||||||
|
|||||||
@ -3,6 +3,15 @@
|
|||||||
This module defines message models for WebSocket communication between
|
This module defines message models for WebSocket communication between
|
||||||
the server and clients. Models ensure type safety and provide validation
|
the server and clients. Models ensure type safety and provide validation
|
||||||
for real-time updates.
|
for real-time updates.
|
||||||
|
|
||||||
|
Series Identifier Convention:
|
||||||
|
- `key`: Primary identifier for series (provider-assigned, URL-safe)
|
||||||
|
e.g., "attack-on-titan"
|
||||||
|
- `folder`: Display metadata only (e.g., "Attack on Titan (2013)")
|
||||||
|
|
||||||
|
All series-related WebSocket events should include `key` as the primary
|
||||||
|
identifier in their data payload. The `folder` field is optional and
|
||||||
|
used for display purposes only.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@ -65,7 +74,16 @@ class WebSocketMessage(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class DownloadProgressMessage(BaseModel):
|
class DownloadProgressMessage(BaseModel):
|
||||||
"""Download progress update message."""
|
"""Download progress update message.
|
||||||
|
|
||||||
|
Data payload should include:
|
||||||
|
- download_id: Unique download identifier
|
||||||
|
- key: Series identifier (primary, e.g., 'attack-on-titan')
|
||||||
|
- folder: Series folder name (optional, display only)
|
||||||
|
- percent: Download progress percentage
|
||||||
|
- speed_mbps: Download speed
|
||||||
|
- eta_seconds: Estimated time remaining
|
||||||
|
"""
|
||||||
|
|
||||||
type: WebSocketMessageType = Field(
|
type: WebSocketMessageType = Field(
|
||||||
default=WebSocketMessageType.DOWNLOAD_PROGRESS,
|
default=WebSocketMessageType.DOWNLOAD_PROGRESS,
|
||||||
@ -77,12 +95,22 @@ class DownloadProgressMessage(BaseModel):
|
|||||||
)
|
)
|
||||||
data: Dict[str, Any] = Field(
|
data: Dict[str, Any] = Field(
|
||||||
...,
|
...,
|
||||||
description="Progress data including download_id, percent, speed, eta",
|
description=(
|
||||||
|
"Progress data including download_id, key (series identifier), "
|
||||||
|
"folder (display), percent, speed_mbps, eta_seconds"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DownloadCompleteMessage(BaseModel):
|
class DownloadCompleteMessage(BaseModel):
|
||||||
"""Download completion message."""
|
"""Download completion message.
|
||||||
|
|
||||||
|
Data payload should include:
|
||||||
|
- download_id: Unique download identifier
|
||||||
|
- key: Series identifier (primary, e.g., 'attack-on-titan')
|
||||||
|
- folder: Series folder name (optional, display only)
|
||||||
|
- file_path: Path to downloaded file
|
||||||
|
"""
|
||||||
|
|
||||||
type: WebSocketMessageType = Field(
|
type: WebSocketMessageType = Field(
|
||||||
default=WebSocketMessageType.DOWNLOAD_COMPLETE,
|
default=WebSocketMessageType.DOWNLOAD_COMPLETE,
|
||||||
@ -93,12 +121,23 @@ class DownloadCompleteMessage(BaseModel):
|
|||||||
description="ISO 8601 timestamp",
|
description="ISO 8601 timestamp",
|
||||||
)
|
)
|
||||||
data: Dict[str, Any] = Field(
|
data: Dict[str, Any] = Field(
|
||||||
..., description="Completion data including download_id, file_path"
|
...,
|
||||||
|
description=(
|
||||||
|
"Completion data including download_id, key (series identifier), "
|
||||||
|
"folder (display), file_path"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DownloadFailedMessage(BaseModel):
|
class DownloadFailedMessage(BaseModel):
|
||||||
"""Download failure message."""
|
"""Download failure message.
|
||||||
|
|
||||||
|
Data payload should include:
|
||||||
|
- download_id: Unique download identifier
|
||||||
|
- key: Series identifier (primary, e.g., 'attack-on-titan')
|
||||||
|
- folder: Series folder name (optional, display only)
|
||||||
|
- error_message: Description of the failure
|
||||||
|
"""
|
||||||
|
|
||||||
type: WebSocketMessageType = Field(
|
type: WebSocketMessageType = Field(
|
||||||
default=WebSocketMessageType.DOWNLOAD_FAILED,
|
default=WebSocketMessageType.DOWNLOAD_FAILED,
|
||||||
@ -109,7 +148,11 @@ class DownloadFailedMessage(BaseModel):
|
|||||||
description="ISO 8601 timestamp",
|
description="ISO 8601 timestamp",
|
||||||
)
|
)
|
||||||
data: Dict[str, Any] = Field(
|
data: Dict[str, Any] = Field(
|
||||||
..., description="Error data including download_id, error_message"
|
...,
|
||||||
|
description=(
|
||||||
|
"Error data including download_id, key (series identifier), "
|
||||||
|
"folder (display), error_message"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,15 @@
|
|||||||
This module provides a comprehensive WebSocket manager for handling
|
This module provides a comprehensive WebSocket manager for handling
|
||||||
real-time updates, connection management, room-based messaging, and
|
real-time updates, connection management, room-based messaging, and
|
||||||
broadcast functionality for the Aniworld web application.
|
broadcast functionality for the Aniworld web application.
|
||||||
|
|
||||||
|
Series Identifier Convention:
|
||||||
|
- `key`: Primary identifier for series (provider-assigned, URL-safe)
|
||||||
|
e.g., "attack-on-titan"
|
||||||
|
- `folder`: Display metadata only (e.g., "Attack on Titan (2013)")
|
||||||
|
|
||||||
|
All broadcast methods that handle series-related data should include `key`
|
||||||
|
as the primary identifier in the message payload. The `folder` field is
|
||||||
|
optional and used for display purposes only.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@ -363,6 +372,16 @@ class WebSocketService:
|
|||||||
Args:
|
Args:
|
||||||
download_id: The download item identifier
|
download_id: The download item identifier
|
||||||
progress_data: Progress information (percent, speed, etc.)
|
progress_data: Progress information (percent, speed, etc.)
|
||||||
|
Should include 'key' (series identifier) and
|
||||||
|
optionally 'folder' (display name)
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The progress_data should include:
|
||||||
|
- key: Series identifier (primary, e.g., 'attack-on-titan')
|
||||||
|
- folder: Series folder name (optional, display only)
|
||||||
|
- percent: Download progress percentage
|
||||||
|
- speed_mbps: Download speed
|
||||||
|
- eta_seconds: Estimated time remaining
|
||||||
"""
|
"""
|
||||||
message = {
|
message = {
|
||||||
"type": "download_progress",
|
"type": "download_progress",
|
||||||
@ -382,6 +401,14 @@ class WebSocketService:
|
|||||||
Args:
|
Args:
|
||||||
download_id: The download item identifier
|
download_id: The download item identifier
|
||||||
result_data: Download result information
|
result_data: Download result information
|
||||||
|
Should include 'key' (series identifier) and
|
||||||
|
optionally 'folder' (display name)
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The result_data should include:
|
||||||
|
- key: Series identifier (primary, e.g., 'attack-on-titan')
|
||||||
|
- folder: Series folder name (optional, display only)
|
||||||
|
- file_path: Path to the downloaded file
|
||||||
"""
|
"""
|
||||||
message = {
|
message = {
|
||||||
"type": "download_complete",
|
"type": "download_complete",
|
||||||
@ -401,6 +428,14 @@ class WebSocketService:
|
|||||||
Args:
|
Args:
|
||||||
download_id: The download item identifier
|
download_id: The download item identifier
|
||||||
error_data: Error information
|
error_data: Error information
|
||||||
|
Should include 'key' (series identifier) and
|
||||||
|
optionally 'folder' (display name)
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The error_data should include:
|
||||||
|
- key: Series identifier (primary, e.g., 'attack-on-titan')
|
||||||
|
- folder: Series folder name (optional, display only)
|
||||||
|
- error_message: Description of the failure
|
||||||
"""
|
"""
|
||||||
message = {
|
message = {
|
||||||
"type": "download_failed",
|
"type": "download_failed",
|
||||||
@ -412,7 +447,9 @@ class WebSocketService:
|
|||||||
}
|
}
|
||||||
await self._manager.broadcast_to_room(message, "downloads")
|
await self._manager.broadcast_to_room(message, "downloads")
|
||||||
|
|
||||||
async def broadcast_queue_status(self, status_data: Dict[str, Any]) -> None:
|
async def broadcast_queue_status(
|
||||||
|
self, status_data: Dict[str, Any]
|
||||||
|
) -> None:
|
||||||
"""Broadcast queue status update to all clients.
|
"""Broadcast queue status update to all clients.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user