bayard 0.9.0

A distributed search server.
use std::path::Path;

use tokio::{
    fs::{self, File},
    io::{AsyncReadExt, AsyncWriteExt},
};

const TMP_FILE_EXT: &str = "tmp";
const OLD_FILE_EXT: &str = "old";

pub async fn write_file(path: &Path, content: &[u8]) -> anyhow::Result<()> {
    let tmp_file_path = path.with_extension(TMP_FILE_EXT);
    let mut tmp_file = File::create(&tmp_file_path)
        .await
        .map_err(|error| anyhow::anyhow!(error))?;
    tmp_file
        .write_all(content)
        .await
        .map_err(|error| anyhow::anyhow!(error))?;

    if path.exists() {
        let old_file_path = path.with_extension(OLD_FILE_EXT);
        fs::rename(path, &old_file_path)
            .await
            .map_err(|error| anyhow::anyhow!(error))?;
    }

    fs::rename(&tmp_file_path, path)
        .await
        .map_err(|error| anyhow::anyhow!(error))?;

    Ok(())
}

pub async fn read_file(path: &Path) -> anyhow::Result<Vec<u8>> {
    let mut file = File::open(path)
        .await
        .map_err(|error| anyhow::anyhow!(error))?;
    let mut content = Vec::new();
    file.read_to_end(&mut content)
        .await
        .map_err(|error| anyhow::anyhow!(error))?;
    Ok(content)
}

pub async fn remove_file(path: &Path) -> anyhow::Result<()> {
    let tmp_file_path = path.with_extension(TMP_FILE_EXT);
    if tmp_file_path.exists() {
        fs::remove_file(&tmp_file_path)
            .await
            .map_err(|error| anyhow::anyhow!(error))?;
    }

    let old_file_path = path.with_extension(OLD_FILE_EXT);
    if old_file_path.exists() {
        fs::remove_file(&old_file_path)
            .await
            .map_err(|error| anyhow::anyhow!(error))?;
    }

    if path.exists() {
        fs::remove_file(path)
            .await
            .map_err(|error| anyhow::anyhow!(error))?;
    }
    Ok(())
}