Skip to content

Commit

Permalink
Merge pull request #124 from asuper0/optional_fix_time
Browse files Browse the repository at this point in the history
add option fix_time_gap to Client and the builder.
  • Loading branch information
DmitrySamoylov authored Apr 9, 2024
2 parents aeedff9 + a95a3c6 commit e9b5258
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 6 deletions.
51 changes: 49 additions & 2 deletions onvif/examples/camera.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use onvif::soap;
use chrono::{NaiveDate, Utc};
use onvif::soap::{self, client::AuthType};
use schema::{self, transport};
use structopt::StructOpt;
use tracing::debug;
use tracing::{debug, warn};
use url::Url;

#[derive(StructOpt)]
Expand All @@ -24,6 +25,14 @@ struct Args {
#[structopt(global = true, long, default_value = "onvif/device_service")]
service_path: String,

/// Auto fix time gap between PC and the camera
#[structopt(short = "t", long)]
fix_time: bool,

/// Authorization type [Any(Default), Digest, UsernameToken]
#[structopt(short = "a", long, default_value = "Any")]
auth_type: String,

#[structopt(subcommand)]
cmd: Cmd,
}
Expand Down Expand Up @@ -92,9 +101,15 @@ impl Clients {
.as_ref()
.ok_or_else(|| "--uri must be specified.".to_string())?;
let devicemgmt_uri = base_uri.join(&args.service_path).unwrap();
let auth_type = match args.auth_type.to_ascii_lowercase().as_str() {
"digest" => AuthType::Digest,
"usernametoken" => AuthType::UsernameToken,
_ => AuthType::Any,
};
let mut out = Self {
devicemgmt: soap::client::ClientBuilder::new(&devicemgmt_uri)
.credentials(creds.clone())
.auth_type(auth_type.clone())
.build(),
imaging: None,
ptz: None,
Expand All @@ -104,6 +119,36 @@ impl Clients {
media2: None,
analytics: None,
};

let time_gap = if args.fix_time {
let device_time =
schema::devicemgmt::get_system_date_and_time(&out.devicemgmt, &Default::default())
.await?
.system_date_and_time;

if let Some(utc_time) = &device_time.utc_date_time {
let pc_time = Utc::now();
let date = &utc_time.date;
let t = &utc_time.time;
let device_time =
NaiveDate::from_ymd_opt(date.year, date.month as _, date.day as _)
.unwrap()
.and_hms_opt(t.hour as _, t.minute as _, t.second as _)
.unwrap()
.and_utc();

let diff = device_time - pc_time;
if diff.num_seconds().abs() > 60 {
out.devicemgmt.set_fix_time_gap(Some(diff));
}
Some(diff)
} else {
warn!("GetSystemDateAndTimeResponse doesn't have utc_data_time value!");
None
}
} else {
None
};
let services =
schema::devicemgmt::get_services(&out.devicemgmt, &Default::default()).await?;
for service in &services.service {
Expand All @@ -117,6 +162,8 @@ impl Clients {
let svc = Some(
soap::client::ClientBuilder::new(&service_url)
.credentials(creds.clone())
.auth_type(auth_type.clone())
.fix_time_gap(time_gap)
.build(),
);
match service.namespace.as_str() {
Expand Down
2 changes: 1 addition & 1 deletion onvif/src/discovery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ mod tests {
let our_uuid = "uuid:84ede3de-7dec-11d0-c360-F01234567890";
let bad_uuid = "uuid:84ede3de-7dec-11d0-c360-F00000000000";

let input = vec![
let input = [
make_xml(our_uuid, "http://addr_20 http://addr_21 http://addr_22"),
make_xml(bad_uuid, "http://addr_30 http://addr_31"),
];
Expand Down
16 changes: 14 additions & 2 deletions onvif/src/soap/auth/username_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,22 @@ pub struct UsernameToken {
}

impl UsernameToken {
pub fn new(username: &str, password: &str) -> UsernameToken {
pub fn new(
username: &str,
password: &str,
fix_time_gap: Option<chrono::Duration>,
) -> UsernameToken {
let uuid = uuid::Uuid::new_v4();
let nonce = uuid.as_bytes();
let created = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true);

let mut created = chrono::Utc::now();
if let Some(time_gap) = fix_time_gap {
created = match created.checked_add_signed(time_gap) {
Some(t) => t,
None => chrono::Utc::now(),
};
}
let created = created.to_rfc3339_opts(chrono::SecondsFormat::Millis, true);

let mut concat = Vec::with_capacity(nonce.len() + created.len() + password.len());

Expand Down
13 changes: 12 additions & 1 deletion onvif/src/soap/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl ClientBuilder {
response_patcher: None,
auth_type: AuthType::Any,
timeout: ClientBuilder::DEFAULT_TIMEOUT,
fix_time_gap: None,
},
}
}
Expand Down Expand Up @@ -79,6 +80,11 @@ impl ClientBuilder {
self
}

pub fn fix_time_gap(mut self, time_gap: Option<chrono::Duration>) -> Self {
self.config.fix_time_gap = time_gap;
self
}

pub fn build(self) -> Client {
let client = if let Some(client) = self.client {
client
Expand Down Expand Up @@ -121,6 +127,7 @@ struct Config {
response_patcher: Option<ResponsePatcher>,
auth_type: AuthType,
timeout: Duration,
fix_time_gap: Option<chrono::Duration>,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -314,6 +321,10 @@ impl Client {
self.config
.credentials
.as_ref()
.map(|c| UsernameToken::new(&c.username, &c.password))
.map(|c| UsernameToken::new(&c.username, &c.password, self.config.fix_time_gap))
}

pub fn set_fix_time_gap(&mut self, time_gap: Option<chrono::Duration>) {
self.config.fix_time_gap = time_gap;
}
}

0 comments on commit e9b5258

Please sign in to comment.