use super::{xml_bool, xml_str, xml_u32};
use crate::error::OnvifError;
use crate::soap::{SoapError, XmlNode};
#[derive(Debug, Clone, Default)]
pub struct NetworkCapabilities {
pub ip_filter: bool,
pub zero_configuration: bool,
pub ip_version6: bool,
pub dyn_dns: bool,
}
#[derive(Debug, Clone, Default)]
pub struct SystemCapabilities {
pub discovery_resolve: bool,
pub discovery_bye: bool,
pub remote_discovery: bool,
pub system_backup: bool,
pub system_logging: bool,
pub firmware_upgrade: bool,
}
#[derive(Debug, Clone, Default)]
pub struct IoCapabilities {
pub input_connectors: Option<u32>,
pub relay_outputs: Option<u32>,
}
#[derive(Debug, Clone, Default)]
pub struct SecurityCapabilities {
pub tls_1_2: bool,
pub onboard_key_generation: bool,
pub access_policy_config: bool,
pub x509_token: bool,
pub username_token: bool,
}
#[derive(Debug, Clone, Default)]
pub struct DeviceCapabilities {
pub url: Option<String>,
pub network: NetworkCapabilities,
pub system: SystemCapabilities,
pub io: IoCapabilities,
pub security: SecurityCapabilities,
}
#[derive(Debug, Clone, Default)]
pub struct StreamingCapabilities {
pub rtp_multicast: bool,
pub rtp_tcp: bool,
pub rtp_rtsp_tcp: bool,
}
#[derive(Debug, Clone, Default)]
pub struct MediaCapabilities {
pub url: Option<String>,
pub streaming: StreamingCapabilities,
pub max_profiles: Option<u32>,
}
#[derive(Debug, Clone, Default)]
pub struct EventsCapabilities {
pub url: Option<String>,
pub ws_subscription_policy: bool,
pub ws_pull_point: bool,
}
#[derive(Debug, Clone, Default)]
pub struct AnalyticsCapabilities {
pub url: Option<String>,
pub rule_support: bool,
pub analytics_module_support: bool,
}
#[derive(Debug, Clone, Default)]
pub struct Capabilities {
pub device: DeviceCapabilities,
pub media: MediaCapabilities,
pub events: EventsCapabilities,
pub analytics: AnalyticsCapabilities,
pub ptz_url: Option<String>,
pub imaging_url: Option<String>,
pub recording_url: Option<String>,
pub search_url: Option<String>,
pub replay_url: Option<String>,
pub device_io_url: Option<String>,
pub media2_url: Option<String>,
}
impl Capabilities {
pub(crate) fn from_xml(resp: &XmlNode) -> Result<Self, OnvifError> {
let caps = resp
.child("Capabilities")
.ok_or_else(|| SoapError::missing("Capabilities"))?;
Ok(Self {
device: caps
.child("Device")
.map(parse_device_caps)
.unwrap_or_default(),
media: caps
.child("Media")
.map(parse_media_caps)
.unwrap_or_default(),
events: caps
.child("Events")
.map(parse_events_caps)
.unwrap_or_default(),
analytics: caps
.child("Analytics")
.map(parse_analytics_caps)
.unwrap_or_default(),
ptz_url: caps.path(&["PTZ", "XAddr"]).map(|n| n.text().to_string()),
imaging_url: caps
.path(&["Imaging", "XAddr"])
.map(|n| n.text().to_string()),
recording_url: caps
.path(&["Extension", "Recording", "XAddr"])
.map(|n| n.text().to_string()),
search_url: caps
.path(&["Extension", "Search", "XAddr"])
.map(|n| n.text().to_string()),
replay_url: caps
.path(&["Extension", "Replay", "XAddr"])
.map(|n| n.text().to_string()),
device_io_url: caps
.path(&["Extension", "DeviceIO", "XAddr"])
.map(|n| n.text().to_string()),
media2_url: caps
.path(&["Extension", "Media2", "XAddr"])
.map(|n| n.text().to_string()),
})
}
}
fn parse_device_caps(d: &XmlNode) -> DeviceCapabilities {
DeviceCapabilities {
url: xml_str(d, "XAddr"),
network: d
.child("Network")
.map(|n| NetworkCapabilities {
ip_filter: xml_bool(n, "IPFilter"),
zero_configuration: xml_bool(n, "ZeroConfiguration"),
ip_version6: xml_bool(n, "IPVersion6"),
dyn_dns: xml_bool(n, "DynDNS"),
})
.unwrap_or_default(),
system: d
.child("System")
.map(|n| SystemCapabilities {
discovery_resolve: xml_bool(n, "DiscoveryResolve"),
discovery_bye: xml_bool(n, "DiscoveryBye"),
remote_discovery: xml_bool(n, "RemoteDiscovery"),
system_backup: xml_bool(n, "SystemBackup"),
system_logging: xml_bool(n, "SystemLogging"),
firmware_upgrade: xml_bool(n, "FirmwareUpgrade"),
})
.unwrap_or_default(),
io: d
.child("IO")
.map(|n| IoCapabilities {
input_connectors: xml_u32(n, "InputConnectors"),
relay_outputs: xml_u32(n, "RelayOutputs"),
})
.unwrap_or_default(),
security: d
.child("Security")
.map(|n| SecurityCapabilities {
tls_1_2: xml_bool(n, "TLS1.2"),
onboard_key_generation: xml_bool(n, "OnboardKeyGeneration"),
access_policy_config: xml_bool(n, "AccessPolicyConfig"),
x509_token: xml_bool(n, "X.509Token"),
username_token: xml_bool(n, "UsernameToken"),
})
.unwrap_or_default(),
}
}
fn parse_media_caps(m: &XmlNode) -> MediaCapabilities {
MediaCapabilities {
url: xml_str(m, "XAddr"),
streaming: m
.child("StreamingCapabilities")
.map(|n| StreamingCapabilities {
rtp_multicast: xml_bool(n, "RTPMulticast"),
rtp_tcp: xml_bool(n, "RTP_TCP"),
rtp_rtsp_tcp: xml_bool(n, "RTP_RTSP_TCP"),
})
.unwrap_or_default(),
max_profiles: xml_u32(m, "MaximumNumberOfProfiles"),
}
}
fn parse_events_caps(e: &XmlNode) -> EventsCapabilities {
EventsCapabilities {
url: xml_str(e, "XAddr"),
ws_subscription_policy: xml_bool(e, "WSSubscriptionPolicySupport"),
ws_pull_point: xml_bool(e, "WSPullPointSupport"),
}
}
fn parse_analytics_caps(a: &XmlNode) -> AnalyticsCapabilities {
AnalyticsCapabilities {
url: xml_str(a, "XAddr"),
rule_support: xml_bool(a, "RuleSupport"),
analytics_module_support: xml_bool(a, "AnalyticsModuleSupport"),
}
}