1#![warn(missing_docs)]
2
3use std::sync::Arc;
6use std::sync::Mutex;
7
8use async_trait::async_trait;
9use chrono::DateTime;
10use chrono::Duration;
11use chrono::Utc;
12use dashmap::mapref::one::RefMut;
13use dashmap::DashMap;
14use rings_core::dht::Did;
15use rings_core::measure;
16use rings_core::measure::Measure;
17use rings_core::measure::MeasureCounter;
18use rings_core::storage::KvStorageInterface;
19use rings_derive::MeasureBehaviour;
20
21#[cfg(test)]
22const DURATION: u64 = 1;
23#[cfg(not(test))]
24const DURATION: u64 = 60 * 60;
25
26#[cfg(feature = "browser")]
29pub type MeasureStorage = Box<dyn KvStorageInterface<u64>>;
30
31#[cfg(not(feature = "browser"))]
34pub type MeasureStorage = Box<dyn KvStorageInterface<u64> + Sync + Send>;
35
36#[derive(MeasureBehaviour)]
40pub struct PeriodicMeasure {
41 storage: MeasureStorage,
42 counters: DashMap<(Did, MeasureCounter), Mutex<PeriodicCounter>>,
43 clock: Arc<dyn MeasureClock>,
44}
45
46trait MeasureClock: Send + Sync {
50 fn now(&self) -> DateTime<Utc>;
51}
52
53struct SystemMeasureClock;
54
55impl MeasureClock for SystemMeasureClock {
56 fn now(&self) -> DateTime<Utc> {
57 Utc::now()
58 }
59}
60
61#[derive(Debug)]
62struct PeriodicCounter {
63 period: Duration,
67 count: u64,
68 previous: DateTime<Utc>,
69 previous_count: u64,
70}
71
72impl PeriodicCounter {
73 fn new(period: u64, previous_count: u64, now: DateTime<Utc>) -> Self {
74 Self {
75 period: Duration::seconds(period as i64),
76 count: 0,
77 previous: now,
78 previous_count,
79 }
80 }
81
82 fn refresh_at(&mut self, now: DateTime<Utc>) -> bool {
84 if now - self.previous < self.period {
85 return false;
86 }
87
88 self.previous_count = self.count;
89 self.count = 0;
90 self.previous = now;
91 true
92 }
93
94 fn barely_get(&self) -> u64 {
96 if self.previous_count == 0 {
97 self.count
98 } else {
99 self.previous_count
100 }
101 }
102
103 fn incr_at(&mut self, now: DateTime<Utc>) -> (u64, bool) {
105 let is_refreshed = self.refresh_at(now);
106 self.count += 1;
107 (self.barely_get(), is_refreshed)
108 }
109
110 fn get_at(&mut self, now: DateTime<Utc>) -> (u64, bool) {
112 let is_refreshed = self.refresh_at(now);
113 (self.barely_get(), is_refreshed)
114 }
115}
116
117impl PeriodicMeasure {
118 pub fn new(storage: MeasureStorage) -> Self {
120 Self {
121 storage,
122 counters: DashMap::new(),
123 clock: Arc::new(SystemMeasureClock),
124 }
125 }
126
127 #[cfg(all(test, feature = "node"))]
128 fn new_with_clock(storage: MeasureStorage, clock: Arc<dyn MeasureClock>) -> Self {
129 Self {
130 storage,
131 counters: DashMap::new(),
132 clock,
133 }
134 }
135
136 fn gen_storage_key(did: Did, counter: MeasureCounter) -> String {
137 format!("PeriodicMeasure/counters/{did}/{counter:?}")
138 }
139
140 async fn ensure_counter(
142 &self,
143 did: Did,
144 counter: MeasureCounter,
145 now: DateTime<Utc>,
146 ) -> RefMut<'_, (Did, MeasureCounter), Mutex<PeriodicCounter>> {
147 let k = Self::gen_storage_key(did, counter);
148 let count = self
149 .storage
150 .get(&k)
151 .await
152 .unwrap_or_else(|e| {
153 log::error!("Failed to get counter: {e:?}");
154 Some(0)
155 })
156 .unwrap_or(0);
157 self.counters
158 .entry((did, counter))
159 .or_insert_with(|| Mutex::new(PeriodicCounter::new(DURATION, count, now)))
160 }
161
162 async fn save_counter(&self, did: Did, counter: MeasureCounter, count: u64) {
163 let k = Self::gen_storage_key(did, counter);
164 self.storage.put(&k, &count).await.unwrap_or_else(|e| {
165 log::error!("Failed to save counter: {e:?}");
166 })
167 }
168}
169
170#[cfg_attr(feature = "node", async_trait)]
171#[cfg_attr(feature = "browser", async_trait(?Send))]
172impl Measure for PeriodicMeasure {
173 async fn incr(&self, did: Did, counter: MeasureCounter) {
175 let now = self.clock.now();
176 let (count, is_refreshed) = {
177 let c = self.ensure_counter(did, counter, now).await;
178 let result = if let Ok(mut c) = c.lock() {
179 c.incr_at(now)
180 } else {
181 return;
182 };
183 result
184 };
185 if is_refreshed {
186 self.save_counter(did, counter, count).await;
187 }
188 }
189
190 async fn get_count(&self, did: Did, counter: MeasureCounter) -> u64 {
192 let now = self.clock.now();
193 let (count, is_refreshed) = {
194 let c = self.ensure_counter(did, counter, now).await;
195 let result = if let Ok(mut c) = c.lock() {
196 c.get_at(now)
197 } else {
198 return 0;
199 };
200 result
201 };
202 if is_refreshed {
203 self.save_counter(did, counter, count).await;
204 }
205 count
206 }
207}
208
209#[cfg_attr(feature = "node", async_trait)]
210#[cfg_attr(feature = "browser", async_trait(?Send))]
211impl measure::BehaviourJudgement for PeriodicMeasure {
212 async fn good(&self, did: Did) -> bool {
213 <Self as measure::ConnectBehaviour<{crate::consts::CONNECT_FAILED_LIMIT}>>::good(self, did).await &&
214 <Self as measure::MessageSendBehaviour<{crate::consts::MSG_SEND_FAILED_LIMIT}>>::good(self, did).await &&
215 <Self as measure::MessageRecvBehaviour<{crate::consts::MSG_RECV_FAILED_LIMIT}>>::good(self, did).await
216 }
217}
218
219#[cfg(test)]
220#[cfg(feature = "node")]
221mod tests {
222 use std::str::FromStr;
223 use std::sync::Arc;
224 use std::sync::Mutex;
225
226 use rings_core::storage::sled::SledStorage;
227 use rings_core::storage::MemStorage;
228
229 use super::*;
230
231 #[derive(Clone)]
232 struct ManualMeasureClock {
233 now: Arc<Mutex<DateTime<Utc>>>,
234 }
235
236 impl ManualMeasureClock {
237 fn new(now: DateTime<Utc>) -> Self {
238 Self {
239 now: Arc::new(Mutex::new(now)),
240 }
241 }
242
243 fn advance(&self, duration: Duration) {
244 let Ok(mut now) = self.now.lock() else {
245 panic!("manual measure clock lock poisoned");
246 };
247 let Some(advanced) = now.checked_add_signed(duration) else {
248 panic!("manual measure clock overflow");
249 };
250 *now = advanced;
251 }
252 }
253
254 impl MeasureClock for ManualMeasureClock {
255 fn now(&self) -> DateTime<Utc> {
256 let Ok(now) = self.now.lock() else {
257 panic!("manual measure clock lock poisoned");
258 };
259 now.to_owned()
260 }
261 }
262
263 fn advance_period(clock: &ManualMeasureClock) {
264 clock.advance(Duration::seconds(DURATION as i64));
265 }
266
267 #[tokio::test]
268 async fn test_measure_counter() {
269 let ms = Box::new(MemStorage::new());
270
271 let did1 = Did::from_str("0x11E807fcc88dD319270493fB2e822e388Fe36ab0").unwrap();
272 let did2 = Did::from_str("0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E").unwrap();
273
274 let clock = ManualMeasureClock::new(Utc::now());
275 let measure = PeriodicMeasure::new_with_clock(ms, Arc::new(clock.clone()));
276 assert_eq!(measure.get_count(did1, MeasureCounter::Sent).await, 0);
277 assert_eq!(measure.get_count(did2, MeasureCounter::Sent).await, 0);
278 assert_eq!(measure.get_count(did1, MeasureCounter::Received).await, 0);
279 assert_eq!(measure.get_count(did2, MeasureCounter::Received).await, 0);
280
281 measure.incr(did1, MeasureCounter::Sent).await;
282 measure.incr(did1, MeasureCounter::Received).await;
283
284 measure.incr(did2, MeasureCounter::Sent).await;
285 measure.incr(did2, MeasureCounter::Sent).await;
286 measure.incr(did2, MeasureCounter::Received).await;
287 measure.incr(did2, MeasureCounter::Received).await;
288 measure.incr(did2, MeasureCounter::Received).await;
289
290 assert_eq!(measure.get_count(did1, MeasureCounter::Sent).await, 1);
291 assert_eq!(measure.get_count(did2, MeasureCounter::Sent).await, 2);
292 assert_eq!(measure.get_count(did1, MeasureCounter::Received).await, 1);
293 assert_eq!(measure.get_count(did2, MeasureCounter::Received).await, 3);
294 }
295
296 #[tokio::test]
297 async fn test_measure_period() {
298 let ms = Box::new(MemStorage::new());
299
300 let did = Did::from_str("0x11E807fcc88dD319270493fB2e822e388Fe36ab0").unwrap();
301
302 let clock = ManualMeasureClock::new(Utc::now());
303 let measure = PeriodicMeasure::new_with_clock(ms, Arc::new(clock.clone()));
304 assert_eq!(measure.get_count(did, MeasureCounter::Sent).await, 0);
305 assert_eq!(measure.get_count(did, MeasureCounter::Received).await, 0);
306
307 measure.incr(did, MeasureCounter::Sent).await;
308 measure.incr(did, MeasureCounter::Sent).await;
309 measure.incr(did, MeasureCounter::Received).await;
310
311 assert_eq!(measure.get_count(did, MeasureCounter::Sent).await, 2);
313 assert_eq!(measure.get_count(did, MeasureCounter::Received).await, 1);
314
315 advance_period(&clock);
316
317 measure.incr(did, MeasureCounter::Sent).await;
318 measure.incr(did, MeasureCounter::Received).await;
319 measure.incr(did, MeasureCounter::Received).await;
320 measure.incr(did, MeasureCounter::Received).await;
321
322 assert_eq!(measure.get_count(did, MeasureCounter::Sent).await, 2);
324 assert_eq!(measure.get_count(did, MeasureCounter::Received).await, 1);
325
326 advance_period(&clock);
327
328 assert_eq!(measure.get_count(did, MeasureCounter::Sent).await, 1);
330 assert_eq!(measure.get_count(did, MeasureCounter::Received).await, 3);
331
332 advance_period(&clock);
333
334 assert_eq!(measure.get_count(did, MeasureCounter::Sent).await, 0);
336 assert_eq!(measure.get_count(did, MeasureCounter::Received).await, 0);
337 }
338
339 #[tokio::test]
340 async fn test_persistent_measure_storage() {
341 let ms: MeasureStorage = Box::new(
342 SledStorage::new_with_cap_and_path(4096, "tmp/measure_test_db")
343 .await
344 .unwrap(),
345 );
346 ms.clear().await.unwrap();
347
348 let did = Did::from_str("0x11E807fcc88dD319270493fB2e822e388Fe36ab0").unwrap();
349 let clock = ManualMeasureClock::new(Utc::now());
350 let measure = PeriodicMeasure::new_with_clock(ms, Arc::new(clock.clone()));
351 assert_eq!(measure.get_count(did, MeasureCounter::Sent).await, 0);
352 assert_eq!(measure.get_count(did, MeasureCounter::Received).await, 0);
353
354 measure.incr(did, MeasureCounter::Sent).await;
355 measure.incr(did, MeasureCounter::Sent).await;
356 measure.incr(did, MeasureCounter::Received).await;
357
358 advance_period(&clock);
359
360 let c1 = measure.get_count(did, MeasureCounter::Sent).await;
362 assert_eq!(c1, 2);
363 let c2 = measure.get_count(did, MeasureCounter::Received).await;
364 assert_eq!(c2, 1);
365
366 drop(measure);
368
369 let ms2 = Box::new(
371 SledStorage::new_with_cap_and_path(4096, "tmp/measure_test_db")
372 .await
373 .unwrap(),
374 );
375 let measure2 = PeriodicMeasure::new_with_clock(ms2, Arc::new(clock));
376
377 assert_eq!(measure2.get_count(did, MeasureCounter::Sent).await, 2);
379 assert_eq!(measure2.get_count(did, MeasureCounter::Received).await, 1);
380 }
381}