Skip to content

Commit

Permalink
refactor: Add wasm support (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
dariusc93 authored Apr 15, 2024
1 parent 10eb995 commit 57a6a2e
Show file tree
Hide file tree
Showing 22 changed files with 838 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- chore: Reenable websocket support and add support for secured websockets.
- feat: Implmenets webrtc transport and add a new feature. [PR 177](https://github.com/dariusc93/rust-ipfs/pull/177)
- refactor: Remove async-broadcast and stream clones. [PR 174](httops://github.com/dariusc93/rust-ipfs/pull/174)

This comment has been minimized.

Copy link
@rieval

rieval Apr 16, 2024

I noticed a small typo here:
httops -> https
😁

This comment has been minimized.

Copy link
@dariusc93

dariusc93 Apr 16, 2024

Author Owner

Thanks for the catch xD

- refactor: Add wasm support. [PR 178](httops://github.com/dariusc93/rust-ipfs/pull/178)

# 0.11.4
- fix: Send a wantlist of missing blocks.
Expand Down
66 changes: 66 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 40 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,45 @@ hickory-resolver = "0.24.0"
beetle-bitswap-next = { workspace = true, optional = true }
rcgen = "0.13.1"

[target.'cfg(target_arch = "wasm32")'.dependencies]
tokio-stream = { version = "0.1", default-features = false }
tokio-util = { version = "0.7", default-features = false }
tokio = { default-features = false, features = [
"sync",
"macros",
], version = "1" }
wasm-bindgen-futures = { version = "0.4" }
getrandom = { version = "0.2.14", features = ["js"] }
libp2p = { features = [
"gossipsub",
"autonat",
"relay",
"dcutr",
"identify",
"kad",
"websocket-websys",
"webtransport-websys",
"macros",
"noise",
"ping",
"yamux",
"dns",
"ed25519",
"secp256k1",
"ecdsa",
"serde",
"request-response",
"json",
"cbor",
"rendezvous",
"wasm-bindgen",
], workspace = true }

libp2p-webrtc-websys = "0.3.0-alpha"

serde-wasm-bindgen = "0.6"
idb = "0.6"

[dev-dependencies]
criterion = { default-features = false, version = "0.5" }
hex-literal = { default-features = false, version = "0.4" }
Expand All @@ -173,7 +212,7 @@ clap = { workspace = true }
debug = true

[workspace]
members = ["packages/*", "unixfs"]
members = ["packages/*", "unixfs", "examples/*"]
exclude = ["archived", "deprecated/*"]

resolver = "2"
19 changes: 19 additions & 0 deletions examples/wasm-example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "wasm-example"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
rust-ipfs = { path = "../.." }
futures = "0.3"
anyhow = "1.0.81"
wasm-bindgen = "0.2.90"
wasm-bindgen-futures = "0.4.42"
web-sys = { version = "0.3", features = ['Document', 'Element', 'HtmlElement', 'Node', 'Response', 'Window'] }
js-sys = "0.3.69"
libipld.workspace = true
Empty file added examples/wasm-example/README.md
Empty file.
94 changes: 94 additions & 0 deletions examples/wasm-example/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use libipld::ipld;
use rust_ipfs::UninitializedIpfsNoop as UninitializedIpfs;
use rust_ipfs::{Multiaddr, Protocol};
use wasm_bindgen::prelude::*;
use web_sys::{Document, HtmlElement};

#[wasm_bindgen]
pub async fn run() -> Result<(), JsError> {
let body = Body::from_current_window()?;
body.append_p("Ipfs block exchange test")?;

let node_a = UninitializedIpfs::new()
.with_default()
.add_listening_addr(Multiaddr::empty().with(Protocol::Memory(0)))
.start()
.await
.unwrap();
let node_b = UninitializedIpfs::new()
.with_default()
.add_listening_addr(Multiaddr::empty().with(Protocol::Memory(0)))
.start()
.await
.unwrap();

let peer_id = node_a.keypair().public().to_peer_id();
let peer_id_b = node_b.keypair().public().to_peer_id();

body.append_p(&format!("Our Node (A): {peer_id}"))?;
body.append_p(&format!("Our Node (B): {peer_id_b}"))?;

let addrs = node_a.listening_addresses().await.unwrap();

for addr in addrs {
node_b.add_peer(peer_id, addr).await.unwrap();
}

node_b.connect(peer_id).await.unwrap();

let block_a = ipld!({
"name": "alice",
"age": 99,
});

let cid = node_a.put_dag(block_a.clone()).await.unwrap();

let block_b = node_b.get_dag(cid).await.unwrap();

assert_eq!(block_b, block_a);

body.append_p(&format!("Block from node A: {block_b:?}"))?;

node_a.exit_daemon().await;
node_b.exit_daemon().await;
Ok(())
}

/// Borrowed from libp2p
struct Body {
body: HtmlElement,
document: Document,
}

impl Body {
fn from_current_window() -> Result<Self, JsError> {
// Use `web_sys`'s global `window` function to get a handle on the global
// window object.
let document = web_sys::window()
.ok_or(js_error("no global `window` exists"))?
.document()
.ok_or(js_error("should have a document on window"))?;
let body = document
.body()
.ok_or(js_error("document should have a body"))?;

Ok(Self { body, document })
}

fn append_p(&self, msg: &str) -> Result<(), JsError> {
let val = self
.document
.create_element("p")
.map_err(|_| js_error("failed to create <p>"))?;
val.set_text_content(Some(msg));
self.body
.append_child(&val)
.map_err(|_| js_error("failed to append <p>"))?;

Ok(())
}
}

fn js_error(msg: &str) -> JsError {
std::io::Error::new(std::io::ErrorKind::Other, msg).into()
}
9 changes: 9 additions & 0 deletions examples/wasm-example/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html>
<body>
<script type="module" defer>
import init, { run } from "./wasm_example.js"
await init();
run();
</script>
</body>
</html>
16 changes: 15 additions & 1 deletion src/ipns/dnslink.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::error::Error;
use crate::p2p::DnsResolver;
use crate::path::IpfsPath;
use std::str::FromStr;

use tracing_futures::Instrument;

#[cfg(not(target_arch = "wasm32"))]
pub async fn resolve<'a>(
resolver: DnsResolver,
domain: &str,
mut path: impl Iterator<Item = &'a str>,
) -> Result<IpfsPath, Error> {
use hickory_resolver::AsyncResolver;
use std::borrow::Cow;
use std::str::FromStr;

let span = tracing::trace_span!("dnslink", %domain);

Expand Down Expand Up @@ -84,6 +86,18 @@ pub async fn resolve<'a>(
.await
}

#[cfg(target_arch = "wasm32")]
pub async fn resolve<'a>(
_: DnsResolver,
domain: &str,
_: impl Iterator<Item = &'a str>,
) -> Result<IpfsPath, Error> {
let span = tracing::trace_span!("dnslink", %domain);
async move { anyhow::bail!("failed to resolve {domain}: unimplemented") }
.instrument(span)
.await
}

#[cfg(test)]
mod tests {
use super::resolve;
Expand Down
Loading

0 comments on commit 57a6a2e

Please sign in to comment.