wip: use proper hashes
This commit is contained in:
parent
be288dfcd6
commit
1c8c593de3
80
Cargo.lock
generated
80
Cargo.lock
generated
@ -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"
|
||||||
@ -92,6 +104,24 @@ version = "2.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
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"
|
||||||
@ -104,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"
|
||||||
@ -152,6 +203,16 @@ 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]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@ -321,6 +382,7 @@ name = "offline-web"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
|
"blake2",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -501,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"
|
||||||
@ -592,12 +660,24 @@ 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"
|
||||||
|
@ -11,7 +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"
|
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"
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
160
src/lib.rs
160
src/lib.rs
@ -1,72 +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 axum::{extract::Path, http, response::{Html, IntoResponse}, routing::get, Json, Router};
|
||||||
use datamodel::Reference;
|
use blake2::{Blake2b512, Digest};
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use datamodel::Reference;
|
||||||
mod datamodel;
|
mod datamodel;
|
||||||
|
|
||||||
async fn all_references() -> Json<Rc<Reference>> {
|
#[derive(Debug)]
|
||||||
let path_root = String::from("ref/0");
|
pub struct AddressableObject {
|
||||||
let mut root_ref = Reference::new(
|
pub address: String,
|
||||||
"username:0".to_string(),
|
pub content: String,
|
||||||
String::from("0"),
|
|
||||||
path_root.clone(),
|
|
||||||
);
|
|
||||||
for i in 1..=10 {
|
|
||||||
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),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
root_ref = root_ref.add_dep(Rc::new(item_ref));
|
|
||||||
}
|
|
||||||
Json(root_ref.to_rc())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dummy_item_ref(Path(i): Path<usize>) -> Json<Rc<Reference>> {
|
fn random_object() -> AddressableObject {
|
||||||
let path_root = String::from("ref/0");
|
|
||||||
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>> {
|
|
||||||
let path_root = String::from("ref/0");
|
|
||||||
Json(
|
|
||||||
Reference::new(
|
|
||||||
format!("item:{}:subitem:{}", i, j),
|
|
||||||
format!("0:{}:{}", i, j),
|
|
||||||
format!("{}/item/{}/subitem/{}", path_root, i, j),
|
|
||||||
)
|
|
||||||
.to_rc(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn dummy_object(Path(addr): Path<String>) -> String {
|
|
||||||
use rand::Rng;
|
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
let random_size = rng.random_range(50..=4096);
|
let random_size = rng.random_range(50..=4096);
|
||||||
let random_string: String = (0..random_size)
|
let random_string: String = (0..random_size)
|
||||||
.map(|_| rng.sample(rand::distr::Alphanumeric) as char)
|
.map(|_| rng.sample(rand::distr::Alphanumeric) as char)
|
||||||
.collect();
|
.collect();
|
||||||
format!("I am object {} -- {}", addr, random_string)
|
|
||||||
|
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 mut objects = HashMap::new();
|
||||||
|
let mut refs = HashMap::new();
|
||||||
|
let mut root_ref = Reference::new(
|
||||||
|
"username:0".to_string(),
|
||||||
|
String::from("0"),
|
||||||
|
path_root.clone(),
|
||||||
|
);
|
||||||
|
let mut root_hasher = Blake2b512::new();
|
||||||
|
for i in 1..=10 {
|
||||||
|
let mut item_ref = Reference::new(
|
||||||
|
format!("item:{}", i),
|
||||||
|
format!("0:{}", i),
|
||||||
|
format!("/item/{}", i),
|
||||||
|
);
|
||||||
|
let mut hasher = Blake2b512::new();
|
||||||
|
for j in 1..=10 {
|
||||||
|
let object = random_object();
|
||||||
|
hasher.update(&object.content);
|
||||||
|
let leaf_ref = Reference::new(
|
||||||
|
format!("item:{}:subitem:{}", i, j),
|
||||||
|
format!("{}", object.address),
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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 all_references(root_ref: Arc<Reference>) -> Json<Arc<Reference>> {
|
||||||
|
Json(root_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ref_path(refs: Arc<HashMap<String, Arc<Reference>>>, Path(path): Path<String>) -> Json<Arc<Reference>> {
|
||||||
|
let path = format!("/item/{}", path);
|
||||||
|
match refs.get(&path) {
|
||||||
|
Some(r) => Json(r.clone()),
|
||||||
|
None => todo!("Return a 404?"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn object_path(objects: Arc<HashMap<String, AddressableObject>>, Path(path): Path<String>) -> String {
|
||||||
|
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 {
|
||||||
@ -76,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))
|
||||||
@ -98,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();
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,9 @@ 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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user