ncbi_dl 0.1.8

download ncbi genome file
Documentation
use anyhow::Result;
use lazy_static::lazy_static;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::sync::Mutex;

const META_FILE_NAME: &'static str = ".metadata";

async fn parse_metadata(filename: &PathBuf) -> Result<HashMap<String, String>> {
    let mut meta: HashMap<String, String> = HashMap::new();
    if !filename.exists() {
        File::create(filename).await?;
    }

    let file = File::open(filename).await?;
    let reader = BufReader::new(file);
    let mut lines = reader.lines();

    while let Some(line) = lines.next_line().await? {
        if line.starts_with('#') || line.trim().is_empty() {
            continue;
        }

        let parts: Vec<&str> = line.split(',').collect();
        if parts.len() < 2 {
            continue;
        }
        let url = parts[0].to_string();
        let etag = parts[1].to_string();
        meta.insert(url, etag);
    }

    Ok(meta)
}

pub struct Meta {
    inner: HashMap<String, String>,
}

impl Meta {
    pub fn new() -> Self {
        Self {
            inner: HashMap::new(),
        }
    }

    pub async fn init(&mut self, db_path: &PathBuf) {
        let meta_file: PathBuf = db_path.clone().join(META_FILE_NAME);
        if let Ok(meta) = parse_metadata(&meta_file).await {
            self.inner = meta;
        }
    }

    pub fn get_etag(&self, key: &str) -> Option<String> {
        self.inner.get(key).map(|s| s.to_string())
    }

    pub fn insert_or_update(&mut self, key: String, new_etag: String) {
        self.inner.insert(key, new_etag);
    }
}

pub async fn init_meta(db_path: &PathBuf) {
    let mut meta = META.lock().await;
    meta.init(db_path).await;
}

pub async fn get_local_etag(key: &str) -> Option<String> {
    let meta = META.lock().await;
    meta.get_etag(key)
}

pub async fn insert_local_etag(key: String, new_etag: String) {
    let mut meta = META.lock().await;
    meta.insert_or_update(key, new_etag);
}

pub async fn save_meta(db_path: &PathBuf) -> Result<()> {
    let meta = META.lock().await;
    let meta_file: PathBuf = db_path.join(META_FILE_NAME);
    let mut file = File::create(meta_file).await?;

    for (url, etag) in meta.inner.iter() {
        file.write_all(format!("{},{}\n", url, etag).as_bytes())
            .await?;
    }

    Ok(())
}

lazy_static! {
    pub static ref META: Arc<Mutex<Meta>> = Arc::new(Mutex::new(Meta::new()));
}