use std::fmt; use std::sync::Arc; use bevy_reflect::Reflect; use chrono::{DateTime, Utc}; use std::sync::RwLock; use xmltree::Element; use crate::{ UpnpObjectType, UpnpTyped, UpnpTypedInstance, object_trait::{UpnpInstance, UpnpObject}, state_variables::{StateVarInstance, StateVariable, UpnpVariable}, variable_types::{StateValue, StateValueError, UpnpVarType}, }; impl UpnpVariable for StateVarInstance { fn get_definition(&self) -> &StateVariable { return &self.model; } } impl UpnpObject for StateVarInstance { fn to_xml_element(&self) -> Element { self.get_definition().to_xml_element() } } impl UpnpVarType for StateVarInstance { fn as_state_var_type(&self) -> crate::variable_types::StateVarType { self.get_definition().as_state_var_type() } } impl UpnpInstance for StateVarInstance { type Model = StateVariable; fn new(from: &StateVariable) -> Self { Self { object: UpnpObjectType { name: from.object.name.clone(), object_type: "StateVarInstance".to_string(), }, model: from.clone(), value: RwLock::new(from.get_default()), old_value: RwLock::new(from.get_default()), last_modified: RwLock::new(Utc::now()), last_notification: RwLock::new(Utc::now()), service: RwLock::new(None), reflexive_cache: RwLock::new(None), } } } impl UpnpTyped for StateVarInstance { fn as_upnp_object_type(&self) -> &UpnpObjectType { return &self.object; } } impl UpnpTypedInstance for StateVarInstance { fn get_model(&self) -> &Self::Model { &self.model } } impl fmt::Debug for StateVarInstance { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StateVarInstance") .field("object", &self.object) .field("model", &self.model) .field("value", &self.value) .field("old_value", &self.old_value) .field("last_modified", &self.last_modified) .field("last_notification", &self.last_notification) .finish() } } impl Clone for StateVarInstance { fn clone(&self) -> Self { Self { object: self.object.clone(), model: self.model.clone(), value: RwLock::new(self.value.read().unwrap().clone()), 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()), reflexive_cache: RwLock::new(None), // Le cache n'est pas cloné, il sera recalculé si nécessaire } } } 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() { return Err(StateValueError::TypeError( "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.clone(); *modified = Utc::now(); // Invalider le cache réflexif { let mut cache = self.reflexive_cache.write().unwrap(); *cache = None; } // 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() { // Obtenir la valeur réflexive (sans propager l'erreur car on est dans une notification) if let Ok(reflected_value) = self.reflexive_value() { service.event_to_be_sent(self.get_name().to_string(), reflected_value); } } } } Ok(()) } /// Accès à la valeur pub fn value(&self) -> StateValue { self.value.read().unwrap().clone() } /// Accès au timestamp pub fn last_modified(&self) -> DateTime { self.last_modified.read().unwrap().clone() } /// Retourne la valeur sous forme réflexive (Reflect). /// /// Cette méthode utilise un cache pour optimiser les performances lorsqu'un parser /// est défini. Si la variable a un parser, la valeur String sera parsée et le résultat /// sera mis en cache. Sinon, la StateValue brute est retournée directement comme Reflect. /// /// Le cache est invalidé automatiquement lors de `set_value()`. /// /// # Returns /// /// Un `Arc` contenant soit: /// - La valeur parsée (si un parser est défini) /// - La StateValue brute (sinon) /// /// # Examples /// /// ```rust,ignore /// let var = StateVarInstance::new(&variable); /// let reflected = var.reflexive_value(); /// // reflected peut maintenant être inspecté avec l'API Reflect /// ``` pub fn reflexive_value( &self, ) -> Result, crate::state_variables::StateVariableError> { // Vérifier si on a un cache valide { let cache = self.reflexive_cache.read().unwrap(); if let Some(cached) = cache.as_ref() { return Ok(Arc::clone(cached)); } } // Pas de cache, il faut calculer la valeur let value = self.value.read().unwrap().clone(); // Si la variable a un parser, l'utiliser if let Some(parser) = &self.model.parse { // La valeur doit être une String pour être parsée if let crate::variable_types::StateValue::String(s) = &value { match parser(s) { Ok(parsed) => { // Convertir Box en Arc let arc_reflect: Arc = Arc::from(parsed); // Mettre en cache let mut cache = self.reflexive_cache.write().unwrap(); *cache = Some(Arc::clone(&arc_reflect)); return Ok(arc_reflect); } Err(e) => return Err(e), } } } // Pas de parser ou la valeur n'est pas une String: convertir la StateValue en Reflect let reflected = value.to_reflect(); let arc_reflect: Arc = Arc::from(reflected); // Mettre en cache let mut cache = self.reflexive_cache.write().unwrap(); *cache = Some(Arc::clone(&arc_reflect)); Ok(arc_reflect) } /// Convertit la valeur actuelle en Box /// /// - Si type String ET parser défini : utilise le parser /// - Sinon : utilise StateValue::to_reflect() directement /// /// # Returns /// /// Un `Box` contenant la valeur actuelle pub fn to_reflect(&self) -> Box { let current_value = self.value.read().unwrap().clone(); self.parse_value(current_value) } pub fn parse_value(&self, value: StateValue) -> Box { use crate::variable_types::StateVarType; // Parser uniquement pour les String if self.as_state_var_type() == StateVarType::String { if let StateValue::String(ref s) = value { if let Some(ref parser) = self.model.parse { match parser(s) { Ok(reflected) => return reflected, Err(e) => { tracing::warn!( "Failed to parse value '{}' for variable '{}': {:?}, using raw string", s, self.get_name(), e ); } } } } } value.to_reflect() } /// Définit la valeur depuis Box /// /// - Si type String ET marshal défini : utilise le marshal /// - Sinon : utilise StateValue::from_reflect() directement /// /// Puis délègue à set_value() pour la mise à jour et les notifications /// /// # Arguments /// /// * `reflect_value` - La nouvelle valeur sous forme Reflect /// /// # Errors /// /// Retourne une erreur si : /// - La conversion Reflect → StateValue échoue /// - Le marshalling échoue /// - La mise à jour de la valeur échoue pub async fn set_reflect_value( &self, reflect_value: Box, ) -> Result<(), StateValueError> { use crate::variable_types::StateVarType; // Convertir Reflect → StateValue let state_value = if self.as_state_var_type() == StateVarType::String { // Pour les String : essayer le marshal si défini if let Some(ref marshal) = self.model.marshal { // D'abord, essayer de convertir Reflect → StateValue temporaire match StateValue::from_reflect(reflect_value.as_ref(), self.as_state_var_type()) { Ok(temp_value) => { // Utiliser le marshal pour obtenir la String marshallée match marshal(&temp_value) { Ok(marshalled_string) => StateValue::String(marshalled_string), Err(e) => { tracing::warn!( "Failed to marshal value for variable '{}': {:?}, using standard conversion", self.get_name(), e ); // Fallback temp_value } } } Err(e) => return Err(e), } } else { // Pas de marshal, conversion standard StateValue::from_reflect(reflect_value.as_ref(), self.as_state_var_type())? } } else { // Pas un String, conversion standard StateValue::from_reflect(reflect_value.as_ref(), self.as_state_var_type())? }; // Déléguer à set_value() pour factoriser (mise à jour + notifications) self.set_value(state_value).await } }