From adeb37ce83a7b1b9064ffa183f59886f0bace27d Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Mon, 6 Oct 2025 12:15:33 +0200 Subject: [PATCH] Connection de la couche sspd aux instances --- Cargo.lock | 1 + PMOMusic/src/main.rs | 91 +++++++++++++++++++------- pmoupnp/Cargo.toml | 1 + pmoupnp/src/devices/device_instance.rs | 10 ++- 4 files changed, 78 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d372720..fc276813 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1515,6 +1515,7 @@ dependencies = [ "parking_lot", "pmoconfig", "pmodidl", + "pmoutils", "reqwest", "serde", "serde_json", diff --git a/PMOMusic/src/main.rs b/PMOMusic/src/main.rs index 4e75369f..905558ac 100644 --- a/PMOMusic/src/main.rs +++ b/PMOMusic/src/main.rs @@ -1,4 +1,8 @@ -use pmoupnp::{mediarenderer::avtransport::AVTTRANSPORT, UpnpObject}; +use pmoupnp::{ + mediarenderer::MEDIA_RENDERER, + ssdp::{SsdpDevice, SsdpServer}, + UpnpModel, +}; use pmoserver::{ logs::{log_dump, log_sse, LogState, SseLayer}, ServerBuilder @@ -10,17 +14,22 @@ use tracing::info; #[tokio::main] async fn main() { - // Charger la config + // Initialiser le logging d'abord + let log_state = LogState::new(1000); + let subscriber = Registry::default() + .with( + tracing_subscriber::fmt::layer() + .with_target(true) + .with_level(true) + .with_ansi(true), + ) + .with(SseLayer::new(log_state.clone())); + tracing::subscriber::set_global_default(subscriber).unwrap(); + // Créer le serveur let mut server = ServerBuilder::new_configured().build(); - // Ajouter des routes - server - .add_route("/hello", || async { - serde_json::json!({"message": "Hello World"}) - }) - .await; - + // Routes de base server .add_route("/info", || async { serde_json::json!({"version": "1.0.0"}) @@ -29,18 +38,7 @@ async fn main() { server.add_spa::("/app").await; - // Gère la sortie des logs et sur le serveur SSE pour l'interface web et sur la console - let log_state = LogState::new(1000); - let subscriber = Registry::default() - .with( - tracing_subscriber::fmt::layer() - .with_target(true) - .with_level(true) - .with_ansi(true), // Couleurs dans le terminal - ) - .with(SseLayer::new(log_state.clone())); - tracing::subscriber::set_global_default(subscriber).unwrap(); - + // Routes de logging server .add_handler_with_state("/log-sse", log_sse, log_state.clone()) .await; @@ -50,8 +48,55 @@ async fn main() { server.add_redirect("/", "/app").await; - info!("{}",AVTTRANSPORT.to_markdown()); - info!("{}",AVTTRANSPORT.scpd_xml()); + // Créer et enregistrer le MediaRenderer + info!("🎵 Creating MediaRenderer instance..."); + let renderer_instance = MEDIA_RENDERER.create_instance(); + + // Créer et ajouter les instances de services + for service in MEDIA_RENDERER.services().iter() { + let service_instance = service.create_instance(); + renderer_instance + .add_service(service_instance) + .expect("Failed to add service to renderer"); + } + + info!("📡 Registering MediaRenderer routes..."); + renderer_instance + .register_urls(&mut server) + .await + .expect("Failed to register MediaRenderer routes"); + + info!("✅ MediaRenderer ready at {}{}", + renderer_instance.base_url(), + renderer_instance.description_route() + ); + + // Créer et démarrer le serveur SSDP + info!("📡 Starting SSDP discovery..."); + let mut ssdp_server = SsdpServer::new(); + ssdp_server.start().expect("Failed to start SSDP server"); + + // Créer le device SSDP pour le MediaRenderer + let location = format!("{}{}", + renderer_instance.base_url(), + renderer_instance.description_route() + ); + + let mut ssdp_device = SsdpDevice::new( + renderer_instance.udn().to_string(), + MEDIA_RENDERER.device_type(), + location, + format!("Linux/5.0 UPnP/1.1 PMOMusic/1.0"), + ); + + // Ajouter les types de notification pour chaque service + for service in renderer_instance.services() { + ssdp_device.add_notification_type(service.service_type()); + } + + // Enregistrer le device et envoyer les annonces SSDP + ssdp_server.add_device(ssdp_device); + info!("✅ SSDP announcements sent for MediaRenderer"); server.start().await; server.wait().await; diff --git a/pmoupnp/Cargo.toml b/pmoupnp/Cargo.toml index d6bf20b4..3d550251 100644 --- a/pmoupnp/Cargo.toml +++ b/pmoupnp/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] pmoconfig = { path = "../pmoconfig" } pmodidl = { path = "../pmodidl"} +pmoutils = { path = "../pmoutils" } url = "2.5.7" uuid = "1.18.1" diff --git a/pmoupnp/src/devices/device_instance.rs b/pmoupnp/src/devices/device_instance.rs index 26526aa1..1aa2f6c4 100644 --- a/pmoupnp/src/devices/device_instance.rs +++ b/pmoupnp/src/devices/device_instance.rs @@ -87,6 +87,11 @@ impl UpnpInstance for DeviceInstance { format!("uuid:{}_{}", model.udn_prefix(), uuid::Uuid::new_v4()) }; + // Obtenir l'IP locale et le port depuis la configuration + let local_ip = pmoutils::guess_local_ip(); + let port = pmoconfig::get_config().get_http_port(); + let server_base_url = format!("http://{}:{}", local_ip, port); + Self { object: UpnpObjectType { name: model.get_name().to_string(), @@ -94,7 +99,7 @@ impl UpnpInstance for DeviceInstance { }, model: Arc::new(model.clone()), udn, - server_base_url: "http://localhost:8080".to_string(), + server_base_url, services: RwLock::new(HashMap::new()), devices: RwLock::new(HashMap::new()), } @@ -184,8 +189,9 @@ impl DeviceInstance { } /// Retourne la route du device (chemin relatif). + /// Utilise l'UDN pour garantir l'unicité si plusieurs devices du même type existent. pub fn route(&self) -> String { - format!("/device/{}", self.get_name()) + format!("/device/{}", self.udn()) } /// Retourne la route de description du device.