use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
#[derive(Clone, Debug, Default)]
pub struct PhaseTiming {
pub dns_duration: Option<Duration>,
pub tcp_duration: Option<Duration>,
pub tls_duration: Option<Duration>,
pub remote_ip: Option<SocketAddr>,
pub local_ip: Option<SocketAddr>,
}
#[derive(Clone, Debug, Default)]
pub struct RequestMetrics {
pub request_start: Option<Instant>,
pub first_response_byte: Option<Instant>,
pub response_end: Option<Instant>,
pub redirect_duration: Duration,
pub num_redirects: u32,
pub size_upload: u64,
pub size_download: u64,
pub size_header: u64,
pub num_headers: u32,
pub url_effective: Option<String>,
pub redirect_url: Option<String>,
pub status: Option<u16>,
pub http_version: Option<String>,
pub headers: Option<reqwest::header::HeaderMap>,
pub phase: Arc<Mutex<PhaseTiming>>,
}
impl RequestMetrics {
pub fn time_total(&self) -> Duration {
match (self.request_start, self.response_end) {
(Some(s), Some(e)) => e.saturating_duration_since(s),
_ => Duration::ZERO,
}
}
pub fn time_starttransfer(&self) -> Duration {
match (self.request_start, self.first_response_byte) {
(Some(s), Some(fb)) => fb.saturating_duration_since(s),
_ => Duration::ZERO,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_are_zero() {
let m = RequestMetrics::default();
assert_eq!(m.time_total(), Duration::ZERO);
assert_eq!(m.time_starttransfer(), Duration::ZERO);
assert_eq!(m.num_redirects, 0);
assert_eq!(m.size_download, 0);
assert!(m.url_effective.is_none());
}
#[test]
fn time_total_computes_from_start_and_end() {
let mut m = RequestMetrics::default();
let t0 = Instant::now();
m.request_start = Some(t0);
m.response_end = Some(t0 + Duration::from_millis(250));
assert_eq!(m.time_total(), Duration::from_millis(250));
}
#[test]
fn time_total_zero_without_end() {
let mut m = RequestMetrics::default();
m.request_start = Some(Instant::now());
assert_eq!(m.time_total(), Duration::ZERO);
}
#[test]
fn time_starttransfer_computes_from_start_and_first_byte() {
let mut m = RequestMetrics::default();
let t0 = Instant::now();
m.request_start = Some(t0);
m.first_response_byte = Some(t0 + Duration::from_millis(100));
assert_eq!(m.time_starttransfer(), Duration::from_millis(100));
}
}