use rupnp::{Device, DeviceSpec, Service};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct UpnpDevice {
pub name: String,
pub udn: String,
pub volume: Option<String>,
pub services: Vec<UpnpService>,
}
impl From<&DeviceSpec> for UpnpDevice {
fn from(value: &DeviceSpec) -> Self {
Self {
name: value.friendly_name().to_string(),
udn: value.udn().to_string(),
volume: None,
services: vec![],
}
}
}
impl From<&Device> for UpnpDevice {
fn from(value: &Device) -> Self {
let spec: &DeviceSpec = value;
spec.into()
}
}
impl UpnpDevice {
#[must_use]
pub fn with_volume(mut self, volume: Option<String>) -> Self {
self.volume = volume;
self
}
#[must_use]
pub fn with_services(mut self, services: Vec<UpnpService>) -> Self {
self.services = services;
self
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct UpnpService {
pub id: String,
pub r#type: String,
}
impl From<&Service> for UpnpService {
fn from(value: &Service) -> Self {
Self {
id: value.service_id().to_string(),
r#type: value.service_type().to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test_log::test]
fn test_upnp_device_with_volume() {
let device = UpnpDevice {
name: "Test Device".to_string(),
udn: "uuid:test-123".to_string(),
volume: None,
services: vec![],
};
let updated = device.with_volume(Some("50".to_string()));
assert_eq!(updated.volume, Some("50".to_string()));
assert_eq!(updated.name, "Test Device");
assert_eq!(updated.udn, "uuid:test-123");
}
#[test_log::test]
fn test_upnp_device_with_volume_none() {
let device = UpnpDevice {
name: "Test Device".to_string(),
udn: "uuid:test-123".to_string(),
volume: Some("30".to_string()),
services: vec![],
};
let updated = device.with_volume(None);
assert!(updated.volume.is_none());
}
#[test_log::test]
fn test_upnp_device_with_services() {
let device = UpnpDevice {
name: "Test Device".to_string(),
udn: "uuid:test-123".to_string(),
volume: None,
services: vec![],
};
let services = vec![
UpnpService {
id: "urn:upnp-org:serviceId:AVTransport".to_string(),
r#type: "urn:schemas-upnp-org:service:AVTransport:1".to_string(),
},
UpnpService {
id: "urn:upnp-org:serviceId:RenderingControl".to_string(),
r#type: "urn:schemas-upnp-org:service:RenderingControl:1".to_string(),
},
];
let updated = device.with_services(services);
assert_eq!(updated.services.len(), 2);
assert_eq!(updated.services[0].id, "urn:upnp-org:serviceId:AVTransport");
assert_eq!(
updated.services[1].id,
"urn:upnp-org:serviceId:RenderingControl"
);
}
#[test_log::test]
fn test_upnp_device_builder_pattern() {
let device = UpnpDevice {
name: "Test Device".to_string(),
udn: "uuid:test-123".to_string(),
volume: None,
services: vec![],
};
let service = UpnpService {
id: "urn:upnp-org:serviceId:AVTransport".to_string(),
r#type: "urn:schemas-upnp-org:service:AVTransport:1".to_string(),
};
let updated = device
.with_volume(Some("75".to_string()))
.with_services(vec![service]);
assert_eq!(updated.volume, Some("75".to_string()));
assert_eq!(updated.services.len(), 1);
assert_eq!(updated.services[0].id, "urn:upnp-org:serviceId:AVTransport");
}
}