tag2upload_service_manager/
utils.rs1
2use crate::prelude::*;
3
4use std::time::SystemTime;
5
6define_derive_deftly! {
7 export DebugTransparent expect items:
8
9 impl Debug for $tname {
10 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
11 $(
12 Debug::fmt(&self.$fname, f)
13 )
14 }
15 }
16}
17
18pub fn handle_string_fmt_error(_: fmt::Error) -> ! {
19 panic!("failed to format onto String")
20}
21
22#[macro_export]
23macro_rules! write_string { { $($a:tt)* }=> {
24 write!($($a)*)
25 .unwrap_or_else(|e| $crate::utils::handle_string_fmt_error(e))
26} }
27
28#[macro_export]
45macro_rules! with_let {
46 {
47 [ ],
48 { $($body:tt)* }
49 } => {
50 { $($body)* }
51 };
52 {
53 [ $bind0:ident = $val0:expr; $($bindn:tt)* ],
54 { $($body:tt)* }
55 } => {
56 match $val0 {
57 $bind0 => with_let!( [ $($bindn)* ], { $($body)* } ),
58 }
59 }
60}
61
62#[ext(WatchReceiverExt)]
63pub impl<T: Send + Sync> watch::Receiver<T> {
64 fn wait_for_then<R: Send + Sync>(
65 &mut self,
66 mut f: impl FnMut(&T) -> Option<R> + Send + Sync,
67 ) -> impl Future<Output = Result<R, watch::error::RecvError>>
68 + Send + Sync
69 {
70 async move {
71 let mut r = None;
72 self.wait_for(|rx| {
73 r = f(&rx);
74 r.is_some()
75 }).await?;
76 Ok(r.expect("watch::Receiver misbehaved"))
77 }
78 }
79}
80
81impl Globals {
82 pub fn now_systemtime(&self) -> SystemTime {
83 let now = SystemTime::now();
84
85 {
88 let add: i64 = self.config.testing.time_offset;
89
90 #[cfg(test)]
91 let add = add + *self.test_suppl.simulated_time_advance
92 .lock().expect("simulated time poisoned");
93
94 if add < 0 {
95 now - Duration::from_secs(-add as _)
96 } else if add > 0 {
97 now + Duration::from_secs(add as _)
98 } else {
99 now
100 }
101 }
102 }
103
104 pub fn now(&self) -> TimeT {
105 self.now_systemtime().into()
106 }
107
108 pub fn check_tag_recency(
109 &self,
110 tag_date: SystemTime,
111 ) -> Result<IsRecentEnough, NFR> {
112 let now_st = self.now_systemtime();
113
114 macro_rules! check_interval_max { {
115 $var:ident <= $max:ident else $constructor:ident
116 } => {
117 let max = self.config.intervals.$max;
118 if $var > *max {
119 return Err(NFR::$constructor {
120 $var: $var.into(),
121 max: (*max).into(),
122 })
123 }
124 } }
125
126 if let Ok(age) = now_st.duration_since(tag_date) {
127 check_interval_max!(age <= max_tag_age else TagTooOld);
128 } else if let Ok(skew) = tag_date.duration_since(now_st) {
129 check_interval_max!(skew <= max_tag_age_skew else TagTooNew);
130 }
131
132 Ok(IsRecentEnough::new_unchecked())
133 }
134}
135
136pub struct IsRecentEnough { _hidden: () }
138
139impl IsRecentEnough {
140 pub fn new_unchecked() -> Self {
141 IsRecentEnough { _hidden: () }
142 }
143}
144
145#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
149#[derive(Into, From, Deref)]
150pub struct HtDuration(pub Duration);
151
152impl Serialize for HtDuration {
153 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
154 humantime_serde::Serde::from(self.0).serialize(s)
155 }
156}
157impl<'de> Deserialize<'de> for HtDuration {
158 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
159 let h = humantime_serde::Serde::<Duration>::deserialize(d)?;
160 Ok(HtDuration(*h))
161 }
162}
163impl FromStr for HtDuration {
164 type Err = <humantime::Duration as FromStr>::Err;
165 fn from_str(s: &str) -> Result<Self, Self::Err> {
166 let h: humantime::Duration = s.parse()?;
167 Ok(HtDuration(h.into()))
168 }
169}
170impl Display for HtDuration {
171 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172 let h = humantime::Duration::from(self.0);
173 Display::fmt(&h, f)
174 }
175}
176
177#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
179#[derive(Into, From, Deref)]
180pub struct HtTimeT(pub TimeT);
181
182impl Serialize for HtTimeT {
183 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
184 humantime_serde::Serde::from(SystemTime::from(self.0)).serialize(s)
185 }
186}
187impl Display for HtTimeT {
188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 let h = humantime::Timestamp::from(SystemTime::from(self.0));
190 Display::fmt(&h, f)
191 }
192}
193
194pub fn unix_access(path: &str, mode: c_int) -> io::Result<()> {
195 let path: Vec<NonZeroU8> = path.as_bytes().iter()
196 .map(|c| NonZeroU8::try_from(*c))
197 .collect::<Result<_, _>>().
198 map_err(|e| io::Error::new(
199 io::ErrorKind::InvalidInput,
200 e,
201 ))?;
202
203 let path: CString = path.into();
204
205 let r = unsafe { libc::access(path.as_ptr(), mode) };
208 drop::<CString>(path);
209
210 if r == 0 {
211 Ok(())
212 } else {
213 Err(io::Error::last_os_error())
214 }
215}
216
217#[test]
218fn ht_duration() -> test_prelude::TestResult<()> {
219 #[derive(Serialize, Deserialize, Debug)]
220 struct O {
221 d: HtDuration,
222 }
223
224 let s = "27m";
225 let j = format!(r#"{{"d":{s:?}}}"#);
226
227 let o: O = serde_json::from_str(&j)?;
228 let d = HtDuration::from_str(s)?;
229
230 assert_eq!(*d, Duration::from_secs(27 * 60));
231 assert_eq!(o.d, d);
232 assert_eq!(d.to_string(), s);
233 assert_eq!(serde_json::to_string(&o)?, j);
234
235 Ok(())
236}
237
238#[test]
239fn ht_time_t() -> test_prelude::TestResult<()> {
240 #[derive(Serialize, Debug)]
241 struct O {
242 t: HtTimeT,
243 }
244
245 let t = HtTimeT(1727646604.into());
246 let s = "2024-09-29T21:50:04Z";
247 let j = format!(r#"{{"t":{s:?}}}"#);
248 let o = O { t };
249
250 assert_eq!(t.to_string(), s);
251 assert_eq!(serde_json::to_string(&o)?, j);
252
253 Ok(())
254}