use std::sync::Arc;
use crate::error::OnvifError;
use crate::soap::{SoapEnvelope, WsSecurityToken};
use crate::transport::{HttpTransport, Transport};
mod device;
mod events;
mod imaging;
mod media;
mod media2;
mod ptz;
mod recording;
#[derive(Clone)]
pub struct OnvifClient {
device_url: String,
credentials: Option<(String, String)>,
utc_offset: i64,
transport: Arc<dyn Transport>,
}
impl OnvifClient {
pub fn new(device_url: impl Into<String>) -> Self {
Self {
device_url: device_url.into(),
credentials: None,
utc_offset: 0,
transport: Arc::new(HttpTransport::new()),
}
}
pub fn with_credentials(
mut self,
username: impl Into<String>,
password: impl Into<String>,
) -> Self {
self.credentials = Some((username.into(), password.into()));
self
}
pub fn with_utc_offset(mut self, offset_secs: i64) -> Self {
self.utc_offset = offset_secs;
self
}
pub fn with_transport(mut self, transport: Arc<dyn Transport>) -> Self {
self.transport = transport;
self
}
pub fn device_url(&self) -> &str {
&self.device_url
}
fn security_token(&self) -> Option<WsSecurityToken> {
self.credentials
.as_ref()
.map(|(user, pass)| WsSecurityToken::generate(user, pass, self.utc_offset))
}
async fn call(&self, url: &str, action: &str, body: &str) -> Result<String, OnvifError> {
let mut envelope = SoapEnvelope::new(body.to_string()).with_wsa_to(url);
if let Some(token) = self.security_token() {
envelope = envelope.with_security(token);
}
Ok(self
.transport
.soap_post(url, action, envelope.build())
.await?)
}
}
#[cfg(test)]
#[path = "../tests/client_tests.rs"]
mod tests;