#
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}