Ajoute une reference dans les VariableInstance vers leur ServiceInstance

This commit is contained in:
2025-10-10 23:49:59 +02:00
parent 4a8deae567
commit 708cefd5ab
4 changed files with 76 additions and 4 deletions

View File

@@ -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);

View File

@@ -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<ServiceInstance>
/// 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<Self>) {
let weak_self = Arc::downgrade(self);
for var in self.statevariables.all() {
var.register_service(weak_self.clone());
}
}
/// Retourne l'identifiant du service.
///
/// # Examples

View File

@@ -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<crate::services::ServiceInstance>) {
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() {
@@ -102,9 +128,23 @@ impl StateVarInstance {
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

View File

@@ -58,6 +58,8 @@ pub struct StateVarInstance {
old_value: RwLock<StateValue>,
last_modified: RwLock<DateTime<Utc>>,
last_notification: RwLock<DateTime<Utc>>,
/// Pointeur vers le service parent (interior mutability)
service: RwLock<Option<std::sync::Weak<crate::services::ServiceInstance>>>,
}
pub type StateVarInstanceSet = UpnpObjectSet<StateVarInstance>;