veza/veza-stream-server/docs/STREAM_API.md

403 lines
8.9 KiB
Markdown
Raw Normal View History

P0: stabilisation backend/chat/stream + nouvelle base migrations v1 Backend Go: - Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN. - Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError). - Sécurisation de config.go, CORS, statuts de santé et monitoring. - Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles). - Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés. - Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*. Chat server (Rust): - Refonte du pipeline JWT + sécurité, audit et rate limiting avancé. - Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing). - Nettoyage des panics, gestion d’erreurs robuste, logs structurés. - Migrations chat alignées sur le schéma UUID et nouvelles features. Stream server (Rust): - Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core. - Transactions P0 pour les jobs et segments, garanties d’atomicité. - Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION). Documentation & audits: - TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services. - Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3). - Scripts de reset et de cleanup pour la lab DB et la V1. Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
# 🌐 API REST - Documentation complète
**Date**: 2025-01-27
**Version**: 0.2.0
**Base URL**: `http://localhost:8082`
---
## Vue d'ensemble
L'API REST du stream-server permet de:
- Soumettre des fichiers audio pour transcodage
- Récupérer l'état des jobs
- Servir les fichiers HLS générés
---
## Endpoints
### POST `/v1/stream/transcode`
Soumet un fichier audio pour transcodage en HLS.
**Request**:
- **Method**: `POST`
- **Content-Type**: `multipart/form-data`
- **Body**:
- `file` (required): Fichier audio (WAV, MP3, FLAC, etc.)
- `codec` (optional): Codec cible (`aac`, `mp3`, `opus`, `flac`)
- `bitrate` (optional): Bitrate en bps (ex: `192000`)
- `quality_profile` (optional): Profil (`hi_res`, `high`, `medium`, `low`)
- `priority` (optional): Priorité (`urgent`, `normal`, `background`)
**Response** (200 OK):
```json
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued",
"message": "Job submitted successfully"
}
```
**Erreurs**:
- `400 Bad Request`: Fichier manquant ou invalide
- `500 Internal Server Error`: Erreur serveur
**Exemple cURL**:
```bash
curl -X POST http://localhost:8082/v1/stream/transcode \
-F "file=@audio.wav" \
-F "quality_profile=high" \
-F "priority=normal"
```
**Exemple JavaScript**:
```javascript
const formData = new FormData();
formData.append('file', audioFile);
formData.append('quality_profile', 'high');
const response = await fetch('http://localhost:8082/v1/stream/transcode', {
method: 'POST',
body: formData
});
const { job_id, status } = await response.json();
```
---
### GET `/v1/stream/job/{id}`
Récupère l'état d'un job de transcodage.
**Request**:
- **Method**: `GET`
- **Path Parameter**: `id` (UUID du job)
**Response** (200 OK):
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"track_id": "my_track",
"status": "processing",
"progress": 45.5,
"created_at": "SystemTime { tv_sec: 1737979200, tv_nsec: 0 }",
"started_at": "Some(SystemTime { tv_sec: 1737979205, tv_nsec: 0 })",
"completed_at": null,
"error": null
}
```
**Statuts possibles**:
- `"Pending"`: Job en attente dans la queue
- `"Processing"`: Job en cours de traitement
- `"Completed"`: Job terminé avec succès
- `"Failed(String)"`: Job échoué (le message d'erreur est dans `error`)
- `"Cancelled"`: Job annulé
**Erreurs**:
- `404 Not Found`: Job introuvable
**Exemple cURL**:
```bash
curl http://localhost:8082/v1/stream/job/550e8400-e29b-41d4-a716-446655440000
```
**Exemple JavaScript**:
```javascript
const response = await fetch(`http://localhost:8082/v1/stream/job/${jobId}`);
const status = await response.json();
if (status.status === 'Completed') {
console.log('Job terminé!');
} else if (status.status.startsWith('Failed')) {
console.error('Erreur:', status.error);
}
```
---
### GET `/v1/stream/hls/{job_id}/index.m3u8`
Sert le manifest HLS pour un job terminé.
**Request**:
- **Method**: `GET`
- **Path Parameter**: `job_id` (UUID du job)
- **Headers**: Aucun requis
**Response** (200 OK):
- **Content-Type**: `application/vnd.apple.mpegurl`
- **Body**: Contenu du fichier `index.m3u8`
**Exemple de contenu**:
```m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.0,
segment_00001.ts
#EXTINF:6.0,
segment_00002.ts
#EXTINF:6.0,
segment_00003.ts
#EXT-X-ENDLIST
```
**Erreurs**:
- `404 Not Found`: Job introuvable ou manifest non généré
- `400 Bad Request`: Job non terminé
**Exemple cURL**:
```bash
curl http://localhost:8082/v1/stream/hls/550e8400-e29b-41d4-a716-446655440000/index.m3u8
```
**Exemple JavaScript**:
```javascript
const manifestUrl = `http://localhost:8082/v1/stream/hls/${jobId}/index.m3u8`;
// Utiliser avec hls.js
import Hls from 'hls.js';
const hls = new Hls();
hls.loadSource(manifestUrl);
hls.attachMedia(audioElement);
```
---
### GET `/v1/stream/hls/{job_id}/{segment}`
Sert un segment HLS (.ts).
**Request**:
- **Method**: `GET`
- **Path Parameters**:
- `job_id`: UUID du job
- `segment`: Nom du segment (ex: `segment_00001.ts`)
**Response** (200 OK):
- **Content-Type**: `video/mp2t`
- **Body**: Contenu binaire du segment
**Erreurs**:
- `404 Not Found`: Segment introuvable
**Exemple cURL**:
```bash
curl http://localhost:8082/v1/stream/hls/550e8400-e29b-41d4-a716-446655440000/segment_00001.ts \
--output segment_00001.ts
```
**Note**: Généralement appelé automatiquement par le player HLS lors du parsing du manifest.
---
## Workflow complet
### 1. Soumettre un job
```javascript
const formData = new FormData();
formData.append('file', audioFile);
formData.append('quality_profile', 'high');
const submitResponse = await fetch('http://localhost:8082/v1/stream/transcode', {
method: 'POST',
body: formData
});
const { job_id } = await submitResponse.json();
console.log('Job soumis:', job_id);
```
### 2. Poller l'état
```javascript
async function pollJobStatus(jobId) {
while (true) {
const response = await fetch(`http://localhost:8082/v1/stream/job/${jobId}`);
const status = await response.json();
console.log(`Statut: ${status.status}, Progression: ${status.progress}%`);
if (status.status === 'Completed') {
return status;
} else if (status.status.startsWith('Failed')) {
throw new Error(status.error);
}
// Attendre 2 secondes avant le prochain poll
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
const completedJob = await pollJobStatus(jobId);
```
### 3. Charger le manifest HLS
```javascript
const manifestUrl = `http://localhost:8082/v1/stream/hls/${jobId}/index.m3u8`;
// Avec hls.js
import Hls from 'hls.js';
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(manifestUrl);
hls.attachMedia(audioElement);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
console.log('Manifest chargé, prêt à jouer');
audioElement.play();
});
} else if (audioElement.canPlayType('application/vnd.apple.mpegurl')) {
// Support natif (Safari)
audioElement.src = manifestUrl;
audioElement.addEventListener('loadedmetadata', () => {
audioElement.play();
});
}
```
---
## Codes d'erreur
### 400 Bad Request
- Fichier manquant dans la requête
- Format de fichier invalide
- Paramètres invalides
### 404 Not Found
- Job introuvable
- Manifest HLS introuvable
- Segment introuvable
### 500 Internal Server Error
- Erreur serveur interne
- Échec de soumission du job
- Erreur de traitement
---
## Rate limiting
Actuellement non implémenté (P0). À ajouter en P1.
---
## Authentification
Actuellement non requise (P0). À ajouter en P1 avec JWT.
---
## CORS
CORS configuré pour:
- `http://localhost:5176` (Vite dev)
- `http://localhost:3000` (React dev)
Configurable via variable d'environnement `ALLOWED_ORIGINS`.
---
## Exemples complets
### Python
```python
import requests
import time
import uuid
# 1. Soumettre un job
with open('audio.wav', 'rb') as f:
response = requests.post(
'http://localhost:8082/v1/stream/transcode',
files={'file': f},
data={'quality_profile': 'high'}
)
job_id = response.json()['job_id']
# 2. Poller l'état
while True:
response = requests.get(f'http://localhost:8082/v1/stream/job/{job_id}')
status = response.json()
print(f"Statut: {status['status']}, Progression: {status['progress']}%")
if status['status'] == 'Completed':
break
elif status['status'].startswith('Failed'):
raise Exception(status['error'])
time.sleep(2)
# 3. URL du manifest
manifest_url = f'http://localhost:8082/v1/stream/hls/{job_id}/index.m3u8'
print(f"Manifest HLS: {manifest_url}")
```
### Node.js
```javascript
const FormData = require('form-data');
const fs = require('fs');
const fetch = require('node-fetch');
async function transcodeAudio(filePath) {
// 1. Soumettre
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
form.append('quality_profile', 'high');
const submitRes = await fetch('http://localhost:8082/v1/stream/transcode', {
method: 'POST',
body: form
});
const { job_id } = await submitRes.json();
// 2. Poller
while (true) {
const statusRes = await fetch(`http://localhost:8082/v1/stream/job/${job_id}`);
const status = await statusRes.json();
if (status.status === 'Completed') {
return `http://localhost:8082/v1/stream/hls/${job_id}/index.m3u8`;
} else if (status.status.startsWith('Failed')) {
throw new Error(status.error);
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
// Usage
transcodeAudio('./audio.wav')
.then(manifestUrl => console.log('Manifest:', manifestUrl))
.catch(console.error);
```
---
## Changelog
### v0.2.0 (2025-01-27)
- ✅ Ajout endpoints `/v1/stream/transcode`
- ✅ Ajout endpoint `/v1/stream/job/{id}`
- ✅ Ajout endpoints HLS `/v1/stream/hls/{job_id}/...`
- ✅ Support multipart/form-data pour upload
- ✅ Gestion des erreurs et statuts
---
**Prochaine étape**: Voir `STREAM_PIPELINE.md` pour l'architecture interne.