Compare commits

...

2 commits

Author SHA1 Message Date
36b80bbbd9 feat: purge file storage daily
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-04-02 17:36:01 +02:00
4cb4a34f39 chore: update cargo dependencies 2023-04-02 17:04:37 +02:00
7 changed files with 361 additions and 271 deletions

582
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@ time = { version = "0.3.15", features = [
httpdate = "1.0.2" httpdate = "1.0.2"
sha2 = "0.10.6" sha2 = "0.10.6"
path_macro = "1.0.0" path_macro = "1.0.0"
hex-literal = "0.3.4" hex-literal = "0.4.0"
hex = { version = "0.4.3", features = ["serde"] } hex = { version = "0.4.3", features = ["serde"] }
temp-dir = "0.1.11" temp-dir = "0.1.11"
zip = { version = "0.6.4", default-features = false, features = [ zip = { version = "0.6.4", default-features = false, features = [
@ -54,6 +54,7 @@ shadow-rs = "0.21.0"
walkdir = "2.3.2" walkdir = "2.3.2"
rust-embed = { version = "6.6.1", features = ["poem-ex"] } rust-embed = { version = "6.6.1", features = ["poem-ex"] }
image = "0.24.6" image = "0.24.6"
clokwerk = { version = "0.4.0", default-features = false }
[dev-dependencies] [dev-dependencies]
rstest = "0.17.0" rstest = "0.17.0"

View file

@ -80,10 +80,26 @@ impl Config {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct ServerCfg { pub struct ServerCfg {
/// Address to bind the server to
///
/// Default: `0.0.0.0:3000`
pub address: String, pub address: String,
/// Root domain (and port if non-standard) under which Talon is available
///
/// Default: `localhost:3000`
pub root_domain: String, pub root_domain: String,
/// Subdomain used for Talon internals (API, assets)
///
/// Default: `talon`
pub internal_subdomain: String, pub internal_subdomain: String,
/// URL under which the internals are available
///
/// Default: `http://talon.localhost:3000`
pub internal_url: String, pub internal_url: String,
/// Interval in minutes between file storage purges
///
/// Default: 1440 (24h)
pub purge_interval: u32,
} }
impl Default for ServerCfg { impl Default for ServerCfg {
@ -93,6 +109,7 @@ impl Default for ServerCfg {
root_domain: "localhost:3000".to_owned(), root_domain: "localhost:3000".to_owned(),
internal_subdomain: "talon".to_owned(), internal_subdomain: "talon".to_owned(),
internal_url: "http://talon.localhost:3000".to_owned(), internal_url: "http://talon.localhost:3000".to_owned(),
purge_interval: 1440,
} }
} }
} }

View file

@ -1,4 +1,4 @@
use std::{ops::Deref, path::Path, sync::Arc}; use std::{ops::Deref, path::Path, sync::Arc, time::Duration};
use crate::{ use crate::{
assets, assets,
@ -10,6 +10,7 @@ use crate::{
storage::Storage, storage::Storage,
util, util,
}; };
use clokwerk::{Interval, Scheduler};
use path_macro::path; use path_macro::path;
use poem::{ use poem::{
http::header, listener::TcpListener, middleware, Endpoint, EndpointExt, Route, RouteDomain, http::header, listener::TcpListener, middleware, Endpoint, EndpointExt, Route, RouteDomain,
@ -68,7 +69,7 @@ impl Talon {
let storage = Storage::new(storage_dir, db.clone(), cfg.clone()); let storage = Storage::new(storage_dir, db.clone(), cfg.clone());
let icons = Icons::new(icons_dir); let icons = Icons::new(icons_dir);
Ok(Self { let talon = Self {
i: TalonInner { i: TalonInner {
cfg, cfg,
db, db,
@ -77,7 +78,24 @@ impl Talon {
start_time: OffsetDateTime::now_utc(), start_time: OffsetDateTime::now_utc(),
} }
.into(), .into(),
}) };
Ok(talon)
}
fn scheduler(&self) -> Scheduler {
let mut scheduler = Scheduler::new();
let talon = self.clone();
scheduler
.every(Interval::Minutes(self.cfg.server.purge_interval))
.run(move || {
log::info!("Starting purge");
match talon.storage.purge() {
Ok((files, freed)) => log::info!("{files} files purged, {freed} bytes freed"),
Err(e) => log::error!("purge error: {e}"),
}
});
scheduler
} }
pub fn endpoint(&self) -> impl Endpoint { pub fn endpoint(&self) -> impl Endpoint {
@ -129,6 +147,9 @@ impl Talon {
} }
pub async fn launch(&self) -> Result<()> { pub async fn launch(&self) -> Result<()> {
let scheduler = self.scheduler();
let _scheduler_handle = scheduler.watch_thread(Duration::from_secs(1));
Server::new(TcpListener::bind(&self.i.cfg.server.address)) Server::new(TcpListener::bind(&self.i.cfg.server.address))
.run_with_graceful_shutdown(self.endpoint(), Self::shutdown_signal(), None) .run_with_graceful_shutdown(self.endpoint(), Self::shutdown_signal(), None)
.await?; .await?;

View file

@ -8,6 +8,7 @@ ConfigInner(
root_domain: "example.com", root_domain: "example.com",
internal_subdomain: "talon-i", internal_subdomain: "talon-i",
internal_url: "http://talon-i.example.com", internal_url: "http://talon-i.example.com",
purge_interval: 60,
), ),
compression: CompressionCfg( compression: CompressionCfg(
gzip_en: true, gzip_en: true,

View file

@ -8,6 +8,7 @@ ConfigInner(
root_domain: "localhost:3000", root_domain: "localhost:3000",
internal_subdomain: "talon", internal_subdomain: "talon",
internal_url: "http://talon.localhost:3000", internal_url: "http://talon.localhost:3000",
purge_interval: 1440,
), ),
compression: CompressionCfg( compression: CompressionCfg(
gzip_en: true, gzip_en: true,

View file

@ -3,6 +3,7 @@ address = "127.0.0.1:3000"
root_domain = "example.com" root_domain = "example.com"
internal_subdomain = "talon-i" internal_subdomain = "talon-i"
internal_url = "http://talon-i.example.com" internal_url = "http://talon-i.example.com"
purge_interval = 60
# Talon compresses files when they are uploaded # Talon compresses files when they are uploaded
# Here you can configure compression algorithms and levels # Here you can configure compression algorithms and levels