Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(meta): improve documentation, comments, doctests for dx #173

Merged
merged 15 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/todo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: todo
on: ["push"]
jobs:
build:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v3"
- name: "TODO to Issue"
uses: "alstr/todo-to-issue-action@v4"
with:
AUTO_ASSIGN: true
IDENTIFIERS: '[{"name": "TODO", "labels": ["T-todo"]}, {"name": "FIX", "labels": ["T-bug"]}]'
48 changes: 46 additions & 2 deletions bifrost/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,47 @@
# Bifrost
# `bifrost`

The version manager for Heimdall
![image](https://github.com/Jon-Becker/heimdall-rs/assets/64037729/4f236ff0-7417-4e8d-8a09-6cb6da9325da)

Bifrost is heimdall's installer and version manager. Named after the rainbow bridge in Norse mythology, `bifrost` is the bridge between heimdall and your system.

## Installation
```bash
curl -L http://get.heimdall.rs | bash
```

## Usage

To install the latest stable release:
```bash
bifrost
```

To install the lastest stable release (pre-compiled):
```bash
bifrost --binary
```

To install a specific branch:
```bash
bifrost --version <branch>
```

To install a specific tag:
```bash
bifrost --version <tag>
```

To install a specific tag (pre-compiled):
```bash
bifrost --version <tag> --binary
```

To list all available versions:
```bash
bifrost --list
```

To update bifrost to the latest version:
```bash
bifrost --update
```
3 changes: 3 additions & 0 deletions cache/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# heimdall-cache

This crate is a simple on-disc caching system utilized by the Heimdall library. Heimdall modules may use this library to save immutable on-chain data to disc, such as bytecode, calldata, as well as the results of expensive computations.
148 changes: 108 additions & 40 deletions cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use util::*;

pub mod util;

/// Clap argument parser for the cache subcommand
#[derive(Debug, Clone, Parser)]
#[clap(
about = "Manage heimdall-rs' cached objects",
Expand All @@ -23,7 +24,7 @@ pub struct CacheArgs {
#[derive(Debug, Clone, Parser)]
pub struct NoArguments {}

/// Clap subcommand parser for the cache subcommand
/// Clap subcommand parser for cache subcommands
#[derive(Debug, Clone, Parser)]
#[clap(
about = "Manage heimdall-rs' cached objects",
Expand All @@ -41,12 +42,31 @@ pub enum Subcommands {
Size(NoArguments),
}

/// A simple cache object that stores a value and an expiry time \
/// The expiry time is a unix timestamp
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Cache<T> {
pub value: T,
pub expiry: u64,
}

/// Clear the cache, removing all objects
///
/// ```
/// use heimdall_cache::{clear_cache, store_cache, keys};
///
/// /// add a value to the cache
/// store_cache("clear_cache_key", "value", None);
///
/// /// assert that the cache contains the key
/// assert!(keys("*").contains(&"clear_cache_key".to_string()));
///
/// /// clear the cache
/// clear_cache();
///
/// /// assert that the cache no longer contains the key
/// assert!(!keys("*").contains(&"clear_cache_key".to_string()));
/// ```
#[allow(deprecated)]
pub fn clear_cache() {
let home = home_dir().unwrap();
Expand All @@ -59,6 +79,20 @@ pub fn clear_cache() {
}
}

/// Check if a cached object exists
///
/// ```
/// use heimdall_cache::{store_cache, exists};
///
/// /// add a value to the cache
/// store_cache("exists_key", "value", None);
///
/// /// assert that the cache contains the key
/// assert!(exists("exists_key"));
///
/// /// assert that the cache does not contain a non-existent key
/// assert!(!exists("non_existent_key"));
/// ```
#[allow(deprecated)]
pub fn exists(key: &str) -> bool {
let home = home_dir().unwrap();
Expand All @@ -68,6 +102,23 @@ pub fn exists(key: &str) -> bool {
cache_file.exists()
}

/// List all cached objects
///
/// ```
/// use heimdall_cache::{store_cache, keys};
///
/// /// add a value to the cache
/// store_cache("keys_key", "value", None);
///
/// /// assert that the cache contains the key
/// assert!(keys("*").contains(&"keys_key".to_string()));
///
/// /// assert that the cache does not contain a non-existent key
/// assert!(!keys("*").contains(&"non_existent_key".to_string()));
///
/// /// assert that the cache contains the key
/// assert!(keys("keys_*").contains(&"keys_key".to_string()));
/// ```
#[allow(deprecated)]
pub fn keys(pattern: &str) -> Vec<String> {
let home = home_dir().unwrap();
Expand All @@ -92,6 +143,22 @@ pub fn keys(pattern: &str) -> Vec<String> {
keys
}

/// Delete a cached object
/// ```
/// use heimdall_cache::{store_cache, delete_cache, keys};
///
/// /// add a value to the cache
/// store_cache("delete_cache_key", "value", None);
///
/// /// assert that the cache contains the key
/// assert!(keys("*").contains(&"delete_cache_key".to_string()));
///
/// /// delete the cached object
/// delete_cache("delete_cache_key");
///
/// /// assert that the cache does not contain the key
/// assert!(!keys("*").contains(&"delete_cache_key".to_string()));
/// ```
#[allow(deprecated)]
pub fn delete_cache(key: &str) {
let home = home_dir().unwrap();
Expand All @@ -103,42 +170,17 @@ pub fn delete_cache(key: &str) {
}
}

#[allow(deprecated)]
pub fn check_expiry<T>() -> bool
where
T: DeserializeOwned, {
let home = home_dir().unwrap();
let cache_dir = home.join(".bifrost").join("cache");

for entry in cache_dir.read_dir().unwrap() {
let entry = entry.unwrap();
let path = entry.path();
let binary_string = match read_file(path.to_str().unwrap()) {
Some(s) => s,
None => return false,
};

let binary_vec = decode_hex(&binary_string);
if binary_vec.is_err() {
return false
}

let cache: Result<Cache<T>, _> = bincode::deserialize(&binary_vec.unwrap());
if cache.is_err() {
delete_path(path.to_str().unwrap());
};

let cache = cache.unwrap();
if cache.expiry <
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs()
{
// delete file
delete_path(path.to_str().unwrap());
}
}
true
}

/// Read a cached object
///
/// ```
/// use heimdall_cache::{store_cache, read_cache};
///
/// /// add a value to the cache
/// store_cache("read_cache_key", "value", None);
///
/// /// read the cached object
/// assert_eq!(read_cache::<String>("read_cache_key").unwrap(), "value");
/// ```
#[allow(deprecated)]
pub fn read_cache<T>(key: &str) -> Option<T>
where
Expand All @@ -158,13 +200,38 @@ where
return None
}

let cache: Cache<T> = match bincode::deserialize(&binary_vec.unwrap()) {
Ok(c) => c,
let cache: Cache<T> = match bincode::deserialize::<Cache<T>>(&binary_vec.unwrap()) {
Ok(c) => {
// check if the cache has expired, if so, delete it and return None
if c.expiry <
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
{
delete_cache(key);
return None
}

c
}
Err(_) => return None,
};
Some(*Box::new(cache.value))
}

/// Store a value in the cache, with an optional expiry time \
/// If no expiry time is specified, the object will expire in 90 days
///
/// ```
/// use heimdall_cache::{store_cache, read_cache};
///
/// /// add a value to the cache with no expiry time (90 days)
/// store_cache("store_cache_key", "value", None);
///
/// /// add a value to the cache with an expiry time of 1 day
/// store_cache("store_cache_key2", "value", Some(60 * 60 * 24));
/// ```
#[allow(deprecated)]
pub fn store_cache<T>(key: &str, value: T, expiry: Option<u64>)
where
Expand All @@ -179,12 +246,13 @@ where
60 * 60 * 24 * 90,
);

let cache = Cache { value: value, expiry: expiry };
let cache = Cache { value, expiry };
let encoded: Vec<u8> = bincode::serialize(&cache).unwrap();
let binary_string = encode_hex(encoded);
write_file(cache_file.to_str().unwrap(), &binary_string);
}

/// Cache subcommand handler
#[allow(deprecated)]
pub fn cache(args: CacheArgs) -> Result<(), Box<dyn std::error::Error>> {
match args.sub {
Expand Down
60 changes: 58 additions & 2 deletions cache/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,49 @@ use std::{
process::Command,
};

// decode a hex into an array of integer values
/// Decode a hex string into a bytearray
///
/// ```
/// use heimdall_cache::util::decode_hex;
///
/// let hex = "48656c6c6f20576f726c64"; // "Hello World" in hex
/// let result = decode_hex(hex);
/// assert_eq!(result, Ok(vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]));
/// ```
pub fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
(0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16)).collect()
}

// encode a hex into a string
/// Encode a bytearray into a hex string
///
/// ```
/// use heimdall_cache::util::encode_hex;
///
/// let bytes = vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
/// let result = encode_hex(bytes);
/// assert_eq!(result, "48656c6c6f20576f726c64");
/// ```
pub fn encode_hex(s: Vec<u8>) -> String {
s.iter().fold(String::new(), |mut acc, b| {
write!(acc, "{b:02x}", b = b).unwrap();
acc
})
}

/// Prettify bytes into a human-readable format \
/// e.g. 1024 -> 1 KB
///
/// ```
/// use heimdall_cache::util::prettify_bytes;
///
/// let bytes = 500;
/// let result = prettify_bytes(bytes);
/// assert_eq!(result, "500 B");
///
/// let bytes = 500_000;
/// let result = prettify_bytes(bytes);
/// assert_eq!(result, "488 KB");
/// ```
pub fn prettify_bytes(bytes: u64) -> String {
if bytes < 1024 {
format!("{bytes} B")
Expand All @@ -34,6 +64,15 @@ pub fn prettify_bytes(bytes: u64) -> String {
}
}

/// Write contents to a file on the disc
///
/// ```no_run
/// use heimdall_cache::util::write_file;
///
/// let path = "/tmp/test.txt";
/// let contents = "Hello, World!";
/// let result = write_file(path, contents);
/// ```
pub fn write_file(_path: &str, contents: &str) -> Option<String> {
let path = std::path::Path::new(_path);
let prefix = path.parent().unwrap();
Expand All @@ -54,6 +93,15 @@ pub fn write_file(_path: &str, contents: &str) -> Option<String> {
Some(_path.to_string())
}

/// Read contents from a file on the disc
///
/// ```no_run
/// use heimdall_cache::util::read_file;
///
/// let path = "/tmp/test.txt";
/// let contents = read_file(path);
/// assert!(contents.is_some());
/// ```
pub fn read_file(_path: &str) -> Option<String> {
let path = std::path::Path::new(_path);
let mut file = match File::open(path) {
Expand All @@ -68,6 +116,14 @@ pub fn read_file(_path: &str) -> Option<String> {
Some(contents)
}

/// Delete a file or directory on the disc
///
/// ```no_run
/// use heimdall_cache::util::delete_path;
///
/// let path = "/tmp/test.txt";
/// let result = delete_path(path);
/// ```
pub fn delete_path(_path: &str) -> bool {
let path = match std::path::Path::new(_path).to_str() {
Some(path) => path,
Expand Down
3 changes: 3 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# heimdall-cli

This crate is a very simple clap-based CLI that allows you to interact with the Heimdall library by wrapping [heimdall-core](../core/README.md) modules.
Loading