tag2upload_service_manager/
utils.rs
use crate::prelude::*;
use std::time::SystemTime;
define_derive_deftly! {
export DebugTransparent expect items:
impl Debug for $tname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
$(
Debug::fmt(&self.$fname, f)
)
}
}
}
#[macro_export]
macro_rules! with_let {
{
[ ],
{ $($body:tt)* }
} => {
{ $($body)* }
};
{
[ $bind0:ident = $val0:expr; $($bindn:tt)* ],
{ $($body:tt)* }
} => {
match $val0 {
$bind0 => with_let!( [ $($bindn)* ], { $($body)* } ),
}
}
}
#[ext(WatchReceiverExt)]
pub impl<T: Send + Sync> watch::Receiver<T> {
fn wait_for_then<R: Send + Sync>(
&mut self,
mut f: impl FnMut(&T) -> Option<R> + Send + Sync,
) -> impl Future<Output = Result<R, watch::error::RecvError>>
+ Send + Sync
{
async move {
let mut r = None;
self.wait_for(|rx| {
r = f(&rx);
r.is_some()
}).await?;
Ok(r.expect("watch::Receiver misbehaved"))
}
}
}
impl Globals {
pub fn now_systemtime(&self) -> SystemTime {
let now = SystemTime::now();
{
let add: i64 = self.config.testing.time_offset;
#[cfg(test)]
let add = add + *self.test_suppl.simulated_time_advance
.lock().expect("simulated time poisoned");
if add < 0 {
now - Duration::from_secs(-add as _)
} else if add > 0 {
now + Duration::from_secs(add as _)
} else {
now
}
}
}
pub fn now(&self) -> TimeT {
self.now_systemtime().into()
}
pub fn check_tag_recency(
&self,
tag_date: SystemTime,
) -> Result<IsRecentEnough, NFR> {
let now_st = self.now_systemtime();
macro_rules! check_interval_max { {
$var:ident <= $max:ident else $constructor:ident
} => {
let max = self.config.intervals.$max;
if $var > *max {
return Err(NFR::$constructor {
$var: $var.into(),
max: (*max).into(),
})
}
} }
if let Ok(age) = now_st.duration_since(tag_date) {
check_interval_max!(age <= max_tag_age else TagTooOld);
} else if let Ok(skew) = tag_date.duration_since(now_st) {
check_interval_max!(skew <= max_tag_age_skew else TagTooNew);
}
Ok(IsRecentEnough::new_unchecked())
}
}
pub struct IsRecentEnough { _hidden: () }
impl IsRecentEnough {
pub fn new_unchecked() -> Self {
IsRecentEnough { _hidden: () }
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
#[derive(Into, From, Deref)]
pub struct HtDuration(pub Duration);
impl Serialize for HtDuration {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
humantime_serde::Serde::from(self.0).serialize(s)
}
}
impl<'de> Deserialize<'de> for HtDuration {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let h = humantime_serde::Serde::<Duration>::deserialize(d)?;
Ok(HtDuration(*h))
}
}
impl FromStr for HtDuration {
type Err = <humantime::Duration as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let h: humantime::Duration = s.parse()?;
Ok(HtDuration(h.into()))
}
}
impl Display for HtDuration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let h = humantime::Duration::from(self.0);
Display::fmt(&h, f)
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
#[derive(Into, From, Deref)]
pub struct HtTimeT(pub TimeT);
impl Serialize for HtTimeT {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
humantime_serde::Serde::from(SystemTime::from(self.0)).serialize(s)
}
}
impl Display for HtTimeT {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let h = humantime::Timestamp::from(SystemTime::from(self.0));
Display::fmt(&h, f)
}
}
pub fn unix_access(path: &str, mode: c_int) -> io::Result<()> {
let path: Vec<NonZeroU8> = path.as_bytes().iter()
.map(|c| NonZeroU8::try_from(*c))
.collect::<Result<_, _>>().
map_err(|e| io::Error::new(
io::ErrorKind::InvalidInput,
e,
))?;
let path: CString = path.into();
let r = unsafe { libc::access(path.as_ptr(), mode) };
drop::<CString>(path);
if r == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[test]
fn ht_duration() -> test_prelude::TestResult<()> {
#[derive(Serialize, Deserialize, Debug)]
struct O {
d: HtDuration,
}
let s = "27m";
let j = format!(r#"{{"d":{s:?}}}"#);
let o: O = serde_json::from_str(&j)?;
let d = HtDuration::from_str(s)?;
assert_eq!(*d, Duration::from_secs(27 * 60));
assert_eq!(o.d, d);
assert_eq!(d.to_string(), s);
assert_eq!(serde_json::to_string(&o)?, j);
Ok(())
}
#[test]
fn ht_time_t() -> test_prelude::TestResult<()> {
#[derive(Serialize, Debug)]
struct O {
t: HtTimeT,
}
let t = HtTimeT(1727646604.into());
let s = "2024-09-29T21:50:04Z";
let j = format!(r#"{{"t":{s:?}}}"#);
let o = O { t };
assert_eq!(t.to_string(), s);
assert_eq!(serde_json::to_string(&o)?, j);
Ok(())
}