1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (C) 2022  Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

use async_trait::async_trait;
use db_core::errors::DBResult;
use serde::{Deserialize, Serialize};

use crate::data::Data;

#[async_trait]
pub trait Stats: std::marker::Send + std::marker::Sync + CloneStats {
    /// record PoWConfig fetches
    async fn record_fetch(&self, d: &Data, key: &str) -> DBResult<()>;

    /// record PoWConfig solves
    async fn record_solve(&self, d: &Data, key: &str) -> DBResult<()>;

    /// record PoWConfig confirms
    async fn record_confirm(&self, d: &Data, key: &str) -> DBResult<()>;

    /// fetch stats
    async fn fetch(&self, d: &Data, user: &str, key: &str) -> DBResult<CaptchaStats>;
}

/// Trait to clone MCDatabase
pub trait CloneStats {
    /// clone DB
    fn clone_stats(&self) -> Box<dyn Stats>;
}

impl<T> CloneStats for T
where
    T: Stats + Clone + 'static,
{
    fn clone_stats(&self) -> Box<dyn Stats> {
        Box::new(self.clone())
    }
}

//impl Clone for Box<dyn CloneStats> {
//    fn clone(&self) -> Self {
//        Box::clone(self)
//        //(*self).clone_stats()
//    }
//}

#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
pub struct CaptchaStats {
    pub config_fetches: Vec<i64>,
    pub solves: Vec<i64>,
    pub confirms: Vec<i64>,
}

#[derive(Clone, Default, PartialEq, Debug)]
pub struct Real;

#[async_trait]
impl Stats for Real {
    /// record PoWConfig fetches
    async fn record_fetch(&self, d: &Data, key: &str) -> DBResult<()> {
        d.db.record_fetch(key).await
    }

    /// record PoWConfig solves
    async fn record_solve(&self, d: &Data, key: &str) -> DBResult<()> {
        d.db.record_solve(key).await
    }

    /// record PoWConfig confirms
    async fn record_confirm(&self, d: &Data, key: &str) -> DBResult<()> {
        d.db.record_confirm(key).await
    }

    /// fetch stats
    async fn fetch(&self, d: &Data, user: &str, key: &str) -> DBResult<CaptchaStats> {
        let config_fetches_fut = d.db.fetch_config_fetched(user, key);
        let solves_fut = d.db.fetch_solve(user, key);
        let confirms_fut = d.db.fetch_confirm(user, key);

        let (config_fetches, solves, confirms) =
            futures::try_join!(config_fetches_fut, solves_fut, confirms_fut)?;

        let res = CaptchaStats {
            config_fetches,
            solves,
            confirms,
        };

        Ok(res)
    }
}

#[derive(Clone, Default, PartialEq, Debug)]
pub struct Dummy;

#[async_trait]
impl Stats for Dummy {
    /// record PoWConfig fetches
    async fn record_fetch(&self, _: &Data, _: &str) -> DBResult<()> {
        Ok(())
    }

    /// record PoWConfig solves
    async fn record_solve(&self, _: &Data, _: &str) -> DBResult<()> {
        Ok(())
    }

    /// record PoWConfig confirms
    async fn record_confirm(&self, _: &Data, _: &str) -> DBResult<()> {
        Ok(())
    }

    /// fetch stats
    async fn fetch(&self, _: &Data, _: &str, _: &str) -> DBResult<CaptchaStats> {
        Ok(CaptchaStats::default())
    }
}