Skip to content

Commit

Permalink
feat: Remove Share struct, add documentation, add rc constructor …
Browse files Browse the repository at this point in the history
…variants (#343)

* Cleanup

* Add rc constructor variants; remove Share struct

* Fix share fn in wasm

* Fix wasm code

* Update doc examples

* refactor: Rename `rc` functions to `new_rc`

---------

Co-authored-by: Philipp Krüger <[email protected]>
  • Loading branch information
appcypher and matheus23 authored Sep 4, 2023
1 parent 2d15fbd commit e6cee87
Show file tree
Hide file tree
Showing 28 changed files with 664 additions and 606 deletions.
28 changes: 13 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,15 @@ Let's see an example of working with a public filesystem. We will use the in-mem
```rust
use anyhow::Result;
use chrono::Utc;
use std::rc::Rc;
use wnfs::public::PublicDirectory;
use wnfs_common::MemoryBlockStore;
use wnfs::{
common::MemoryBlockStore,
public::PublicDirectory
};
#[async_std::main]
async fn main() -> Result<()> {
// Create a new public directory.
let dir = &mut Rc::new(PublicDirectory::new(Utc::now()));
let dir = &mut PublicDirectory::new_rc(Utc::now());
// Create an in-memory block store.
let store = &MemoryBlockStore::default();
Expand Down Expand Up @@ -215,12 +216,13 @@ That's the public filesystem, the private filesystem, on the other hand, is a bi
use anyhow::Result;
use chrono::Utc;
use rand::thread_rng;
use std::rc::Rc;
use wnfs::private::{
PrivateDirectory,
forest::{hamt::HamtForest, traits::PrivateForest},
use wnfs::{
common::MemoryBlockStore,
private::{
PrivateDirectory,
forest::{hamt::HamtForest, traits::PrivateForest},
}
};
use wnfs_common::MemoryBlockStore;
#[async_std::main]
async fn main() -> Result<()> {
Expand All @@ -231,14 +233,10 @@ async fn main() -> Result<()> {
let rng = &mut thread_rng();
// Create a private forest.
let forest = &mut Rc::new(HamtForest::new_trusted(rng));
let forest = &mut HamtForest::new_trusted_rc(rng);
// Create a new private directory.
let dir = &mut Rc::new(PrivateDirectory::new(
&forest.empty_name(),
Utc::now(),
rng,
));
let dir = &mut PrivateDirectory::new_rc(&forest.empty_name(), Utc::now(), rng);
// Add a file to /pictures/cats directory.
dir.mkdir(
Expand Down
64 changes: 40 additions & 24 deletions wnfs-common/src/blockstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@ use std::{cell::RefCell, collections::HashMap};

/// The value representing the DAG-JSON codec.
///
/// - https://ipld.io/docs/codecs/#known-codecs
/// - https://github.com/multiformats/multicodec/blob/master/table.csv
/// - <https://ipld.io/docs/codecs/#known-codecs>
/// - <https://github.com/multiformats/multicodec/blob/master/table.csv>
pub const CODEC_DAG_JSON: u64 = 0x0129;

/// The value representing the DAG-CBOR codec.
///
/// - https://ipld.io/docs/codecs/#known-codecs
/// - https://github.com/multiformats/multicodec/blob/master/table.csv
/// - <https://ipld.io/docs/codecs/#known-codecs>
/// - <https://github.com/multiformats/multicodec/blob/master/table.csv>
pub const CODEC_DAG_CBOR: u64 = 0x71;

/// The value representing the DAG-Protobuf codec.
///
/// - https://ipld.io/docs/codecs/#known-codecs
/// - https://github.com/multiformats/multicodec/blob/master/table.csv
/// - <https://ipld.io/docs/codecs/#known-codecs>
/// - <https://github.com/multiformats/multicodec/blob/master/table.csv>
pub const CODEC_DAG_PB: u64 = 0x70;

/// The value representing the raw codec.
///
/// - https://ipld.io/docs/codecs/#known-codecs
/// - https://github.com/multiformats/multicodec/blob/master/table.csv
/// - <https://ipld.io/docs/codecs/#known-codecs>
/// - <https://github.com/multiformats/multicodec/blob/master/table.csv>
pub const CODEC_RAW: u64 = 0x55;

//--------------------------------------------------------------------------------------------------
Expand All @@ -49,18 +49,27 @@ pub trait BlockStore: Sized {
async fn get_block(&self, cid: &Cid) -> Result<Bytes>;
async fn put_block(&self, bytes: impl Into<Bytes>, codec: u64) -> Result<Cid>;

async fn get_deserializable<V: DeserializeOwned>(&self, cid: &Cid) -> Result<V> {
async fn get_deserializable<V>(&self, cid: &Cid) -> Result<V>
where
V: DeserializeOwned,
{
let bytes = self.get_block(cid).await?;
let ipld = decode(bytes.as_ref(), DagCborCodec)?;
Ok(ipld_serde::from_ipld::<V>(ipld)?)
}

async fn put_serializable<V: Serialize>(&self, value: &V) -> Result<Cid> {
async fn put_serializable<V>(&self, value: &V) -> Result<Cid>
where
V: Serialize,
{
let bytes = encode(&ipld_serde::to_ipld(value)?, DagCborCodec)?;
self.put_block(bytes, CODEC_DAG_CBOR).await
}

async fn put_async_serializable<V: AsyncSerialize>(&self, value: &V) -> Result<Cid> {
async fn put_async_serializable<V>(&self, value: &V) -> Result<Cid>
where
V: AsyncSerialize,
{
let ipld = value.async_serialize_ipld(self).await?;
let bytes = encode(&ipld, DagCborCodec)?;
self.put_block(bytes, CODEC_DAG_CBOR).await
Expand Down Expand Up @@ -129,7 +138,6 @@ impl BlockStore for MemoryBlockStore {
// Insert the bytes into the HashMap using the CID as the key
self.0.borrow_mut().insert(cid, bytes);

// Return Ok status with the generated CID
Ok(cid)
}
}
Expand All @@ -138,9 +146,11 @@ impl BlockStore for MemoryBlockStore {
// Tests
//--------------------------------------------------------------------------------------------------

/// The following methods are generic functions that can be used to test any type that conforms to the BlockStore trait.
/// In utilizing this structure, externally defined types can still test for retrieval, duplication, and serialization compatibility.
pub async fn bs_retrieval_test<T: BlockStore + Send + 'static>(store: &T) -> Result<()> {
/// Tests the retrieval property of a BlockStore-conforming type.
pub async fn bs_retrieval_test<T>(store: &T) -> Result<()>
where
T: BlockStore + Send + 'static,
{
// Example objects to insert and remove from the blockstore
let first_bytes = vec![1, 2, 3, 4, 5];
let second_bytes = b"hello world".to_vec();
Expand All @@ -157,12 +167,14 @@ pub async fn bs_retrieval_test<T: BlockStore + Send + 'static>(store: &T) -> Res
assert_eq!(first_loaded, first_bytes);
assert_eq!(second_loaded, second_bytes);

// Return Ok
Ok(())
}

// Generic function used to test any type that conforms to the BlockStore trait
pub async fn bs_duplication_test<T: BlockStore + Send + 'static>(store: &T) -> Result<()> {
/// Tests the duplication of a BlockStore-conforming type.
pub async fn bs_duplication_test<T>(store: &T) -> Result<()>
where
T: BlockStore + Send + 'static,
{
// Example objects to insert and remove from the blockstore
let first_bytes = vec![1, 2, 3, 4, 5];
let second_bytes = first_bytes.clone();
Expand All @@ -181,30 +193,34 @@ pub async fn bs_duplication_test<T: BlockStore + Send + 'static>(store: &T) -> R
// Assert that the objects are the same as the ones we inserted
assert_eq!(first_loaded, first_bytes);
assert_eq!(second_loaded, second_bytes);

// Assert that the objects we loaded are the same
assert_eq!(first_loaded, second_loaded);
// Return Ok

Ok(())
}

pub async fn bs_serialization_test<
/// Tests the serialization of a BlockStore-conforming type.
pub async fn bs_serialization_test<T>(store: &T) -> Result<()>
where
T: BlockStore + Send + Serialize + 'static + for<'de> Deserialize<'de>,
>(
store: &T,
) -> Result<()> {
{
// Example objects to insert and remove from the blockstore
let bytes = vec![1, 2, 3, 4, 5];

// Insert the object into the blockstore
let cid = store.put_serializable(&bytes).await?;

// Serialize the BlockStore
let serial_store: Vec<u8> = encode(&store, DagCborCodec)?;
// Construct a new BlockStore from the Serialized object
let deserial_store: T = decode(&serial_store, DagCborCodec)?;
// Retrieve the object from the blockstore
let loaded: Vec<u8> = deserial_store.get_deserializable(&cid).await?;

// Assert that the objects are the same as the ones we inserted
assert_eq!(loaded, bytes);
// Return Ok

Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion wnfs-common/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl Metadata {
/// assert_eq!(metadata.0.get("foo"), None);
/// ```
///
/// Returns Some<Ipld> if the key existed prior to this call, otherwise None.
/// Returns `Some<Ipld>` if the key existed prior to this call, otherwise None.
pub fn delete(&mut self, key: &str) -> Option<Ipld> {
self.0.remove(key)
}
Expand Down
26 changes: 13 additions & 13 deletions wnfs-wasm/src/fs/private/share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ pub fn share(
access_key: AccessKey,
share_count: u32,
sharer_root_did: String,
sharer_forest: &PrivateForest,
recipient_exchange_root: Vec<u8>,
forest: &PrivateForest,
store: BlockStore,
) -> JsResult<Promise> {
let mut sharer_forest = Rc::clone(&sharer_forest.0);
let mut forest = Rc::clone(&forest.0);
let cid = Cid::try_from(&recipient_exchange_root[..]).map_err(error("Invalid CID"))?;
let store = ForeignBlockStore(store);

Expand All @@ -35,14 +35,14 @@ pub fn share(
&access_key.0,
share_count.into(),
&sharer_root_did,
&mut sharer_forest,
PublicLink::from_cid(cid),
&mut forest,
&store,
)
.await
.map_err(error("Cannot share item"))?;

Ok(value!(PrivateForest(sharer_forest)))
Ok(value!(PrivateForest(forest)))
}))
}

Expand All @@ -51,14 +51,14 @@ pub fn create_share_name(
share_count: u32,
sharer_root_did: &str,
recipient_exchange_key: &[u8],
sharer_forest: &PrivateForest,
forest: &PrivateForest,
) -> Name {
let sharer_forest = Rc::clone(&sharer_forest.0);
let forest = Rc::clone(&forest.0);
Name(sharer::create_share_name(
share_count.into(),
sharer_root_did,
recipient_exchange_key,
&sharer_forest,
&forest,
))
}

Expand All @@ -68,19 +68,19 @@ pub fn find_latest_share_counter(
limit: u32,
recipient_exchange_key: Vec<u8>,
sharer_root_did: String,
sharer_forest: &PrivateForest,
forest: &PrivateForest,
store: BlockStore,
) -> JsResult<Promise> {
let store = ForeignBlockStore(store);
let sharer_forest = Rc::clone(&sharer_forest.0);
let forest = Rc::clone(&forest.0);

Ok(future_to_promise(async move {
let count = recipient::find_latest_share_counter(
share_count.into(),
limit.into(),
&recipient_exchange_key,
&sharer_root_did,
&sharer_forest,
&forest,
&store,
)
.await
Expand All @@ -94,15 +94,15 @@ pub fn find_latest_share_counter(
pub fn receive_share(
share_name: Name,
recipient_key: PrivateKey,
sharer_forest: &PrivateForest,
forest: &PrivateForest,
store: BlockStore,
) -> JsResult<Promise> {
let store = ForeignBlockStore(store);
let recipient_key = ForeignPrivateKey(recipient_key);
let sharer_forest = Rc::clone(&sharer_forest.0);
let forest = Rc::clone(&forest.0);

Ok(future_to_promise(async move {
let node = recipient::receive_share(&share_name.0, &recipient_key, &sharer_forest, &store)
let node = recipient::receive_share(&share_name.0, &recipient_key, &forest, &store)
.await
.map_err(error("Cannot receive share"))?;

Expand Down
25 changes: 10 additions & 15 deletions wnfs-wasm/tests/share.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@ test.describe("Share", () => {
test("share and recieve share", async ({ page }) => {
const result = await page.evaluate(async () => {
const {
wnfs: {
PrivateForest,
share,
createShareName,
receiveShare,
},
wnfs: { PrivateForest, share, createShareName, receiveShare },
mock: {
MemoryBlockStore,
Rng,
Expand All @@ -32,12 +27,12 @@ test.describe("Share", () => {
globalThis.ExchangeKey = ExchangeKey;

const rng = new Rng();
var sharerForest = new PrivateForest(rng);
var forest = new PrivateForest(rng);
const sharerRootDid = "did:key:z6MkqZjY";
const store = new MemoryBlockStore();

var { rootDir: sharerDir, forest: sharerForest } = await createSharerDir(
sharerForest,
var { rootDir: sharerDir, forest: forest } = await createSharerDir(
forest,
store,
rng
);
Expand All @@ -47,26 +42,26 @@ test.describe("Share", () => {

const recipientExchRootCid = await recipientExchRoot.store(store);

var [accessKey, sharerForest2] = await sharerDir
var [accessKey, forest2] = await sharerDir
.asNode()
.store(sharerForest, store, rng);
.store(forest, store, rng);

var sharerForest2 = await share(
var forest2 = await share(
accessKey,
0,
sharerRootDid,
sharerForest2,
recipientExchRootCid,
forest2,
store
);

const modulus = await recipientKey.getPublicKey().getPublicKeyModulus();
const shareLabel = createShareName(0, sharerRootDid, modulus, sharerForest2);
const shareLabel = createShareName(0, sharerRootDid, modulus, forest2);

const sharedNode = await receiveShare(
shareLabel,
recipientKey,
sharerForest2,
forest2,
store
);

Expand Down
Loading

0 comments on commit e6cee87

Please sign in to comment.