remove cache feature

This commit is contained in:
yggverse 2026-03-27 11:24:32 +02:00
parent c821fa7492
commit bbf7e73f11
5 changed files with 17 additions and 158 deletions

View file

@ -63,27 +63,13 @@ async fn api_rules(rules: &State<Arc<Rules>>) -> Result<Json<Vec<String>>, Statu
Ok(Json(result))
}
#[rocket::get("/api/cache/clean")]
async fn api_cache_clean(rules: &State<Arc<Rules>>) -> Result<Json<Option<Vec<String>>>, Status> {
let result = rules.cache_clean().await;
info!("Clean cache file: {result:?}");
Ok(Json(result.map_err(|e| {
error!("Could not handle cache clean request: `{e}`");
Status::InternalServerError
})?))
}
#[rocket::launch]
async fn rocket() -> _ {
env_logger::init();
let opt: &'static Opt = Box::leak(Box::new(Opt::from_args()));
let rules = Arc::new(
Rules::from_opt(&opt.allow_list, opt.cache.clone())
.await
.unwrap(),
);
let rules = Arc::new(Rules::from_opt(&opt.allow_list).await.unwrap());
let totals = Arc::new(Total::with_rules(rules.rules().await));
@ -108,14 +94,7 @@ async fn rocket() -> _ {
.manage(Instant::now())
.mount(
"/",
rocket::routes![
index,
api_totals,
api_allow,
api_block,
api_rules,
api_cache_clean
],
rocket::routes![index, api_totals, api_allow, api_block, api_rules],
)
}

View file

@ -1,4 +1,4 @@
use std::{net::SocketAddr, num::ParseFloatError, path::PathBuf, time::Duration};
use std::{net::SocketAddr, num::ParseFloatError, time::Duration};
use structopt::StructOpt;
/// # How to use it:
@ -50,10 +50,6 @@ pub struct Opt {
/// * remote URL
#[structopt(short = "a", long)]
pub allow_list: Vec<String>,
/// FS cache to persist JSON/API changes between server sessions
#[structopt(short = "c", long)]
pub cache: Option<PathBuf>,
}
/// Choose the authentication type

View file

@ -1,23 +1,17 @@
mod cache;
mod item;
use anyhow::Result;
use cache::Cache;
use item::Item;
use log::*;
use std::{collections::HashSet, path::PathBuf};
use std::collections::HashSet;
use tokio::{fs, sync::RwLock};
pub struct Rules {
/// In-memory registry, based on `--allow-list` + `--cache`
index: RwLock<HashSet<Item>>,
/// FS cache for JSON/API changes, based on `--cache` value
cache: Cache,
}
/// In-memory registry, based on `--allow-list`
pub struct Rules(RwLock<HashSet<Item>>);
impl Rules {
/// Build new List object
pub async fn from_opt(list: &Vec<String>, cache: Option<PathBuf>) -> Result<Self> {
pub async fn from_opt(list: &Vec<String>) -> Result<Self> {
fn handle(this: &mut HashSet<Item>, line: &str) -> Option<bool> {
if line.starts_with("/") || line.starts_with("#") || line.is_empty() {
return None;
@ -51,59 +45,36 @@ impl Rules {
}
}
let cache = Cache::from_path(cache).await?;
let cache_rules_total = cache.read().await?.map(|data| {
let mut t = 0;
for line in data.lines() {
if handle(&mut index, line).is_some_and(|status| !status) {
warn!("Cache file contains duplicated entry: `{line}`")
}
t += 1
}
t
});
let len = index.len();
info!("Total rules parsed: {len} (riles: {rules_total} / cache: {cache_rules_total:?})",);
info!("Total rules parsed: {len} (added: {rules_total})",);
Ok(Self {
index: RwLock::new(index),
cache,
})
Ok(Self(RwLock::new(index)))
}
/// Check if rule is exist in the (allow) index
pub async fn any(&self, value: &str) -> bool {
self.index.read().await.iter().any(|item| match item {
self.0.read().await.iter().any(|item| match item {
Item::Exact(v) => v == value,
Item::Ending(v) => value.ends_with(v),
})
}
/// Get total rules from the current session
pub async fn rules(&self) -> u64 {
self.index.read().await.len() as u64
self.0.read().await.len() as u64
}
/// Allow given `rule`
/// * return `false` if the `rule` is exist
pub async fn allow(&self, rule: &str) -> Result<bool> {
self.cache.allow(rule).await?;
Ok(self.index.write().await.insert(Item::from_line(rule)))
Ok(self.0.write().await.insert(Item::from_line(rule)))
}
/// Block given `rule`
/// * return `false` if the `rule` is not exist
pub async fn block(&self, rule: &str) -> Result<bool> {
self.cache.block(rule).await?;
Ok(self.index.write().await.remove(&Item::from_line(rule)))
}
/// Privately clean `--cache` file collected, return deleted rules
/// * we can implement `self.index` update at this step @TODO
pub async fn cache_clean(&self) -> Result<Option<Vec<String>>> {
self.cache.clean().await
Ok(self.0.write().await.remove(&Item::from_line(rule)))
}
/// Return active rules (from server memory)
pub async fn list(&self) -> Vec<String> {
let mut list: Vec<String> = self
.index
.0
.read()
.await
.iter()

View file

@ -1,84 +0,0 @@
use anyhow::{Result, bail};
use std::{collections::HashSet, path::PathBuf};
use tokio::fs;
pub struct Cache(Option<PathBuf>);
impl Cache {
pub async fn from_path(path: Option<PathBuf>) -> Result<Self> {
Ok(Self(match path {
Some(p) => {
init_file(&p).await?;
Some(p)
}
None => None,
}))
}
pub async fn read(&self) -> Result<Option<String>> {
Ok(if let Some(ref p) = self.0 {
init_file(p).await?;
Some(fs::read_to_string(p).await?)
} else {
None
})
}
pub async fn allow(&self, rule: &str) -> Result<()> {
if let Some(ref p) = self.0 {
init_file(p).await?;
let mut rules = HashSet::new();
let lines = fs::read_to_string(p).await?;
for line in lines.lines() {
rules.insert(line);
}
rules.insert(rule);
fs::write(p, rules.into_iter().collect::<Vec<_>>().join("\n")).await?;
}
Ok(())
}
pub async fn block(&self, rule: &str) -> Result<()> {
if let Some(ref p) = self.0 {
init_file(p).await?;
let mut rules = HashSet::new();
let lines = fs::read_to_string(p).await?;
for line in lines.lines() {
if line != rule {
rules.insert(line);
}
}
fs::write(p, rules.into_iter().collect::<Vec<_>>().join("\n")).await?;
}
Ok(())
}
/// Clean `--cache` file collected, return deleted rules
pub async fn clean(&self) -> Result<Option<Vec<String>>> {
match self.0 {
Some(ref p) => {
init_file(p).await?;
let mut rules = Vec::new();
let lines = fs::read_to_string(p).await?;
for line in lines.lines() {
rules.push(line.into());
}
fs::write(p, "").await?;
Ok(Some(rules))
}
None => Ok(None),
}
}
}
/// Make sure that cache file is always exist (e.g. user may remove it when the daemon is running)
async fn init_file(path: &PathBuf) -> Result<()> {
if path.exists() {
if path.is_file() {
return Ok(());
} else {
bail!(
"Cache path `{}` exist but it is not a file!",
path.to_string_lossy()
)
}
}
fs::write(path, "").await?;
Ok(())
}