mcaptcha/
easy.rs

1// Copyright (C) 2024// Copyright (C) 2024  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 std::time::Duration;
7//use std::sync::atomicBool
8
9use actix::clock::sleep;
10use actix::spawn;
11use tokio::sync::oneshot::{channel, error::TryRecvError, Receiver, Sender};
12use tokio::task::JoinHandle;
13
14use crate::api::v1::mcaptcha::easy::{
15    update_runner, TrafficPatternRequest, UpdateTrafficPattern,
16};
17use crate::*;
18
19use errors::*;
20
21pub struct UpdateEasyCaptcha {
22    tx: Sender<()>,
23}
24
25impl UpdateEasyCaptcha {
26    pub async fn spawn(
27        data: AppData,
28        duration: u32,
29    ) -> ServiceResult<(Self, JoinHandle<()>)> {
30        let (tx, rx) = channel();
31        let handle = Self::run(data, duration, rx).await?;
32        let d = Self { tx };
33
34        Ok((d, handle))
35    }
36
37    #[allow(dead_code)]
38    pub fn abort(mut self) {
39        self.tx.send(());
40    }
41
42    /// update configurations
43    async fn update_captcha_configurations(
44        data: &AppData,
45        rx: &mut Receiver<()>,
46    ) -> ServiceResult<()> {
47        let limit = 10;
48        let mut offset = 0;
49        let mut page = 0;
50        loop {
51            offset = page * limit;
52
53            if !Self::can_run(rx) {
54                return Ok(());
55            }
56
57            let mut patterns = data.db.get_all_easy_captchas(limit, offset).await?;
58            if patterns.is_empty() {
59                break;
60            }
61            for pattern in patterns.drain(0..) {
62                if !Self::can_run(rx) {
63                    return Ok(());
64                }
65
66                let publish_benchmarks =
67                    data.db.analytics_captcha_is_published(&pattern.key).await?;
68
69                let req = UpdateTrafficPattern {
70                    pattern: TrafficPatternRequest {
71                        avg_traffic: pattern.traffic_pattern.avg_traffic,
72                        peak_sustainable_traffic: pattern
73                            .traffic_pattern
74                            .peak_sustainable_traffic,
75                        broke_my_site_traffic: pattern
76                            .traffic_pattern
77                            .broke_my_site_traffic,
78                        description: pattern.description,
79                        publish_benchmarks,
80                    },
81                    key: pattern.key,
82                };
83                if !Self::can_run(rx) {
84                    return Ok(());
85                }
86
87                update_runner(&data, req, pattern.username).await?;
88            }
89            page += 1;
90        }
91        Ok(())
92    }
93
94    fn can_run(rx: &mut Receiver<()>) -> bool {
95        match rx.try_recv() {
96            Err(TryRecvError::Empty) => true,
97            _ => false,
98        }
99    }
100
101    pub async fn run(
102        data: AppData,
103        duration: u32,
104        mut rx: Receiver<()>,
105    ) -> ServiceResult<JoinHandle<()>> {
106        let mut exit = false;
107        let fut = async move {
108            loop {
109                if exit {
110                    break;
111                }
112                for _ in 0..duration {
113                    if Self::can_run(&mut rx) {
114                        sleep(Duration::new(1, 0)).await;
115                        continue;
116                    } else {
117                        exit = true;
118                        break;
119                    }
120                }
121
122                if let Some(err) = Self::update_captcha_configurations(&data, &mut rx)
123                    .await
124                    .err()
125                {
126                    log::error!(
127                        "Tried to update easy captcha configurations in background {:?}",
128                        err
129                    );
130                }
131            }
132        };
133        let handle = spawn(fut);
134        Ok(handle)
135    }
136}