#data #cli #cache #data-file #time #fetch #default

tote

适用于 CLI 库的轻量级数据缓存

9 个不稳定版本 (4 个破坏性更改)

0.5.1 2022年5月14日
0.5.0 2021年10月25日
0.4.2 2021年10月7日
0.3.2 2021年10月2日
0.1.0 2020年8月15日

#125缓存

每月下载量 24

MIT 许可证

15KB
208 代码行

Tote Rust

适用于 CLI 库的轻量级数据文件缓存

对于每次调用都查询默认信息集的 CLI,Tote 提供了一种方便的方式将数据缓存到文件中,以便更快地执行后续的 CLI 运行。

Tote 用于缓存(以下示例)时,tote.get() 调用将

  • 检查 Tote 文件路径是否存在以及是否在指定的过期时间内被修改
  • 反序列化并返回数据

如果缓存数据不存在或已过期,Tote

  • 使用 Fetch::fetch 方法检索数据
  • 使用 serde_json 序列化数据并将数据写入 Tote 文件路径
  • 返回新检索的数据

功能

默认

默认功能使用同步的 Fetch 特性

use std::time::Duration;

use serde_derive::{Serialize, Deserialize};
use tote::{Fetch, Tote};

// Implement `serde`'s `Serialize`/`Deserialize` for you own data
// or make a NewType and `derive` so `Tote` can read and write the cached data
#[derive(Debug, Deserialize, Serialize)]
struct NearbyCities(Vec<String>);

impl Fetch for NearbyCities {
    type Cached = NearbyCities;

    fn fetch() -> Result<NearbyCities, Box<dyn std::error::Error>> {
        let resp = reqwest::blocking::get("http://getnearbycities.geobytes.com/GetNearbyCities?radius=10")?
           .json::<Vec<Vec<String>>>()?;
        let cities = resp.into_iter().map(|city| format!("{}, {}", city[1], city[2])).collect();
        Ok(NearbyCities(cities))
    }
}

fn main () -> Result<(), Box<dyn std::error::Error>> {
    // Create a Tote at the given path, with data expiry of 1 day
    let cache: Tote<NearbyCities> = Tote::new(".my_tool.cache", Duration::from_secs(86400));

    // This `.get()` call will use data cached in ".my_tool.cache" if:
    // - The file exists & has valid data
    // - The file has been modified in the past 1 day
    // Otherwise `NearbyCities::fetch` is called to get the data and populate the cache file
    let nearby_cities = cache.get()?;
    println!("Cities near you are: {:?}", nearby_cities);
    # std::fs::remove_file(".my_tool.cache")?; // Cleanup for doctest
    Ok(())
}

异步

“异步”功能添加了 AsyncFetch 特性,如果您想使用异步 I/O 来获取数据。调用 Tote::get_async().await 获取 Tote 内容。

Cargo.toml

tote = { version = "*", features = ["async"] }
use std::collections::HashMap;
use std::net::IpAddr;
use std::time::Duration;

use async_trait::async_trait;
use serde_derive::{Serialize, Deserialize};
use tote::{AsyncFetch, Tote};

// Implement `serde`'s `Serialize`/`Deserialize` for you own data
// or make a NewType and `derive` so `Tote` can read and write the cached data
#[derive(Debug, Deserialize, Serialize)]
struct MyPublicIp(IpAddr);

#[async_trait]
impl AsyncFetch for MyPublicIp {
    type Cached = MyPublicIp;

    async fn fetch_async() -> Result<MyPublicIp, Box<dyn std::error::Error>> {
       let resp = reqwest::get("https://httpbin.org/ip")
           .await?
           .json::<HashMap<String, String>>()
           .await?;
        let origin_ip = resp["origin"].parse()?;
        Ok(MyPublicIp(origin_ip))
    }
}

#[tokio::main]
async fn main () -> Result<(), Box<dyn std::error::Error>> {
    // Create a Tote at the given path, with data expiry of 1 day
    let cache: Tote<MyPublicIp> = Tote::new(".my_tool.cache", Duration::from_secs(86400));
    // This `.get_async().await` call will use data cached in ".my_tool.cache" if:
    // - The file exists & has valid data
    // - The file has been modified in the past 1 day
    // Otherwise `MyPublicIp::fetch_async` is called to get the data and populate the cache file
    let public_ip = cache.get_async().await?;
    println!("Your public IP address is {}", public_ip.0);
    # std::fs::remove_file(".my_tool.cache")?; // Cleanup for doctest
    Ok(())
}

依赖项

~0.6–1.4MB
~32K SLoC