Skip to content

Commit

Permalink
Add some WASM APIs (#39)
Browse files Browse the repository at this point in the history
* Add some WASM APIs

- Provide metadata info in `ls`
- Expose `base_history_on` function
- Expose `load` function

* Fix type error

* Fix tests

* Replace hardcoded `3.0.0` version with loaded version

Co-authored-by: appcypher <[email protected]>

* Use `wasm-pack build --target web`

* Implement and use `From<UnixFsNodeKind> for String`

* Fix TryInto<JsValue> for JsMetadata

* Add `type: module` and `main: wasm_wnfs.js` entries

Co-authored-by: appcypher <[email protected]>
  • Loading branch information
matheus23 and appcypher authored Jul 27, 2022
1 parent 6d40083 commit 4837cba
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 16 deletions.
25 changes: 19 additions & 6 deletions crates/fs/common/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ pub enum UnixFsMode {
/// See <https://docs.ipfs.io/concepts/file-systems/#unix-file-system-unixfs>
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnixFsMetadata {
pub(crate) created: i64,
pub(crate) modified: i64,
pub(crate) mode: UnixFsMode,
pub(crate) kind: UnixFsNodeKind,
pub created: i64,
pub modified: i64,
pub mode: UnixFsMode,
pub kind: UnixFsNodeKind,
}

/// The metadata of a node on the WNFS file system.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Metadata {
pub(crate) unix_fs: UnixFsMetadata,
pub(crate) version: Version,
pub unix_fs: UnixFsMetadata,
pub version: Version,
}

//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -208,6 +208,19 @@ impl TryFrom<&str> for UnixFsNodeKind {
}
}

impl From<&UnixFsNodeKind> for String {
fn from(kind: &UnixFsNodeKind) -> Self {
match kind {
UnixFsNodeKind::Raw => "raw".into(),
UnixFsNodeKind::File => "file".into(),
UnixFsNodeKind::Dir => "dir".into(),
UnixFsNodeKind::Metadata => "metadata".into(),
UnixFsNodeKind::SymLink => "symlink".into(),
UnixFsNodeKind::HAMTShard => "hamt-shard".into(),
}
}
}

//--------------------------------------------------------------------------------------------------
// Tests
//--------------------------------------------------------------------------------------------------
Expand Down
34 changes: 34 additions & 0 deletions crates/wasm/fs/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use crate::fs::JsResult;
use crate::value;
use js_sys::{Object, Reflect};
use wasm_bindgen::JsValue;
use wnfs::{Metadata, UnixFsMetadata};

pub(crate) struct JsMetadata<'a>(pub(crate) &'a Metadata);

impl TryInto<JsValue> for JsMetadata<'_> {
type Error = js_sys::Error;

fn try_into(self) -> JsResult<JsValue> {
let metadata = Object::new();
let unix_meta = unix_fs_to_js_value(&self.0.unix_fs)?;
let version = value!(self.0.version.to_string());

Reflect::set(&metadata, &value!("unixMeta"), &unix_meta)?;
Reflect::set(&metadata, &value!("version"), &version)?;

Ok(value!(metadata))
}
}

fn unix_fs_to_js_value(unix_fs: &UnixFsMetadata) -> JsResult<JsValue> {
let obj = Object::new();
let kind = value!(String::from(&unix_fs.kind));

Reflect::set(&obj, &value!("created"), &value!(unix_fs.created))?;
Reflect::set(&obj, &value!("modified"), &value!(unix_fs.modified))?;
Reflect::set(&obj, &value!("mode"), &value!(unix_fs.mode.clone() as u32))?;
Reflect::set(&obj, &value!("kind"), &kind)?;

Ok(value!(obj))
}
1 change: 1 addition & 0 deletions crates/wasm/fs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod blockstore;
mod metadata;
mod public;
mod types;

Expand Down
59 changes: 54 additions & 5 deletions crates/wasm/fs/public/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use wnfs::{
OpResult as WnfsOpResult, PublicDirectory as WnfsPublicDirectory,
PublicNode as WnfsPublicNode,
},
Id,
BlockStore as WnfsBlockStore, Id,
};

use crate::fs::{BlockStore, ForeignBlockStore, JsResult, PublicNode};
Expand Down Expand Up @@ -86,6 +86,21 @@ impl PublicDirectory {
}))
}

/// Loads a directory given its CID from the block store.
pub fn load(cid: Uint8Array, store: BlockStore) -> JsResult<Promise> {
let store = ForeignBlockStore(store);
let cid = Cid::read_bytes(cid.to_vec().as_slice())
.map_err(|e| Error::new(&format!("Cannot parse cid: {e}")))?;
Ok(future_to_promise(async move {
let directory: WnfsPublicDirectory = store
.get_deserializable(&cid)
.await
.map_err(|e| Error::new(&format!("Couldn't deserialize directory: {e}")))?;

Ok(value!(PublicDirectory(Rc::new(directory))))
}))
}

/// Reads specified file content from the directory.
pub fn read(&self, path_segments: &Array, store: BlockStore) -> JsResult<Promise> {
let directory = Rc::clone(&self.0);
Expand All @@ -98,7 +113,9 @@ impl PublicDirectory {
.await
.map_err(|e| Error::new(&format!("Cannot read from directory: {e}")))?;

Ok(utils::create_op_result(root_dir, result.to_string())?)
let cid_u8array = Uint8Array::from(&result.to_bytes()[..]);

Ok(utils::create_op_result(root_dir, cid_u8array)?)
}))
}

Expand All @@ -116,7 +133,7 @@ impl PublicDirectory {

let result = result
.iter()
.map(|(name, _)| value!(name))
.flat_map(|(name, metadata)| utils::create_ls_entry(name, metadata))
.collect::<Array>();

Ok(utils::create_op_result(root_dir, result)?)
Expand Down Expand Up @@ -169,6 +186,7 @@ impl PublicDirectory {
}

/// Moves a specified path to a new location.
#[wasm_bindgen(js_name = "basicMv")]
pub fn basic_mv(
&self,
path_segments_from: &Array,
Expand Down Expand Up @@ -216,6 +234,24 @@ impl PublicDirectory {
}))
}

#[wasm_bindgen(js_name = "baseHistoryOn")]
pub fn base_history_on(&self, base: &PublicDirectory, store: BlockStore) -> JsResult<Promise> {
let directory = self.0.clone();
let base = base.0.clone();
let mut store = ForeignBlockStore(store);

Ok(future_to_promise(async move {
let WnfsOpResult { root_dir, .. } = directory
.base_history_on(base, &mut store)
.await
.map_err(|e| {
Error::new(&format!("Cannot do history rebase (base_history_on): {e}"))
})?;

Ok(utils::create_op_result(root_dir, JsValue::NULL)?)
}))
}

/// Converts directory to a node.
#[wasm_bindgen(js_name = "asNode")]
pub fn as_node(&self) -> PublicNode {
Expand All @@ -236,10 +272,10 @@ impl PublicDirectory {
mod utils {
use std::rc::Rc;

use crate::{fs::JsResult, value};
use crate::{fs::metadata::JsMetadata, fs::JsResult, value};
use js_sys::{Array, Error, Object, Reflect};
use wasm_bindgen::JsValue;
use wnfs::public::PublicDirectory as WnfsPublicDirectory;
use wnfs::{public::PublicDirectory as WnfsPublicDirectory, Metadata};

use super::PublicDirectory;

Expand Down Expand Up @@ -273,4 +309,17 @@ mod utils {

Ok(value!(op_result))
}

pub(crate) fn create_ls_entry(name: &String, metadata: &Metadata) -> JsResult<JsValue> {
let entry = Object::new();

Reflect::set(&entry, &value!("name"), &value!(name))?;
Reflect::set(
&entry,
&value!("metadata"),
&JsMetadata(metadata).try_into()?,
)?;

Ok(value!(entry))
}
}
7 changes: 4 additions & 3 deletions crates/wasm/tests/fs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ test.describe("PublicDirectory", () => {
});

expect(result.length).toBe(2);
expect(result.includes("dogs")).toBe(true);
expect(result.includes("cats")).toBe(true);
expect(result[0].name).toBe("cats");
expect(result[1].name).toBe("dogs");
});

test("rm can remove children from directory", async ({ page }) => {
Expand Down Expand Up @@ -137,6 +137,7 @@ test.describe("PublicDirectory", () => {
return result;
});

expect(result).toEqual(["dogs"]);
expect(result.length).toEqual(1)
expect(result[0].name).toEqual("dogs");
});
});
7 changes: 5 additions & 2 deletions scripts/rs-wnfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,11 @@ build_wasm() {
display_header "💿 | BUILDING WASM-WNFS PROJECT | 💿"
echo "script_dir = $script_dir"
cd $script_dir/../crates/wasm
wasm-pack build --target nodejs
sed -i ".bak" -e 's/"name": "wasm-wnfs"/"name": "wnfs"/g' pkg/package.json
wasm-pack build --target web
sed -i ".bak" \
-e 's/"name": "wasm-wnfs"/"name": "wnfs",\n "type": "module"/g' \
-e 's/"module": "wasm_wnfs\.js"/"module": "wasm_wnfs\.js",\n "main": "wasm_wnfs\.js"/g' \
pkg/package.json
rm pkg/package.json.bak
}

Expand Down

0 comments on commit 4837cba

Please sign in to comment.