Skip to content

Commit 5c4e706

Browse files
Fix formatting issues in PR #1592
Co-Authored-By: Ian Clarke <[email protected]>
1 parent ffa0623 commit 5c4e706

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use std::{collections::HashMap, fmt::Display, time::Duration};
2+
3+
use chrono::{DateTime, Utc};
4+
5+
pub use chrono;
6+
7+
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
8+
#[cfg_attr(feature = "clap", derive(clap::Parser))]
9+
pub struct PingContractOptions {
10+
/// Time to live for the ping record.
11+
#[serde(with = "humantime_serde")]
12+
#[cfg_attr(feature = "clap", clap(long, value_parser = duration_parser, default_value = "5s"))]
13+
pub ttl: Duration,
14+
15+
/// The frequency to send ping record.
16+
#[serde(with = "humantime_serde")]
17+
#[cfg_attr(feature = "clap", clap(long, value_parser = duration_parser, default_value = "1s"))]
18+
pub frequency: Duration,
19+
20+
/// The tag of the ping contract subscriber.
21+
#[cfg_attr(feature = "clap", clap(long))]
22+
pub tag: String,
23+
24+
/// Code hash of the ping contract.
25+
#[cfg_attr(feature = "clap", clap(long))]
26+
pub code_key: String,
27+
}
28+
29+
#[cfg(feature = "clap")]
30+
#[inline]
31+
fn duration_parser(s: &str) -> Result<Duration, humantime::DurationError> {
32+
humantime::parse_duration(s)
33+
}
34+
35+
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
36+
pub struct Ping {
37+
from: HashMap<String, DateTime<Utc>>,
38+
}
39+
40+
impl core::ops::Deref for Ping {
41+
type Target = HashMap<String, DateTime<Utc>>;
42+
43+
fn deref(&self) -> &Self::Target {
44+
&self.from
45+
}
46+
}
47+
48+
impl core::ops::DerefMut for Ping {
49+
fn deref_mut(&mut self) -> &mut Self::Target {
50+
&mut self.from
51+
}
52+
}
53+
54+
impl Ping {
55+
pub fn new() -> Self {
56+
Self::default()
57+
}
58+
59+
#[cfg(feature = "std")]
60+
pub fn insert(&mut self, name: String) {
61+
self.from.insert(name, Utc::now());
62+
}
63+
64+
pub fn merge(&mut self, other: Self, ttl: Duration) -> HashMap<String, DateTime<Utc>> {
65+
#[cfg(feature = "std")]
66+
let now = Utc::now();
67+
#[cfg(not(feature = "std"))]
68+
let now = freenet_stdlib::time::now();
69+
70+
let mut updates = HashMap::new();
71+
for (name, created_time) in other.from.into_iter() {
72+
if now <= created_time + ttl {
73+
match self.from.entry(name.clone()) {
74+
std::collections::hash_map::Entry::Occupied(mut occupied_entry) => {
75+
if occupied_entry.get() < &created_time {
76+
occupied_entry.insert(created_time);
77+
updates.insert(name, created_time);
78+
}
79+
}
80+
std::collections::hash_map::Entry::Vacant(vacant_entry) => {
81+
vacant_entry.insert(created_time);
82+
updates.insert(name, created_time);
83+
}
84+
}
85+
}
86+
}
87+
88+
self.from.retain(|_, v| now <= *v + ttl);
89+
updates
90+
}
91+
}
92+
93+
impl Display for Ping {
94+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95+
let mut entries: Vec<_> = self.from.iter().collect();
96+
entries.sort_by(|a, b| a.0.cmp(b.0));
97+
write!(
98+
f,
99+
"Ping {{ {} }}",
100+
entries
101+
.iter()
102+
.map(|(k, v)| format!("{}: {}", k, v))
103+
.collect::<Vec<_>>()
104+
.join(", ")
105+
)
106+
}
107+
}
108+
#[cfg(test)]
109+
mod tests {
110+
use super::*;
111+
112+
#[test]
113+
fn test_merge_expired() {
114+
let mut ping = Ping::new();
115+
ping.insert("Alice".to_string());
116+
ping.insert("Bob".to_string());
117+
118+
let mut other = Ping::new();
119+
other
120+
.from
121+
.insert("Alice".to_string(), Utc::now() - Duration::from_secs(6));
122+
other
123+
.from
124+
.insert("Charlie".to_string(), Utc::now() - Duration::from_secs(6));
125+
126+
ping.merge(other, Duration::from_secs(5));
127+
128+
assert_eq!(ping.len(), 2);
129+
assert!(ping.contains_key("Alice"));
130+
assert!(ping.contains_key("Bob"));
131+
assert!(!ping.contains_key("Charlie"));
132+
}
133+
134+
#[test]
135+
fn test_merge_ok() {
136+
let mut ping = Ping::new();
137+
ping.insert("Alice".to_string());
138+
ping.insert("Bob".to_string());
139+
140+
let mut other = Ping::new();
141+
other
142+
.from
143+
.insert("Alice".to_string(), Utc::now() - Duration::from_secs(4));
144+
other
145+
.from
146+
.insert("Charlie".to_string(), Utc::now() - Duration::from_secs(4));
147+
148+
ping.merge(other, Duration::from_secs(5));
149+
150+
assert_eq!(ping.len(), 3);
151+
assert!(ping.contains_key("Alice"));
152+
assert!(ping.contains_key("Bob"));
153+
assert!(ping.contains_key("Charlie"));
154+
}
155+
}

0 commit comments

Comments
 (0)