Tote

A lightweight data file cache for CLI libraries

For CLIs that query a default set of information with each invocation, Tote offers a convenient way to cache data to a file for quicker subsequent CLI runs.

When Tote is used for a cache (examples below), the tote.get() call will: - Check that the Tote filepath exists and has been modified within the specified expiry time - Deserialize and return the data

If the cached data is not present or expired, Tote will: - Use the Fetch::fetch methods to retrieve the data - Serialize the data (using serde_json) and write to the Tote filepath - Return the newly fetched data

Features

Default

The default feature uses a Synchronous Fetch trait:

```rust 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 MyData(Vec); impl Fetch for MyData { fn fetch() -> Result> { // This would likely do some I/O to fetch common data Ok(MyData(vec!["Larkspur".toowned(), "Lavender".toowned(), "Periwinkle".to_owned()])) } }

fn main () -> Result<(), Box> { // Create a Tote at the given path, with data expiry of 1 day let cache: Tote = Tote::new(".mytool.cache", Duration::fromsecs(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 `MyData::fetch` is called to get the data and populate the cache file
let available_colors = cache.get()?;
println!("Colors you can use are: {:?}", available_colors);
# std::fs::remove_file(".my_tool.cache")?;
Ok(())

} ```

Async

Specify the "async" feature to enable the AsyncFetch trait if you want to use async I/O for fetching data. Call Tote::get_async().await to get the Tote contents.

Cargo.toml

toml tote = { version = "*", features = ["async"] }

```rust use std::collections::HashMap; use std::net::IpAddr; use std::time::Duration; use asynctrait::asynctrait; 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 MyData(IpAddr);

[async_trait]

impl AsyncFetch for MyData { async fn fetchasync() -> Result> { let resp = reqwest::get("https://httpbin.org/ip") .await? .json::>() .await?; let originip = resp["origin"].parse()?; Ok(MyData(origin_ip)) } }

[tokio::main]

async fn main () -> Result<(), Box> { // Create a Tote at the given path, with data expiry of 1 day let cache: Tote = Tote::new(".mytool.cache", Duration::fromsecs(86400)); // This .get_async().await call will use data cached in ".mytool.cache" if: // - The file exists & has valid data // - The file has been modified in the past 1 day // Otherwise MyData::fetch_async is called to get the data and populate the cache file let publicip = cache.getasync().await?; println!("Your public IP address is {}", publicip.0); # std::fs::removefile(".mytool.cache")?; Ok(()) } ```