From 1abe80f74a0b39895d9c5b8007f0bcab9d7e08c0 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Fri, 10 Oct 2025 23:49:59 +0200 Subject: [PATCH] Ajoute une reference dans les VariableInstance vers leur ServiceInstance --- pmoupnp/src/devices/device_methods.rs | 4 ++ pmoupnp/src/services/service_instance.rs | 26 ++++++++++ .../src/state_variables/instance_methods.rs | 48 +++++++++++++++++-- pmoupnp/src/state_variables/mod.rs | 2 + 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/pmoupnp/src/devices/device_methods.rs b/pmoupnp/src/devices/device_methods.rs index 6e131fd2..6590d788 100644 --- a/pmoupnp/src/devices/device_methods.rs +++ b/pmoupnp/src/devices/device_methods.rs @@ -129,6 +129,10 @@ impl UpnpModel for Device { // Créer les instances de services depuis le modèle for service_model in self.services() { let service_instance = service_model.create_instance(); + + // Enregistrer le service auprès de ses variables + service_instance.register_with_variables(); + service_instance.set_device(Arc::clone(&instance)); if let Err(e) = instance.add_service(service_instance) { tracing::error!("Failed to add service instance: {:?}", e); diff --git a/pmoupnp/src/services/service_instance.rs b/pmoupnp/src/services/service_instance.rs index a335ca23..19093c2e 100644 --- a/pmoupnp/src/services/service_instance.rs +++ b/pmoupnp/src/services/service_instance.rs @@ -252,6 +252,32 @@ impl UpnpObject for ServiceInstance { } impl ServiceInstance { + /// Enregistre cette instance de service auprès de toutes ses variables. + /// + /// Cette méthode doit être appelée APRÈS la création de l'Arc + /// pour permettre aux variables de notifier le service lors de leurs changements. + /// + /// # Arguments + /// + /// * `self_arc` - Arc pointant vers cette instance + /// + /// # Examples + /// + /// ```rust,ignore + /// # use pmoupnp::services::Service; + /// # use pmoupnp::UpnpModel; + /// # use std::sync::Arc; + /// let service = Service::new("AVTransport".to_string()); + /// let instance = Arc::new(service.create_instance()); + /// instance.register_with_variables(&instance); + /// ``` + pub fn register_with_variables(self: &Arc) { + let weak_self = Arc::downgrade(self); + for var in self.statevariables.all() { + var.register_service(weak_self.clone()); + } + } + /// Retourne l'identifiant du service. /// /// # Examples diff --git a/pmoupnp/src/state_variables/instance_methods.rs b/pmoupnp/src/state_variables/instance_methods.rs index 46b74d40..de079a6a 100644 --- a/pmoupnp/src/state_variables/instance_methods.rs +++ b/pmoupnp/src/state_variables/instance_methods.rs @@ -43,6 +43,7 @@ impl UpnpInstance for StateVarInstance { old_value: RwLock::new(from.get_default()), last_modified: RwLock::new(Utc::now()), last_notification: RwLock::new(Utc::now()), + service: RwLock::new(None), } } @@ -83,11 +84,36 @@ impl Clone for StateVarInstance { old_value: RwLock::new(self.old_value.read().unwrap().clone()), last_modified: RwLock::new(self.last_modified.read().unwrap().clone()), last_notification: RwLock::new(self.last_notification.read().unwrap().clone()), + service: RwLock::new(self.service.read().unwrap().clone()), } } } impl StateVarInstance { + /// Enregistre le service parent pour cette variable. + /// + /// Cette méthode doit être appelée depuis `ServiceInstance::new()` pour + /// permettre à la variable de notifier le service lorsqu'elle change. + /// + /// # Arguments + /// + /// * `service` - Arc vers le ServiceInstance parent + /// + /// # Examples + /// + /// ```rust,ignore + /// # use pmoupnp::services::ServiceInstance; + /// # use pmoupnp::state_variables::StateVarInstance; + /// # use std::sync::Arc; + /// let service_instance = Arc::new(ServiceInstance::new(&service)); + /// let var_instance = Arc::new(StateVarInstance::new(&variable)); + /// var_instance.register_service(Arc::downgrade(&service_instance)); + /// ``` + pub fn register_service(&self, service: std::sync::Weak) { + let mut svc = self.service.write().unwrap(); + *svc = Some(service); + } + pub async fn set_value(&self, new_value: StateValue) -> Result<(), StateValueError> { // Validation du type if self.as_state_var_type() != new_value.as_state_var_type() { @@ -95,16 +121,30 @@ impl StateVarInstance { "Value type mismatch".to_string() )); } - + // Mise à jour avec les locks let mut old_val = self.old_value.write().unwrap(); let mut val = self.value.write().unwrap(); let mut modified = self.last_modified.write().unwrap(); - + *old_val = val.clone(); - *val = new_value; + *val = new_value.clone(); *modified = Utc::now(); - + + // Notifier le service parent si la variable envoie des événements + if self.is_sending_notification() { + // Relâcher les locks avant d'appeler le service + drop(val); + drop(old_val); + drop(modified); + + if let Some(weak_service) = self.service.read().unwrap().as_ref() { + if let Some(service) = weak_service.upgrade() { + service.event_to_be_sent(self.get_name().to_string(), new_value.to_string()); + } + } + } + Ok(()) } /// Accès à la valeur diff --git a/pmoupnp/src/state_variables/mod.rs b/pmoupnp/src/state_variables/mod.rs index 137d1e45..389fda28 100644 --- a/pmoupnp/src/state_variables/mod.rs +++ b/pmoupnp/src/state_variables/mod.rs @@ -58,6 +58,8 @@ pub struct StateVarInstance { old_value: RwLock, last_modified: RwLock>, last_notification: RwLock>, + /// Pointeur vers le service parent (interior mutability) + service: RwLock>>, } pub type StateVarInstanceSet = UpnpObjectSet;