1use async_trait::async_trait;
7use db_core::errors::DBResult;
8use serde::{Deserialize, Serialize};
9
10use crate::data::Data;
11
12#[async_trait]
13pub trait Stats: std::marker::Send + std::marker::Sync + CloneStats {
14 async fn record_fetch(&self, d: &Data, key: &str) -> DBResult<()>;
16
17 async fn record_solve(&self, d: &Data, key: &str) -> DBResult<()>;
19
20 async fn record_confirm(&self, d: &Data, key: &str) -> DBResult<()>;
22
23 async fn fetch(&self, d: &Data, user: &str, key: &str) -> DBResult<CaptchaStats>;
25}
26
27pub trait CloneStats {
29 fn clone_stats(&self) -> Box<dyn Stats>;
31}
32
33impl<T> CloneStats for T
34where
35 T: Stats + Clone + 'static,
36{
37 fn clone_stats(&self) -> Box<dyn Stats> {
38 Box::new(self.clone())
39 }
40}
41
42#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
50pub struct CaptchaStats {
51 pub config_fetches: Vec<i64>,
52 pub solves: Vec<i64>,
53 pub confirms: Vec<i64>,
54}
55
56#[derive(Clone, Default, PartialEq, Debug)]
57pub struct Real;
58
59#[async_trait]
60impl Stats for Real {
61 async fn record_fetch(&self, d: &Data, key: &str) -> DBResult<()> {
63 d.db.record_fetch(key).await
64 }
65
66 async fn record_solve(&self, d: &Data, key: &str) -> DBResult<()> {
68 d.db.record_solve(key).await
69 }
70
71 async fn record_confirm(&self, d: &Data, key: &str) -> DBResult<()> {
73 d.db.record_confirm(key).await
74 }
75
76 async fn fetch(&self, d: &Data, user: &str, key: &str) -> DBResult<CaptchaStats> {
78 let config_fetches_fut = d.db.fetch_config_fetched(user, key);
79 let solves_fut = d.db.fetch_solve(user, key);
80 let confirms_fut = d.db.fetch_confirm(user, key);
81
82 let (config_fetches, solves, confirms) =
83 futures::try_join!(config_fetches_fut, solves_fut, confirms_fut)?;
84
85 let res = CaptchaStats {
86 config_fetches,
87 solves,
88 confirms,
89 };
90
91 Ok(res)
92 }
93}
94
95#[derive(Clone, Default, PartialEq, Debug)]
96pub struct Dummy;
97
98#[async_trait]
99impl Stats for Dummy {
100 async fn record_fetch(&self, _: &Data, _: &str) -> DBResult<()> {
102 Ok(())
103 }
104
105 async fn record_solve(&self, _: &Data, _: &str) -> DBResult<()> {
107 Ok(())
108 }
109
110 async fn record_confirm(&self, _: &Data, _: &str) -> DBResult<()> {
112 Ok(())
113 }
114
115 async fn fetch(&self, _: &Data, _: &str, _: &str) -> DBResult<CaptchaStats> {
117 Ok(CaptchaStats::default())
118 }
119}