feat: r96util
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
kieran 2025-02-10 20:48:40 +00:00
parent 3b4bb866ab
commit b6bd190252
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
3 changed files with 89 additions and 1 deletions

View File

@ -15,6 +15,10 @@ required-features = ["bin-void-cat-force-migrate"]
name = "route96"
path = "src/bin/main.rs"
[[bin]]
name = "r96util"
path = "src/bin/r96util.rs"
[lib]
name = "route96"

84
src/bin/r96util.rs Normal file
View File

@ -0,0 +1,84 @@
use anyhow::Error;
use clap::{Parser, Subcommand};
use config::Config;
use log::{info, warn};
use route96::db::Database;
use route96::filesystem::FileStore;
use route96::settings::Settings;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
#[arg(long)]
pub config: Option<String>,
#[clap(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
enum Commands {
/// Check file hash matches filename / path
Check { delete: Option<bool> },
/// Import a directory into the filesystem
/// (does NOT import files into the database)
Import { from: PathBuf },
}
#[tokio::main]
async fn main() -> Result<(), Error> {
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "info");
}
pretty_env_logger::init();
let args: Args = Args::parse();
let builder = Config::builder()
.add_source(config::File::with_name(if let Some(ref c) = args.config {
c.as_str()
} else {
"config.yaml"
}))
.add_source(config::Environment::with_prefix("APP"))
.build()?;
let settings: Settings = builder.try_deserialize()?;
match args.command {
Commands::Check { delete } => {
info!("Checking files in: {}", settings.storage_dir);
let fs = FileStore::new(settings.clone());
let mut dir = tokio::fs::read_dir(fs.storage_dir()).await?;
while let Some(entry) = dir.next_entry().await? {
if entry.file_type().await?.is_dir() {
continue;
}
let id = if let Ok(f) = hex::decode(entry.file_name().to_str().unwrap()) {
f
} else {
warn!("Skipping invalid filename: {}", entry.path().display());
continue;
};
let hash = FileStore::hash_file(&entry.path()).await?;
if hash != id {
if delete.unwrap_or(false) {
warn!("Deleting corrupt file: {}", entry.path().display());
tokio::fs::remove_file(entry.path()).await?;
} else {
warn!("File is corrupted: {}", entry.path().display());
}
}
}
}
Commands::Import { from } => {
info!("Importing from: {}", from.display());
let db = Database::new(&settings.database).await?;
}
}
Ok(())
}

View File

@ -232,7 +232,7 @@ impl FileStore {
Ok((out_path, n, hash))
}
async fn hash_file(p: &PathBuf) -> Result<Vec<u8>, Error> {
pub async fn hash_file(p: &PathBuf) -> Result<Vec<u8>, Error> {
let mut file = File::open(p).await?;
let mut hasher = Sha256::new();
let mut buf = [0; 4096];