Compare commits

...

2 Commits

Author SHA1 Message Date
1c8c593de3 wip: use proper hashes 2025-04-02 18:42:48 -04:00
be288dfcd6 wip: make the payloads for objects random 2025-04-01 21:35:11 -04:00
5 changed files with 291 additions and 60 deletions

184
Cargo.lock generated
View File

@ -24,6 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288" checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288"
dependencies = [ dependencies = [
"axum-core", "axum-core",
"axum-macros",
"bytes", "bytes",
"form_urlencoded", "form_urlencoded",
"futures-util", "futures-util",
@ -71,6 +72,17 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "axum-macros"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.74"
@ -86,6 +98,30 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.10.1" version = "1.10.1"
@ -98,6 +134,27 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -146,6 +203,28 @@ dependencies = [
"pin-utils", "pin-utils",
] ]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.31.1" version = "0.31.1"
@ -285,7 +364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys", "windows-sys",
] ]
@ -303,6 +382,8 @@ name = "offline-web"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum",
"blake2",
"rand",
"serde", "serde",
"tokio", "tokio",
] ]
@ -331,6 +412,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.94" version = "1.0.94"
@ -349,6 +439,42 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core",
"zerocopy",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.24" version = "0.1.24"
@ -437,6 +563,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.100" version = "2.0.100"
@ -528,18 +660,39 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.18" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
@ -612,3 +765,32 @@ name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@ -11,6 +11,8 @@ name = "example"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
axum = "0.8.3" axum = { version = "0.8.3", features = ["macros"] }
blake2 = "0.10.6"
rand = "0.9.0"
serde = { version = "1.0.219", features = ["derive", "rc"] } serde = { version = "1.0.219", features = ["derive", "rc"] }
tokio = "1.44.1" tokio = "1.44.1"

View File

@ -1,14 +1,14 @@
use std::rc::Rc; use std::sync::Arc;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug)]
pub struct Reference { pub struct Reference {
object_id: String, pub object_id: String,
content_address: String, pub content_address: String,
path: String, pub path: String,
#[serde(skip_serializing_if = "Vec::is_empty")] #[serde(skip_serializing_if = "Vec::is_empty")]
dependents: Vec<Rc<Reference>>, pub dependents: Vec<Arc<Reference>>,
} }
impl Reference { impl Reference {
@ -21,12 +21,16 @@ impl Reference {
} }
} }
pub fn add_dep(mut self, dep: Rc<Reference>) -> Self { pub fn add_dep(mut self, dep: Arc<Reference>) -> Self {
self.dependents.push(dep); self.dependents.push(dep);
self self
} }
pub fn to_rc(self) -> Rc<Self> { pub fn to_arc(self) -> Arc<Self> {
Rc::new(self) Arc::new(self)
}
pub fn is_leaf(&self) -> bool {
return self.dependents.is_empty();
} }
} }

View File

@ -1,66 +1,97 @@
use std::rc::Rc; use std::{collections::HashMap, sync::Arc};
use axum::{extract::Path, http, response::{Html, IntoResponse}, routing::get, Json, Router};
use blake2::{Blake2b512, Digest};
use rand::Rng;
use axum::{extract::Path, http::{self, Response}, response::{AppendHeaders, Html, IntoResponse}, routing::get, Json, Router};
use datamodel::Reference; use datamodel::Reference;
mod datamodel; mod datamodel;
async fn all_references() -> Json<Rc<Reference>> { #[derive(Debug)]
pub struct AddressableObject {
pub address: String,
pub content: String,
}
fn random_object() -> AddressableObject {
let mut rng = rand::rng();
let random_size = rng.random_range(50..=4096);
let random_string: String = (0..random_size)
.map(|_| rng.sample(rand::distr::Alphanumeric) as char)
.collect();
let mut hasher = Blake2b512::new();
hasher.update(&random_string);
let hash = format!("{:x}", hasher.finalize());
AddressableObject {
address: hash,
content: random_string,
}
}
fn random_references_and_objects() -> (Arc<Reference>, Arc<HashMap<String, Arc<Reference>>>, Arc<HashMap<String, AddressableObject>>) {
let path_root = String::from("ref/0"); let path_root = String::from("ref/0");
let mut objects = HashMap::new();
let mut refs = HashMap::new();
let mut root_ref = Reference::new( let mut root_ref = Reference::new(
"username:0".to_string(), "username:0".to_string(),
String::from("0"), String::from("0"),
path_root.clone(), path_root.clone(),
); );
let mut root_hasher = Blake2b512::new();
for i in 1..=10 { for i in 1..=10 {
let mut item_ref = Reference::new( let mut item_ref = Reference::new(
format!("item:{}", i), format!("item:{}", i),
format!("0:{}", i), format!("0:{}", i),
format!("{}/item/{}", path_root, i), format!("/item/{}", i),
); );
let mut hasher = Blake2b512::new();
for j in 1..=10 { for j in 1..=10 {
item_ref = item_ref.add_dep(Rc::new(Reference::new( let object = random_object();
hasher.update(&object.content);
let leaf_ref = Reference::new(
format!("item:{}:subitem:{}", i, j), format!("item:{}:subitem:{}", i, j),
format!("0:{}:{}", i, j), format!("{}", object.address),
format!("{}/item/{}/subitem/{}", path_root, i, j), format!("/item/{}/subitem/{}", i, j),
))); ).to_arc();
item_ref = item_ref.add_dep(leaf_ref.clone());
objects.insert(object.address.clone(), object);
hasher.update(&leaf_ref.content_address);
refs.insert(leaf_ref.path.clone(), leaf_ref);
} }
root_ref = root_ref.add_dep(Rc::new(item_ref)); let hash = format!("{:x}", hasher.finalize());
item_ref.content_address = hash;
root_hasher.update(&item_ref.content_address);
let rc_ref = item_ref.to_arc();
root_ref = root_ref.add_dep(rc_ref.clone());
refs.insert(rc_ref.path.clone(), rc_ref);
} }
Json(root_ref.to_rc()) root_ref.content_address = format!("{:x}", root_hasher.finalize());
let rc_root = root_ref.to_arc();
refs.insert(rc_root.path.clone(), rc_root.clone());
dbg!(&objects);
(rc_root, Arc::new(refs), Arc::new(objects))
} }
async fn dummy_item_ref(Path(i): Path<usize>) -> Json<Rc<Reference>> { async fn all_references(root_ref: Arc<Reference>) -> Json<Arc<Reference>> {
let path_root = String::from("ref/0"); Json(root_ref)
let mut item_ref = Reference::new(
format!("item:{}", i),
format!("0:{}", i),
format!("{}/item/{}", path_root, i),
);
for j in 1..=10 {
item_ref = item_ref.add_dep(Rc::new(Reference::new(
format!("item:{}:subitem:{}", i, j),
format!("0:{}:{}", i, j),
format!("{}/item/{}/subitem/{}", path_root, i, j),
)));
}
Json(item_ref.to_rc())
} }
async fn dummy_subitem_ref(Path(i): Path<usize>, Path(j): Path<usize>) -> Json<Rc<Reference>> { async fn ref_path(refs: Arc<HashMap<String, Arc<Reference>>>, Path(path): Path<String>) -> Json<Arc<Reference>> {
let path_root = String::from("ref/0"); let path = format!("/item/{}", path);
Json( match refs.get(&path) {
Reference::new( Some(r) => Json(r.clone()),
format!("item:{}:subitem:{}", i, j), None => todo!("Return a 404?"),
format!("0:{}:{}", i, j), }
format!("{}/item/{}/subitem/{}", path_root, i, j),
)
.to_rc(),
)
} }
async fn dummy_object(Path(addr): Path<String>) -> String { async fn object_path(objects: Arc<HashMap<String, AddressableObject>>, Path(path): Path<String>) -> String {
format!("I am object {}", addr) dbg!(&path);
match objects.get(&path) {
Some(o) => o.content.clone(),
None => todo!("Return a 404?"),
}
} }
async fn get_client_js() -> impl IntoResponse { async fn get_client_js() -> impl IntoResponse {
@ -70,19 +101,27 @@ async fn get_client_js() -> impl IntoResponse {
) )
} }
pub fn endpoints() -> Router { pub fn endpoints(root_ref: Arc<Reference>, refs: Arc<HashMap<String, Arc<Reference>>>, objects: Arc<HashMap<String, AddressableObject>>) -> Router {
Router::new().nest( Router::new().nest(
"/api/v1", "/api/v1",
Router::new().nest( Router::new().nest(
"/ref", "/ref",
Router::new() Router::new()
.route("/all/username", get(all_references)) .route("/all/username", get({
.route("/item/{i}", get(dummy_item_ref)) let state = root_ref.clone();
.route("/item/{i}/subitem/{j}", get(dummy_subitem_ref)) move || all_references(state)
}))
.route("/item/{*path}", get({
let refs = refs.clone();
move |path| ref_path(refs, path)
}))
).nest( ).nest(
"/object", "/object",
Router::new() Router::new()
.route("/{addr}", get(dummy_object)) .route("/{addr}", get({
let objects = objects.clone();
move |path| object_path(objects, path)
}))
), ),
) )
.route("/lib/client.js", get(get_client_js)) .route("/lib/client.js", get(get_client_js))
@ -92,8 +131,9 @@ pub fn endpoints() -> Router {
// TODO(jwall): Javascript test script // TODO(jwall): Javascript test script
pub async fn serve() { pub async fn serve() {
// run our app with hyper, listening globally on port 3000 // run our app with hyper, listening globally on port 3000
let (root_ref, refs, objects) = random_references_and_objects();
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await .await
.unwrap(); .unwrap();
axum::serve(listener, endpoints()).await.unwrap(); axum::serve(listener, endpoints(root_ref, refs, objects)).await.unwrap();
} }

View File

@ -95,11 +95,14 @@ async function load_objects_and_store(db, references, storeName) {
let objects = [] let objects = []
for (var ref of references) { for (var ref of references) {
/** @type {Response} */ /** @type {Response} */
if (ref.dependents && ref.dependents.length != 0) {
continue; // not a leaf object
}
let response = await fetch("/api/v1/object/" + ref.content_address); let response = await fetch("/api/v1/object/" + ref.content_address);
if (!response.ok) { if (!response.ok) {
throw new Error("Network response was not ok: " + response.statusText); throw new Error("Network response was not ok: " + response.statusText);
} }
let object = await response.text(); const object = await response.text();
objects.push({ id: ref.content_address, content: object }); objects.push({ id: ref.content_address, content: object });
} }
const objectTrxAndStore = await getStoreAndTransaction(db, storeName); const objectTrxAndStore = await getStoreAndTransaction(db, storeName);
@ -130,7 +133,7 @@ async function bootstrap() {
const objectStoreName = "objects"; const objectStoreName = "objects";
const databaseName = "MerkleStore"; const databaseName = "MerkleStore";
const start = new Date().getTime(); const start = new Date().getTime();
let root = await load_bootstrap(); const root = await load_bootstrap();
const db = await openDatabase(databaseName, [refStoreName, objectStoreName]); const db = await openDatabase(databaseName, [refStoreName, objectStoreName]);
const refTrxAndStore = await getStoreAndTransaction(db, refStoreName); const refTrxAndStore = await getStoreAndTransaction(db, refStoreName);
@ -140,13 +143,13 @@ async function bootstrap() {
refTrxAndStore.trx.onerror = (event) => reject(event.target.error); refTrxAndStore.trx.onerror = (event) => reject(event.target.error);
}); });
let refs = await load_reference_paths(refTrxAndStore.store, root); const refs = await load_reference_paths(refTrxAndStore.store, root);
// Wait for the transaction to complete // Wait for the transaction to complete
await transactionComplete; await transactionComplete;
await load_objects_and_store(db, refs, objectStoreName); await load_objects_and_store(db, refs, objectStoreName);
var end = new Date().getTime(); const end = new Date().getTime();
return end - start; return end - start;
} }