1use crossbeam_utils::atomic::AtomicCell;
4use std::{fmt, sync::Arc, time::Duration};
5
6#[derive(Clone)]
13pub struct Metrics {
14 pub(crate) inner: Arc<Inner>,
15}
16
17#[derive(Default)]
18pub(crate) struct Inner {
19 pub(crate) upload_progress: AtomicCell<f64>,
20 pub(crate) upload_total: AtomicCell<f64>,
21 pub(crate) download_progress: AtomicCell<f64>,
22 pub(crate) download_total: AtomicCell<f64>,
23
24 pub(crate) upload_speed: AtomicCell<f64>,
25 pub(crate) download_speed: AtomicCell<f64>,
26
27 pub(crate) namelookup_time: AtomicCell<f64>,
42 pub(crate) connect_time: AtomicCell<f64>,
43 pub(crate) appconnect_time: AtomicCell<f64>,
44 pub(crate) pretransfer_time: AtomicCell<f64>,
45 pub(crate) starttransfer_time: AtomicCell<f64>,
46 pub(crate) total_time: AtomicCell<f64>,
47 pub(crate) redirect_time: AtomicCell<f64>,
48}
49
50impl Metrics {
51 pub(crate) fn new() -> Self {
52 Self {
53 inner: Arc::default(),
54 }
55 }
56
57 pub fn upload_progress(&self) -> (u64, u64) {
59 (
60 self.inner.upload_progress.load() as u64,
61 self.inner.upload_total.load() as u64,
62 )
63 }
64
65 pub fn upload_speed(&self) -> f64 {
67 self.inner.upload_speed.load()
68 }
69
70 pub fn download_progress(&self) -> (u64, u64) {
72 (
73 self.inner.download_progress.load() as u64,
74 self.inner.download_total.load() as u64,
75 )
76 }
77
78 pub fn download_speed(&self) -> f64 {
80 self.inner.download_speed.load()
81 }
82
83 pub fn name_lookup_time(&self) -> Duration {
89 Duration::from_secs_f64(self.inner.namelookup_time.load())
90 }
91
92 pub fn connect_time(&self) -> Duration {
98 Duration::from_secs_f64(
99 (self.inner.connect_time.load() - self.inner.namelookup_time.load()).max(0f64),
100 )
101 }
102
103 pub fn secure_connect_time(&self) -> Duration {
108 let app_connect_time = self.inner.appconnect_time.load();
109
110 if app_connect_time > 0f64 {
111 Duration::from_secs_f64(app_connect_time - self.inner.connect_time.load())
112 } else {
113 Duration::new(0, 0)
114 }
115 }
116
117 pub fn transfer_start_time(&self) -> Duration {
123 Duration::from_secs_f64(self.inner.starttransfer_time.load())
124 }
125
126 pub fn transfer_time(&self) -> Duration {
132 Duration::from_secs_f64(
133 (self.inner.total_time.load() - self.inner.starttransfer_time.load()).max(0f64),
134 )
135 }
136
137 pub fn total_time(&self) -> Duration {
143 Duration::from_secs_f64(self.inner.total_time.load())
144 }
145
146 pub fn redirect_time(&self) -> Duration {
150 Duration::from_secs_f64(self.inner.redirect_time.load())
151 }
152}
153
154impl fmt::Debug for Metrics {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 f.debug_struct("Metrics")
157 .field("upload_progress", &self.upload_progress())
158 .field("upload_speed", &self.upload_speed())
159 .field("download_progress", &self.download_progress())
160 .field("download_speed", &self.download_speed())
161 .field("name_lookup_time", &self.name_lookup_time())
162 .field("connect_time", &self.connect_time())
163 .field("secure_connect_time", &self.secure_connect_time())
164 .field("transfer_start_time", &self.transfer_start_time())
165 .field("transfer_time", &self.transfer_time())
166 .field("total_time", &self.total_time())
167 .field("redirect_time", &self.redirect_time())
168 .finish()
169 }
170}