feat: update dependencies, enhance upload rate limiting, and improve UI elements
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use anyhow::Result;
|
||||
use chrono::{Duration, Utc};
|
||||
@@ -7,7 +7,11 @@ use futures::lock::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::logs::{LogEventType, log_event};
|
||||
use crate::MAX_ASSETS;
|
||||
use crate::{
|
||||
MAX_UPLOADS_PER_HOUR_PER_USER,
|
||||
logs::{LogEventType, log_event},
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Asset {
|
||||
@@ -85,31 +89,30 @@ impl Asset {
|
||||
pub fn to_value(&self) -> Value {
|
||||
serde_json::to_value(self).unwrap_or(Value::Null)
|
||||
}
|
||||
|
||||
// pub fn save(&self) -> Result<String> {
|
||||
// let id = self.id.clone();
|
||||
// let path = format!("{}{}", DATA_STORAGE, self.id);
|
||||
// std::fs::create_dir_all(DATA_STORAGE)?;
|
||||
// std::fs::write(&path, self.to_bytes()?)?;
|
||||
// Ok(id)
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AssetTracker {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct AppState {
|
||||
pub assets: AssetStorage,
|
||||
pub connection_tracker: RateLimiter,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct AssetStorage {
|
||||
assets: Arc<Mutex<Vec<Asset>>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl AssetTracker {
|
||||
impl AssetStorage {
|
||||
pub fn new() -> Self {
|
||||
AssetTracker {
|
||||
assets: Arc::new(Mutex::new(Vec::new())),
|
||||
Self {
|
||||
assets: Arc::new(Mutex::new(Vec::with_capacity(MAX_ASSETS))),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_asset(&self, asset: Asset) {
|
||||
print!("[{}] Adding asset: {}", chrono::Local::now().to_rfc3339(), asset.id());
|
||||
|
||||
self.assets.lock().await.push(asset);
|
||||
self.show_assets().await;
|
||||
}
|
||||
@@ -173,7 +176,43 @@ impl AssetTracker {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_assets(assets: AssetTracker) -> Result<()> {
|
||||
assets.remove_expired().await;
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct RateLimiter {
|
||||
pub clients: Arc<Mutex<HashMap<String, Vec<i64>>>>,
|
||||
}
|
||||
|
||||
impl RateLimiter {
|
||||
pub async fn is_allowed(&self, client_ip: &str) -> bool {
|
||||
let mut clients = self.clients.lock().await;
|
||||
let now = Utc::now().timestamp_millis();
|
||||
let one_hour_ago = now - Duration::hours(1).num_milliseconds();
|
||||
|
||||
let entry = clients.entry(client_ip.to_string()).or_insert_with(Vec::new);
|
||||
entry.retain(|×tamp| timestamp > one_hour_ago);
|
||||
|
||||
let ret_val = if entry.len() < MAX_UPLOADS_PER_HOUR_PER_USER {
|
||||
entry.push(now);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
println!("{:?}", clients);
|
||||
ret_val
|
||||
}
|
||||
|
||||
pub async fn clear_expired(&self) {
|
||||
let mut clients = self.clients.lock().await;
|
||||
let now = Utc::now().timestamp_millis();
|
||||
let one_hour_ago = now - Duration::hours(1).num_milliseconds();
|
||||
|
||||
for timestamps in clients.values_mut() {
|
||||
timestamps.retain(|×tamp| timestamp > one_hour_ago);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_app_data(app_state: &AppState) -> Result<()> {
|
||||
app_state.assets.remove_expired().await;
|
||||
app_state.connection_tracker.clear_expired().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user