⬆️ refactor(sse): migrate event processing to fully async
- Convert `renderer_event_to_payload` and `media_server_sse::event_handler`s to async - Replace sync cover URL transformation with `.await` on `transform_cover_url` - Remove blocking thread-based workarounds for async execution - Improve SSE scalability and responsiveness by eliminating nested runtimes
This commit is contained in:
@@ -360,4 +360,46 @@ fn transform_external_cover_url(url: &str) -> String {
|
||||
|
||||
1. **Nouveau** : `pmocovers/src/proxy.rs` - Endpoint de proxy
|
||||
2. **Modifier** : `pmocontrol/src/pmoserver_ext.rs` - Transformer les album_art_uri
|
||||
3. **Modifier** : `pmocontrol/src/sse.rs` - Transformer les album_art_uri dans les événements
|
||||
3. **Modifier** : `pmocontrol/src/sse.rs` - Transformer les album_art_uri dans les événements
|
||||
|
||||
---
|
||||
|
||||
## Plan: Passer le SSE en mode Async
|
||||
|
||||
### Contexte
|
||||
|
||||
Le SSE de PMO Control est **déjà async** (fonctions `pub async fn`), mais le traitement des événements utilise des fonctions **synchrones** (`fn renderer_event_to_payload` → `transform_cover_url_sync`). Cela nécessite des workarounds (threads avec runtime tokio séparés).
|
||||
|
||||
### Problèmes actuels
|
||||
|
||||
1. **Nested runtime**: `std::thread::spawn` avec `tokio::runtime::Runtime::new()` dans chaque appel
|
||||
2. **Performance dégradée**: Création d'un thread par URL de cover
|
||||
3. **Code complexe**: Workarounds pour exécuter de l'async dans du sync
|
||||
|
||||
### Solution
|
||||
|
||||
Rendre le traitement des événements **entièrement async** :
|
||||
|
||||
1. **Modifier** `renderer_event_to_payload` → `async fn renderer_event_to_payload`
|
||||
2. **Modifier** `transform_cover_url_sync` → `transform_cover_url` (async) avec `.await` direct
|
||||
3. **Supprimer** le workaround `proxy_cover_url_sync` dans `pmocovers` (quand les .await fonctionnent)
|
||||
|
||||
### Avantages attendus
|
||||
|
||||
1. **Fluidité accrue**: Pas de thread par cover,真正的 async/await
|
||||
2. **Meilleure réactivité**: Pas de blocking sur les événements SSE
|
||||
3. **Code plus propre**: Plus de workarounds, plus de runtime imbriqué
|
||||
4. **Meilleure scalabilité**: Plus de création de thread
|
||||
|
||||
### Fichiers à modifier
|
||||
|
||||
1. `pmocontrol/src/sse.rs`:
|
||||
- `renderer_event_to_payload` → `async fn`
|
||||
- `media_server_event_to_payload` → `async fn`
|
||||
- `all_events_sse`: utiliser les versions async
|
||||
|
||||
2. `pmocontrol/src/pmoserver_ext.rs`:
|
||||
- Utiliser `transform_cover_url` (async) avec `.await` au lieu de `transform_cover_url_sync`
|
||||
|
||||
3. `pmocontrol/src/control_point.rs` (si nécessaire):
|
||||
- Adapter les appels aux fonctions async
|
||||
@@ -248,7 +248,7 @@ pub enum UnifiedEventPayload {
|
||||
/// Cette fonction centralise la conversion pour éviter la duplication de code
|
||||
/// entre les différents streams SSE (renderers-only et all-events).
|
||||
#[cfg(feature = "pmoserver")]
|
||||
fn renderer_event_to_payload(
|
||||
async fn renderer_event_to_payload(
|
||||
event: RendererEvent,
|
||||
timestamp: chrono::DateTime<chrono::Utc>,
|
||||
base_url: &pmoserver::BaseUrl,
|
||||
@@ -281,7 +281,7 @@ fn renderer_event_to_payload(
|
||||
title: metadata.title,
|
||||
artist: metadata.artist,
|
||||
album: metadata.album,
|
||||
album_art_uri: transform_cover_url_sync(metadata.album_art_uri.as_deref(), base_url),
|
||||
album_art_uri: transform_cover_url(metadata.album_art_uri.as_deref(), base_url).await,
|
||||
timestamp,
|
||||
},
|
||||
RendererEvent::QueueUpdated { id, queue_length } => RendererEventPayload::QueueUpdated {
|
||||
@@ -361,7 +361,7 @@ fn renderer_event_to_payload(
|
||||
/// Cette fonction centralise la conversion pour éviter la duplication de code
|
||||
/// entre les différents streams SSE (servers-only et all-events).
|
||||
#[cfg(feature = "pmoserver")]
|
||||
fn media_server_event_to_payload(
|
||||
async fn media_server_event_to_payload(
|
||||
event: MediaServerEvent,
|
||||
timestamp: chrono::DateTime<chrono::Utc>,
|
||||
) -> MediaServerEventPayload {
|
||||
@@ -480,7 +480,7 @@ pub async fn renderer_events_sse(
|
||||
// Regular events from the control point
|
||||
Some(event) = rx_tokio.recv() => {
|
||||
let timestamp = chrono::Utc::now();
|
||||
let payload = renderer_event_to_payload(event, timestamp, &base_url);
|
||||
let payload = renderer_event_to_payload(event, timestamp, &base_url).await;
|
||||
|
||||
if let Ok(json) = serde_json::to_string(&payload) {
|
||||
yield Ok::<_, axum::Error>(Event::default().event("renderer").data(json));
|
||||
@@ -602,7 +602,7 @@ pub async fn media_server_events_sse(
|
||||
// Regular events from the control point
|
||||
Some(event) = rx_tokio.recv() => {
|
||||
let timestamp = chrono::Utc::now();
|
||||
let payload = media_server_event_to_payload(event, timestamp);
|
||||
let payload = media_server_event_to_payload(event, timestamp).await;
|
||||
|
||||
if let Ok(json) = serde_json::to_string(&payload) {
|
||||
yield Ok::<_, axum::Error>(Event::default().event("media_server").data(json));
|
||||
@@ -758,7 +758,7 @@ pub async fn all_events_sse(
|
||||
tokio::select! {
|
||||
Some(event) = renderer_rx_tokio.recv() => {
|
||||
let timestamp = chrono::Utc::now();
|
||||
let renderer_payload = renderer_event_to_payload(event, timestamp, &base_url);
|
||||
let renderer_payload = renderer_event_to_payload(event, timestamp, &base_url).await;
|
||||
|
||||
let payload = UnifiedEventPayload::Renderer(renderer_payload);
|
||||
|
||||
@@ -768,7 +768,7 @@ pub async fn all_events_sse(
|
||||
}
|
||||
Some(event) = server_rx_tokio.recv() => {
|
||||
let timestamp = chrono::Utc::now();
|
||||
let server_payload = media_server_event_to_payload(event, timestamp);
|
||||
let server_payload = media_server_event_to_payload(event, timestamp).await;
|
||||
let payload = UnifiedEventPayload::MediaServer(server_payload);
|
||||
|
||||
if let Ok(json) = serde_json::to_string(&payload) {
|
||||
|
||||
Reference in New Issue
Block a user