lastest clean version
This commit is contained in:
@@ -400,15 +400,15 @@ impl Service {
|
||||
format!("/service/{}", self.name())
|
||||
}
|
||||
|
||||
pub fn scpd_url(&self) -> String {
|
||||
pub fn scpd_route(&self) -> String {
|
||||
format!("{}/desc.xml", self.service_base_url())
|
||||
}
|
||||
|
||||
pub fn control_url(&self) -> String {
|
||||
pub fn control_route(&self) -> String {
|
||||
format!("{}/control", self.service_base_url())
|
||||
}
|
||||
|
||||
pub fn event_url(&self) -> String {
|
||||
pub fn event_route(&self) -> String {
|
||||
format!("{}/event", self.service_base_url())
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::{
|
||||
services::{Service, ServiceError},
|
||||
actions::{ActionInstance, ActionInstanceSet},
|
||||
state_variables::{StateVarInstance, StateVarInstanceSet, UpnpVariable},
|
||||
devices::DeviceInstance,
|
||||
UpnpObject, UpnpInstance, UpnpTyped, UpnpTypedInstance, UpnpObjectType,
|
||||
};
|
||||
|
||||
@@ -74,8 +75,8 @@ pub struct ServiceInstance {
|
||||
/// Identifiant du service
|
||||
identifier: String,
|
||||
|
||||
/// Device parent (optionnel)
|
||||
device: Option<Arc<DeviceStub>>,
|
||||
/// Device parent (optionnel) - utilisé via interior mutability
|
||||
device: Arc<RwLock<Option<Arc<DeviceInstance>>>>,
|
||||
|
||||
/// Variables d'état instanciées
|
||||
statevariables: StateVarInstanceSet,
|
||||
@@ -93,31 +94,6 @@ pub struct ServiceInstance {
|
||||
seqid: Arc<Mutex<HashMap<String, u32>>>,
|
||||
}
|
||||
|
||||
// Stub temporaire pour DeviceInstance
|
||||
// TODO: Remplacer par la vraie implémentation quand le module devices sera créé
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DeviceStub {
|
||||
name: String,
|
||||
udn: String,
|
||||
}
|
||||
|
||||
impl DeviceStub {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn base_route(&self) -> String {
|
||||
format!("/device/{}", self.name)
|
||||
}
|
||||
|
||||
pub fn udn(&self) -> &str {
|
||||
&self.udn
|
||||
}
|
||||
|
||||
pub fn server_base_url(&self) -> String {
|
||||
"http://localhost:8080".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ServiceInstance {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -195,7 +171,7 @@ impl UpnpInstance for ServiceInstance {
|
||||
},
|
||||
model: Arc::new(model.clone()),
|
||||
identifier: model.identifier().to_string(),
|
||||
device: None,
|
||||
device: Arc::new(RwLock::new(None)),
|
||||
statevariables,
|
||||
actions,
|
||||
subscribers: Arc::new(RwLock::new(HashMap::new())),
|
||||
@@ -224,15 +200,15 @@ impl UpnpObject for ServiceInstance {
|
||||
elem.children.push(XMLNode::Element(service_id));
|
||||
|
||||
let mut scpd_url = Element::new("SCPDURL");
|
||||
scpd_url.children.push(XMLNode::Text(self.scpd_url()));
|
||||
scpd_url.children.push(XMLNode::Text(self.scpd_route()));
|
||||
elem.children.push(XMLNode::Element(scpd_url));
|
||||
|
||||
let mut control_url = Element::new("controlURL");
|
||||
control_url.children.push(XMLNode::Text(self.control_url()));
|
||||
control_url.children.push(XMLNode::Text(self.control_route()));
|
||||
elem.children.push(XMLNode::Element(control_url));
|
||||
|
||||
let mut event_sub_url = Element::new("eventSubURL");
|
||||
event_sub_url.children.push(XMLNode::Text(self.event_sub_url()));
|
||||
event_sub_url.children.push(XMLNode::Text(self.event_route()));
|
||||
elem.children.push(XMLNode::Element(event_sub_url));
|
||||
|
||||
elem
|
||||
@@ -269,32 +245,43 @@ impl ServiceInstance {
|
||||
self.actions.get_by_name(name)
|
||||
}
|
||||
|
||||
/// Retourne la route de base du service.
|
||||
pub fn base_route(&self) -> String {
|
||||
match &self.device {
|
||||
Some(device) => format!("{}/service/{}", device.base_route(), self.get_name()),
|
||||
/// Définit le device parent pour ce service.
|
||||
///
|
||||
/// Cette méthode doit être appelée après la création du service instance
|
||||
/// pour établir la relation avec le device parent.
|
||||
pub fn set_device(&self, device: Arc<DeviceInstance>) {
|
||||
let mut dev = self.device.write().unwrap();
|
||||
*dev = Some(device);
|
||||
}
|
||||
|
||||
/// Retourne la route du service (chemin relatif).
|
||||
pub fn route(&self) -> String {
|
||||
let device = self.device.read().unwrap();
|
||||
match device.as_ref() {
|
||||
Some(device) => format!("{}/service/{}", device.route(), self.get_name()),
|
||||
None => format!("/service/{}", self.get_name()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retourne l'URL de contrôle SOAP.
|
||||
pub fn control_url(&self) -> String {
|
||||
format!("{}/control", self.base_route())
|
||||
/// Retourne la route de contrôle SOAP.
|
||||
pub fn control_route(&self) -> String {
|
||||
format!("{}/control", self.route())
|
||||
}
|
||||
|
||||
/// Retourne l'URL de souscription aux événements.
|
||||
pub fn event_sub_url(&self) -> String {
|
||||
format!("{}/event", self.base_route())
|
||||
/// Retourne la route de souscription aux événements.
|
||||
pub fn event_route(&self) -> String {
|
||||
format!("{}/event", self.route())
|
||||
}
|
||||
|
||||
/// Retourne l'URL de la description SCPD.
|
||||
pub fn scpd_url(&self) -> String {
|
||||
format!("{}/desc.xml", self.base_route())
|
||||
/// Retourne la route de la description SCPD.
|
||||
pub fn scpd_route(&self) -> String {
|
||||
format!("{}/desc.xml", self.route())
|
||||
}
|
||||
|
||||
/// Retourne l'USN (Unique Service Name).
|
||||
pub fn usn(&self) -> String {
|
||||
match &self.device {
|
||||
let device = self.device.read().unwrap();
|
||||
match device.as_ref() {
|
||||
Some(device) => format!("uuid:{}::urn:{}", device.udn(), self.service_type()),
|
||||
None => format!("uuid::urn:{}", self.service_type()),
|
||||
}
|
||||
@@ -316,17 +303,22 @@ impl ServiceInstance {
|
||||
///
|
||||
/// Retourne une erreur si l'enregistrement des routes échoue.
|
||||
pub async fn register_urls(&self, server: &mut crate::server::Server) -> Result<(), ServiceError> {
|
||||
let device = self.device.read().unwrap();
|
||||
let device_name = device.as_ref().map(|d| d.get_name().clone()).unwrap_or_else(|| "unknown".to_string());
|
||||
let server_url = device.as_ref().map(|d| d.base_url().to_string()).unwrap_or_default();
|
||||
drop(device);
|
||||
|
||||
info!(
|
||||
"✅ Service description for {}:{} available at : {}{}",
|
||||
self.device.as_ref().map(|d| d.name()).unwrap_or("unknown"),
|
||||
device_name,
|
||||
self.get_name(),
|
||||
self.device.as_ref().map(|d| d.server_base_url()).unwrap_or_default(),
|
||||
self.scpd_url(),
|
||||
server_url,
|
||||
self.scpd_route(),
|
||||
);
|
||||
|
||||
// Handler SCPD
|
||||
let instance_scpd = self.clone();
|
||||
server.add_handler(&self.scpd_url(), move || {
|
||||
server.add_handler(&self.scpd_route(), move || {
|
||||
let instance = instance_scpd.clone();
|
||||
async move { instance.scpd_handler().await }
|
||||
}).await;
|
||||
@@ -334,7 +326,7 @@ impl ServiceInstance {
|
||||
// Handler control
|
||||
let instance_control = self.clone();
|
||||
server.add_post_handler_with_state(
|
||||
&self.control_url(),
|
||||
&self.control_route(),
|
||||
control_handler,
|
||||
instance_control,
|
||||
).await;
|
||||
@@ -342,7 +334,7 @@ impl ServiceInstance {
|
||||
// Handler événements
|
||||
let instance_event = self.clone();
|
||||
server.add_handler_with_state(
|
||||
&self.event_sub_url(),
|
||||
&self.event_route(),
|
||||
event_sub_handler,
|
||||
instance_event,
|
||||
).await;
|
||||
@@ -690,10 +682,10 @@ mod tests {
|
||||
let service = Service::new("AVTransport".to_string());
|
||||
let instance = ServiceInstance::new(&service);
|
||||
|
||||
assert_eq!(instance.base_route(), "/service/AVTransport");
|
||||
assert_eq!(instance.control_url(), "/service/AVTransport/control");
|
||||
assert_eq!(instance.event_sub_url(), "/service/AVTransport/event");
|
||||
assert_eq!(instance.scpd_url(), "/service/AVTransport/desc.xml");
|
||||
assert_eq!(instance.route(), "/service/AVTransport");
|
||||
assert_eq!(instance.control_route(), "/service/AVTransport/control");
|
||||
assert_eq!(instance.event_route(), "/service/AVTransport/event");
|
||||
assert_eq!(instance.scpd_route(), "/service/AVTransport/desc.xml");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -35,17 +35,17 @@ impl UpnpObject for Service {
|
||||
|
||||
// SCPDURL
|
||||
let mut SCPDURL = Element::new("SCPDURL");
|
||||
SCPDURL.children.push(XMLNode::Text(self.scpd_url()));
|
||||
SCPDURL.children.push(XMLNode::Text(self.scpd_route()));
|
||||
elem.children.push(XMLNode::Element(SCPDURL));
|
||||
|
||||
// controlURL
|
||||
let mut controlURL = Element::new("controlURL");
|
||||
controlURL.children.push(XMLNode::Text(self.control_url()));
|
||||
controlURL.children.push(XMLNode::Text(self.control_route()));
|
||||
elem.children.push(XMLNode::Element(controlURL));
|
||||
|
||||
// SCPDURL
|
||||
// eventSubURL
|
||||
let mut eventSubURL = Element::new("eventSubURL");
|
||||
eventSubURL.children.push(XMLNode::Text(self.event_url()));
|
||||
eventSubURL.children.push(XMLNode::Text(self.event_route()));
|
||||
elem.children.push(XMLNode::Element(eventSubURL));
|
||||
|
||||
elem
|
||||
|
||||
Reference in New Issue
Block a user