Skip to content

Commit

Permalink
feat: Add a function to get the exact size of a PublicFile and `Pri…
Browse files Browse the repository at this point in the history
…vateFile` (#405)

Adds a `size` function to `PublicFile` and `PrivateFile`, and their wasm equivalents, that returns the exact size of the contents without downloading all the content blocks.

Added doc tests for the core lib, and tests for the wasm lib.

---

* feat: Add a function to get the exact size of a PublicFile and PrivateFile

* refactor: Change `get_size` return type to `u64`

* chore: Fix nightly lints

* refactor: Rename `get_size` -> `size` in `wnfs` crate

* chore: Fix nightly lints & wasm

---------

Co-authored-by: Philipp Krüger <[email protected]>
  • Loading branch information
icidasset and matheus23 authored Feb 28, 2024
1 parent 8ac4021 commit 17c980c
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 69 deletions.
2 changes: 1 addition & 1 deletion wnfs-common/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{
de::{DeserializeOwned, Error as DeError},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{collections::BTreeMap, convert::TryInto, fmt::Display};
use std::{collections::BTreeMap, fmt::Display};

//--------------------------------------------------------------------------------------------------
// Type Definitions
Expand Down
2 changes: 0 additions & 2 deletions wnfs-common/src/storable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ macro_rules! impl_storable_from_serde {
};
}

pub use impl_storable_from_serde;

//--------------------------------------------------------------------------------------------------
// Type Definitions
//--------------------------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion wnfs-hamt/src/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ where
}

for Pair { key, value } in &other_values {
if main_map.get(key).is_none() {
if !main_map.contains_key(key) {
changes.push(KeyValueChange {
r#type: ChangeType::Remove,
key: key.clone(),
Expand Down
11 changes: 5 additions & 6 deletions wnfs-hamt/src/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ use wnfs_common::{
//--------------------------------------------------------------------------------------------------

/// Merges a node with another with the help of a resolver function.
pub async fn merge<K: CondSync, V: CondSync, H, F, B: BlockStore>(
pub async fn merge<K, V, H>(
main_link: Link<Arc<Node<K, V, H>>>,
other_link: Link<Arc<Node<K, V, H>>>,
f: F,
store: &B,
f: impl Fn(&V, &V) -> Result<V>,
store: &impl BlockStore,
) -> Result<Arc<Node<K, V, H>>>
where
F: Fn(&V, &V) -> Result<V>,
K: Storable + Eq + Clone + Hash + AsRef<[u8]>,
V: Storable + Eq + Clone,
K: Storable + Eq + Clone + CondSync + Hash + AsRef<[u8]>,
V: Storable + Eq + Clone + CondSync,
K::Serializable: Serialize + DeserializeOwned,
V::Serializable: Serialize + DeserializeOwned,
H: Hasher + CondSync,
Expand Down
5 changes: 3 additions & 2 deletions wnfs-hamt/src/strategies/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use wnfs_common::{
// Functions
//--------------------------------------------------------------------------------------------------

pub fn generate_kvs<K: Debug + Clone, V: Debug + Clone>(
pub fn generate_kvs<K, V>(
key: impl Strategy<Value = K>,
value: impl Strategy<Value = V>,
size: impl Into<SizeRange>,
) -> impl Strategy<Value = Vec<(K, V)>>
where
K: Eq + Hash,
K: Debug + Clone + Eq + Hash,
V: Debug + Clone,
{
vec((key, value), size).prop_map(|vec| {
vec.into_iter()
Expand Down
6 changes: 3 additions & 3 deletions wnfs-hamt/src/strategies/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,13 @@ where
/// println!("{:?}", node);
/// }
/// ```
pub async fn node_from_operations<K: CondSync, V: CondSync>(
pub async fn node_from_operations<K, V>(
operations: &Operations<K, V>,
store: &impl BlockStore,
) -> Result<Arc<Node<K, V>>>
where
K: Storable + Clone + Debug + AsRef<[u8]>,
V: Storable + Clone + Debug,
K: Storable + Clone + Debug + CondSync + AsRef<[u8]>,
V: Storable + Clone + Debug + CondSync,
K::Serializable: Serialize + DeserializeOwned,
V::Serializable: Serialize + DeserializeOwned,
{
Expand Down
17 changes: 17 additions & 0 deletions wnfs-wasm/src/fs/private/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,23 @@ impl PrivateFile {
self.read_at(value!(0).into(), None, forest, store)
}

/// Gets the exact content size without fetching all content blocks.
#[wasm_bindgen(js_name = "getSize")]
pub fn get_size(&self, forest: &PrivateForest, store: BlockStore) -> JsResult<Promise> {
let file = Rc::clone(&self.0);
let store = ForeignBlockStore(store);
let forest = Rc::clone(&forest.0);

Ok(future_to_promise(async move {
let size = file
.size(&forest, &store)
.await
.map_err(error("Cannot determine file size"))?;

Ok(value!(size as usize))
}))
}

/// Gets the metadata of this file.
pub fn metadata(&self) -> JsResult<JsValue> {
JsMetadata(self.0.get_metadata()).try_into()
Expand Down
16 changes: 16 additions & 0 deletions wnfs-wasm/src/fs/public/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ impl PublicFile {
self.read_at(value!(0).into(), None, store)
}

/// Gets the exact content size without fetching all content blocks.
#[wasm_bindgen(js_name = "getSize")]
pub fn get_size(&self, store: BlockStore) -> JsResult<Promise> {
let file = Rc::clone(&self.0);
let store = ForeignBlockStore(store);

Ok(future_to_promise(async move {
let size = file
.size(&store)
.await
.map_err(error("Cannot determine file size"))?;

Ok(value!(size as usize))
}))
}

/// Gets the metadata of this file.
pub fn metadata(&self) -> JsResult<JsValue> {
JsMetadata(self.0.get_metadata()).try_into()
Expand Down
25 changes: 25 additions & 0 deletions wnfs-wasm/tests/private.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,31 @@ test.describe("PrivateFile", () => {
expect(new Uint8Array(Object.values(content))).toEqual(new Uint8Array([2, 3, 4]));
});

test("getSize returns the exact content size", async ({ page }) => {
const size = await page.evaluate(async () => {
const {
wnfs: { PrivateFile, PrivateForest },
mock: { MemoryBlockStore, Rng },
} = await window.setup();

const rng = new Rng();
const initialForest = new PrivateForest(rng);
const store = new MemoryBlockStore();
var [file, forest] = await PrivateFile.withContent(
initialForest.emptyName(),
new Date(),
new Uint8Array(2 * 1024 * 1024),
initialForest,
store,
rng,
);

return await file.getSize(forest, store);
});

expect(size).toEqual(2 * 1024 * 1024);
});

test("A PrivateDirectory has the correct metadata", async ({ page }) => {
const result = await page.evaluate(async () => {
const {
Expand Down
77 changes: 36 additions & 41 deletions wnfs-wasm/tests/public.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ test.describe("PublicDirectory", () => {
expect(result).toBeDefined();
});

test("lookupNode cannot fetch file not added to directory", async ({
page,
}) => {
test("lookupNode cannot fetch file not added to directory", async ({ page }) => {
const result = await page.evaluate(async () => {
const {
wnfs: { PublicDirectory },
Expand Down Expand Up @@ -65,18 +63,12 @@ test.describe("PublicDirectory", () => {
["pictures", "cats", "tabby.png"],
sampleCID,
time,
store
store,
);

let result0 = await rootDir.getNode(
["pictures", "cats", "tabby.png"],
store
);
let result0 = await rootDir.getNode(["pictures", "cats", "tabby.png"], store);

let result1 = await rootDir.getNode(
["pictures", "dogs", "bingo.png"],
store
);
let result1 = await rootDir.getNode(["pictures", "dogs", "bingo.png"], store);

return [result0, result1];
});
Expand All @@ -102,7 +94,7 @@ test.describe("PublicDirectory", () => {
["pictures", "cats", "tabby.png"],
sampleCID,
time,
store
store,
);

await rootDir.getNode(["pictures", "cats", "tabby.png"], store);
Expand Down Expand Up @@ -130,7 +122,7 @@ test.describe("PublicDirectory", () => {
["pictures", "cats", "tabby.png"],
sampleCID,
time,
store
store,
);

const result = await rootDir.ls(["pictures"], store);
Expand Down Expand Up @@ -158,14 +150,14 @@ test.describe("PublicDirectory", () => {
["pictures", "dogs", "billie.jpeg"],
sampleCID,
time,
store
store,
);

var { rootDir } = await rootDir.write(
["pictures", "cats", "tabby.png"],
sampleCID,
time,
store
store,
);

var { rootDir } = await rootDir.rm(["pictures", "cats"], store);
Expand All @@ -190,18 +182,13 @@ test.describe("PublicDirectory", () => {
const store = new MemoryBlockStore();
const root = new PublicDirectory(time);

var { rootDir } = await root.write(
["pictures", "cats", "luna.jpeg"],
sampleCID,
time,
store
);
var { rootDir } = await root.write(["pictures", "cats", "luna.jpeg"], sampleCID, time, store);

var { rootDir } = await rootDir.write(
["pictures", "cats", "tabby.png"],
sampleCID,
time,
store
store,
);

var { rootDir } = await rootDir.mkdir(["images"], time, store);
Expand All @@ -210,7 +197,7 @@ test.describe("PublicDirectory", () => {
["pictures", "cats"],
["images", "cats"],
time,
store
store,
);

const imagesContent = await rootDir.ls(["images"], store);
Expand All @@ -236,28 +223,18 @@ test.describe("PublicDirectory", () => {
const store = new MemoryBlockStore();
const root = new PublicDirectory(time);

var { rootDir } = await root.write(
["pictures", "cats", "luna.jpeg"],
sampleCID,
time,
store
);
var { rootDir } = await root.write(["pictures", "cats", "luna.jpeg"], sampleCID, time, store);

var { rootDir } = await rootDir.write(
["pictures", "cats", "tabby.png"],
sampleCID,
time,
store
store,
);

var { rootDir } = await rootDir.mkdir(["images"], time, store);

var { rootDir } = await rootDir.cp(
["pictures", "cats"],
["images", "cats"],
time,
store
);
var { rootDir } = await rootDir.cp(["pictures", "cats"], ["images", "cats"], time, store);

const imagesContent = await rootDir.ls(["images"], store);

Expand Down Expand Up @@ -314,10 +291,7 @@ test.describe("PublicDirectory", () => {
const readBack = await file2.getContent(store);
const partialRead = await file2.readAt(7, 5, store);

return [
new TextDecoder().decode(readBack),
new TextDecoder().decode(partialRead)
];
return [new TextDecoder().decode(readBack), new TextDecoder().decode(partialRead)];
});

expect(result[0]).toEqual("Hello, World!");
Expand Down Expand Up @@ -370,4 +344,25 @@ test.describe("PublicDirectory", () => {
expect(result).not.toBeUndefined();
expect(result).toEqual("bafkr4ihkr4ld3m4gqkjf4reryxsy2s5tkbxprqkow6fin2iiyvreuzzab4");
});

test("A PublicFile has a content size", async ({ page }) => {
const result = await page.evaluate(async () => {
const {
wnfs: { PublicFile },
mock: { MemoryBlockStore },
} = await window.setup();

const store = new MemoryBlockStore();
const time = new Date();
const file = new PublicFile(time);

const longString = "x".repeat(5 * 1024 * 1024);
const content = new TextEncoder().encode(longString);
const file2 = await file.setContent(time, content, store);

return await file2.getSize(store);
});

expect(result).toEqual(5 * 1024 * 1024);
});
});
Loading

0 comments on commit 17c980c

Please sign in to comment.