feat: file deletion implementation

This commit is contained in:
Paul Makles
2024-11-27 21:54:39 +00:00
parent acc4317246
commit 249749e14d
15 changed files with 267 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
[package]
name = "crond"
name = "revolt-crond"
version = "0.7.19"
license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"]
@@ -9,6 +9,14 @@ description = "Revolt Daemon Service: Timed data clean up tasks"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# Utility
log = "0.4"
# Async
tokio = { version = "1" }
# Core
revolt-database = { version = "0.7.19", path = "../../core/database" }
revolt-result = { version = "0.7.19", path = "../../core/result" }
revolt-config = { version = "0.7.19", path = "../../core/config" }
revolt-files = { version = "0.7.19", path = "../../core/files" }

View File

@@ -1,3 +1,19 @@
fn main() {
println!("Hello, world!");
use revolt_config::configure;
use revolt_database::DatabaseInfo;
use revolt_result::Result;
use tasks::{file_deletion, prune_dangling_files};
use tokio::try_join;
pub mod tasks;
#[tokio::main]
async fn main() -> Result<()> {
configure!(crond);
let db = DatabaseInfo::Auto.connect().await.expect("database");
try_join!(
file_deletion::task(db.clone()),
prune_dangling_files::task(db)
)
.map(|_| ())
}

View File

@@ -0,0 +1,39 @@
use std::time::Duration;
use log::info;
use revolt_database::Database;
use revolt_files::delete_from_s3;
use revolt_result::Result;
use tokio::time::sleep;
pub async fn task(db: Database) -> Result<()> {
loop {
let files = db.fetch_deleted_attachments().await?;
for file in files {
let count = db
.count_file_hash_references(file.hash.as_ref().expect("no `hash` present"))
.await?;
// No other files reference this file on disk anymore
if count <= 1 {
let file_hash = db
.fetch_attachment_hash(file.hash.as_ref().expect("no `hash` present"))
.await?;
// Delete from S3
delete_from_s3(&file_hash.bucket_id, &file_hash.path).await?;
// Delete the hash
db.delete_attachment_hash(&file_hash.id).await?;
info!("Deleted file hash {}", file_hash.id);
}
// Delete the file
db.delete_attachment(&file.id).await?;
info!("Deleted file {}", file.id);
}
sleep(Duration::from_secs(60)).await;
}
}

View File

@@ -0,0 +1,2 @@
pub mod file_deletion;
pub mod prune_dangling_files;

View File

@@ -0,0 +1,36 @@
use std::time::Duration;
use revolt_database::{iso8601_timestamp::Timestamp, Database};
use revolt_result::Result;
use tokio::time::sleep;
use log::info;
pub async fn task(db: Database) -> Result<()> {
loop {
// This could just be a single database query
// ... but timestamps are inconsistently serialised
// ... sometimes they are dates/numbers, hard to query
// ... in the future, we could use Postgres instead! :D
// ...
// ... on the plus side, it's still only 2 queries
let files = db.fetch_dangling_files().await?;
let file_ids: Vec<String> = files
.into_iter()
.filter(|file| {
file.uploaded_at.is_some_and(|uploaded_at| {
Timestamp::now_utc().duration_since(uploaded_at) > Duration::from_secs(60 * 60)
})
})
.map(|file| file.id)
.collect();
if !file_ids.is_empty() {
db.mark_attachments_as_deleted(&file_ids).await?;
info!("Marked {} dangling files for deletion", file_ids.len());
}
sleep(Duration::from_secs(60)).await;
}
}