mcaptcha/
stats.rs

1// Copyright (C) 2022  Aravinth Manivannan <realaravinth@batsense.net>
2// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6use 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    /// record PoWConfig fetches
15    async fn record_fetch(&self, d: &Data, key: &str) -> DBResult<()>;
16
17    /// record PoWConfig solves
18    async fn record_solve(&self, d: &Data, key: &str) -> DBResult<()>;
19
20    /// record PoWConfig confirms
21    async fn record_confirm(&self, d: &Data, key: &str) -> DBResult<()>;
22
23    /// fetch stats
24    async fn fetch(&self, d: &Data, user: &str, key: &str) -> DBResult<CaptchaStats>;
25}
26
27/// Trait to clone MCDatabase
28pub trait CloneStats {
29    /// clone DB
30    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//impl Clone for Box<dyn CloneStats> {
43//    fn clone(&self) -> Self {
44//        Box::clone(self)
45//        //(*self).clone_stats()
46//    }
47//}
48
49#[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    /// record PoWConfig fetches
62    async fn record_fetch(&self, d: &Data, key: &str) -> DBResult<()> {
63        d.db.record_fetch(key).await
64    }
65
66    /// record PoWConfig solves
67    async fn record_solve(&self, d: &Data, key: &str) -> DBResult<()> {
68        d.db.record_solve(key).await
69    }
70
71    /// record PoWConfig confirms
72    async fn record_confirm(&self, d: &Data, key: &str) -> DBResult<()> {
73        d.db.record_confirm(key).await
74    }
75
76    /// fetch stats
77    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    /// record PoWConfig fetches
101    async fn record_fetch(&self, _: &Data, _: &str) -> DBResult<()> {
102        Ok(())
103    }
104
105    /// record PoWConfig solves
106    async fn record_solve(&self, _: &Data, _: &str) -> DBResult<()> {
107        Ok(())
108    }
109
110    /// record PoWConfig confirms
111    async fn record_confirm(&self, _: &Data, _: &str) -> DBResult<()> {
112        Ok(())
113    }
114
115    /// fetch stats
116    async fn fetch(&self, _: &Data, _: &str, _: &str) -> DBResult<CaptchaStats> {
117        Ok(CaptchaStats::default())
118    }
119}