Skip to content

Commit

Permalink
feat: Now supports null for profile and string in JS np.publish(). Re…
Browse files Browse the repository at this point in the history
…lated to #4
  • Loading branch information
vemonet committed Mar 3, 2024
1 parent b9b3179 commit 63093e4
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 47 deletions.
3 changes: 2 additions & 1 deletion js/Cargo.toml
Expand Up @@ -18,10 +18,11 @@ crate-type = ["cdylib"]
nanopub = { version = "0.0.18", path = "../lib" }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
serde-wasm-bindgen = "0.6"
wasm-bindgen-derive = "0.2"
js-sys = "0.3"
console_error_panic_hook = "0.1"
serde = { version = "1.0" }
serde-wasm-bindgen = "0.6"

[dev-dependencies]
wasm-bindgen-test = "0.3"
12 changes: 3 additions & 9 deletions js/index.html
Expand Up @@ -63,6 +63,7 @@ <h1 class="text-xl font-semibold">Nanopublication dev</h1>
const orcid="https://orcid.org/0000-0000-0000-0000";

async function main() {
// WebAssembly binary needs to be initialized. In async functions you can use "await init();"
await init();

const rdfInput = document.getElementById('rdf-input');
Expand All @@ -72,26 +73,19 @@ <h1 class="text-xl font-semibold">Nanopublication dev</h1>
form.addEventListener('submit', async (event) => {
event.preventDefault();
const rdfStr = rdfInput.value
// WebAssembly binary needs to be initialized. In async functions you can use "await init();"
// const keypair = new KeyPair()
// console.log("KEYS", keypair.info())

// const checked = Nanopub.check(rdfStr);
// console.log("CHECKED", checked.info());

const profile = new NpProfile(privKey, orcid, "Your Name", "");
// const np = await Nanopub.publish(rdfStr, profile, "")
const np = await new Nanopub(rdfStr).publish(profile, "");
// const np = await new Nanopub(rdfStr).publish();

// console.log(np.get_rdf());
// await np.publish(profile, "");
rdfOutput.innerText = np.get_rdf();
console.log(profile)
console.log("Published Nanopub:", np.info());
rdfOutput.innerText = np.getRdf();

console.log(profile)
const np2 = await new Nanopub(rdfStr).publish(profile, "");
console.log("Published Nanopub:", np2.info());
// new Nanopub(rdfStr).publish(profile, "")
// .then(np => {
// rdfOutput.innerText = np.get_rdf();
Expand Down
2 changes: 2 additions & 0 deletions js/src/lib.rs
@@ -1,3 +1,5 @@
extern crate alloc;

use js_sys::Error;
// #![allow(clippy::unused_unit)]
use wasm_bindgen::prelude::*;
Expand Down
102 changes: 66 additions & 36 deletions js/src/nanopub.rs
@@ -1,24 +1,25 @@
use js_sys::{Promise, JSON};
use nanopub::{
constants::TEST_SERVER, get_np_server as get_server, profile::gen_keys, Nanopub, NpProfile,
constants::TEST_SERVER, get_np_server as get_server, profile::gen_keys, Nanopub as RsNanopub,
NpProfile as RsNpProfile,
};
use serde::Serialize;
use wasm_bindgen::prelude::*;
use wasm_bindgen_derive::TryFromJsValue;
use wasm_bindgen_futures::future_to_promise;

#[wasm_bindgen(js_name = Nanopub)]
#[wasm_bindgen]
#[derive(Clone)]
pub struct NanopubJs {
np: Nanopub,
pub struct Nanopub {
np: RsNanopub,
}

// Optional arguments: https://docs.rs/wasm-bindgen-derive/latest/wasm_bindgen_derive/#optional-arguments
// Maybe try https://rustwasm.github.io/wasm-bindgen/reference/arbitrary-data-with-serde.html
#[allow(unused_variables, clippy::inherent_to_string)]
#[wasm_bindgen(js_class = Nanopub)]
impl NanopubJs {
#[wasm_bindgen]
impl Nanopub {
#[wasm_bindgen(constructor)]
pub fn new(rdf: JsValue) -> Result<NanopubJs, JsValue> {
pub fn new(rdf: JsValue) -> Result<Nanopub, JsValue> {
let rdf_str = if rdf.is_string() {
rdf.as_string()
.ok_or_else(|| JsValue::from_str("RDF input must be a string"))?
Expand All @@ -28,57 +29,77 @@ impl NanopubJs {
.as_string()
.ok_or_else(|| JsValue::from_str("Failed to convert JSON-LD object to string"))?
};
Nanopub::new(&rdf_str)
RsNanopub::new(&rdf_str)
.map(|np| Self { np })
.map_err(|e| JsValue::from_str(&e.to_string()))
}

#[wasm_bindgen]
pub fn check(self) -> Result<NanopubJs, JsValue> {
pub fn check(self) -> Result<Nanopub, JsValue> {
self.np
.check()
.map(|np| Self { np })
.map_err(|e| JsValue::from_str(&e.to_string()))
}

#[wasm_bindgen]
pub fn sign(self, profile: &NpProfileJs) -> Result<NanopubJs, JsValue> {
pub fn sign(self, profile: &NpProfile) -> Result<Nanopub, JsValue> {
self.np
.sign(&profile.profile)
.map(|np| Self { np })
.map_err(|e| JsValue::from_str(&e.to_string()))
}

// TODO: optional args https://docs.rs/wasm-bindgen-derive/latest/wasm_bindgen_derive/#optional-arguments
#[wasm_bindgen]
pub fn publish(self, profile: &NpProfileJs, server_url: &str) -> Promise {
let profile = profile.profile.clone();
let server_url = if server_url.is_empty() {
TEST_SERVER
pub fn publish(self, profile: &OptionNpProfile, server_url: Option<String>) -> Promise {
// Handle null/undefined profile
let js_value: &JsValue = profile.as_ref();
let option_profile: Option<NpProfile> = if js_value.is_undefined() {
None
} else {
server_url
}
.to_string();
Some(
NpProfile::try_from(js_value)
.map_err(|e| JsValue::from_str(&e.to_string()))
.unwrap(),
)
};
let profile = if let Some(option_profile) = option_profile {
Some(option_profile.profile.clone())
} else {
None
};
let server_url = if let Some(server_url) = server_url {
Some(server_url)
} else {
None
};
// TODO: make shorter
future_to_promise(async move {
match self.np.publish(Some(&profile), Some(&server_url)).await {
Ok(np) => Ok(JsValue::from(NanopubJs { np })),
match self
.np
.publish(profile.as_ref(), server_url.as_deref())
.await
{
Ok(np) => Ok(JsValue::from(Nanopub { np })),
Err(e) => Err(JsValue::from_str(&format!(
"Error publishing the Nanopub: {e}"
))),
}
})
}

#[wasm_bindgen(static_method_of = NanopubJs)]
pub fn publish_intro(profile: &NpProfileJs, server_url: &str) -> Promise {
#[wasm_bindgen(static_method_of = Nanopub)]
pub fn publish_intro(profile: &NpProfile, server_url: String) -> Promise {
let profile = profile.profile.clone();
let server_url = if server_url.is_empty() {
TEST_SERVER
} else {
server_url
&server_url
}
.to_string();
future_to_promise(async move {
let np = match Nanopub::new_intro(&profile) {
let np = match RsNanopub::new_intro(&profile) {
Ok(np) => np,
Err(e) => {
return Err(JsValue::from_str(&format!(
Expand All @@ -87,14 +108,15 @@ impl NanopubJs {
}
};
match np.publish(Some(&profile), Some(&server_url)).await {
Ok(np) => Ok(JsValue::from(NanopubJs { np })),
Ok(np) => Ok(JsValue::from(Nanopub { np })),
Err(e) => Err(JsValue::from_str(&format!(
"Error publishing Nanopub Introduction: {e}"
))),
}
})
}

#[wasm_bindgen(js_name = getRdf)]
pub fn get_rdf(&self) -> Result<String, JsValue> {
self.np
.get_rdf()
Expand All @@ -116,25 +138,33 @@ impl NanopubJs {
}

/// Nanopub profile in JavaScript
#[wasm_bindgen(js_name = NpProfile)]
#[derive(Serialize)]
pub struct NpProfileJs {
profile: NpProfile,
#[derive(TryFromJsValue)]
#[wasm_bindgen]
#[derive(Clone, Serialize)]
pub struct NpProfile {
profile: RsNpProfile,
}

// Optional arguments: https://docs.rs/wasm-bindgen-derive/latest/wasm_bindgen_derive/#optional-arguments
// https://github.com/rustwasm/wasm-bindgen/issues/2370
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "NpProfile | undefined")]
pub type OptionNpProfile;
}
// pub struct NpProfileJs(NpProfile);

#[allow(clippy::inherent_to_string)]
#[wasm_bindgen(js_class = NpProfile)]
impl NpProfileJs {
#[wasm_bindgen]
impl NpProfile {
#[wasm_bindgen(constructor)]
pub fn new(
private_key: &str,
orcid_id: &str,
name: &str,
introduction_nanopub_uri: &str,
) -> Result<NpProfileJs, JsValue> {
NpProfile::new(private_key, orcid_id, name, Some(introduction_nanopub_uri))
.map(|profile: NpProfile| Self { profile })
) -> Result<NpProfile, JsValue> {
RsNpProfile::new(private_key, orcid_id, name, Some(introduction_nanopub_uri))
.map(|profile: RsNpProfile| Self { profile })
.map_err(|e| JsValue::from_str(&e.to_string()))
}
// TODO: create from profile.yml file
Expand Down Expand Up @@ -179,7 +209,7 @@ impl KeyPair {
}
}

// impl Into<JsValue> for NanopubJs {
// impl Into<JsValue> for Nanopub {
// fn into(self) -> JsValue {
// // JsValue::from_serde(&self).unwrap()
// self.to_js()
Expand Down
1 change: 1 addition & 0 deletions lib/docs/demo.html
Expand Up @@ -255,6 +255,7 @@ <h1 class="text-xl font-semibold">✍️ Nanopublication signing playground 🕹
rdfOutput.classList.remove("hidden");
});

// Display error in output editor with line and position
function displayError(err) {
oeditor.setValue(err);
document.getElementById('success-msg').classList.add('hidden');
Expand Down
10 changes: 9 additions & 1 deletion lib/src/nanopub.rs
Expand Up @@ -372,7 +372,11 @@ impl Nanopub {
};

let server_url = if let Some(server_url) = server_url {
server_url.to_string()
if server_url.is_empty() {
TEST_SERVER.to_string()
} else {
server_url.to_string()
}
} else {
// Use test server if None provided
println!(
Expand All @@ -381,6 +385,10 @@ impl Nanopub {
);
TEST_SERVER.to_string()
};
// let server_url = server_url.unwrap_or_else(|| {
// println!("No server URL provided, using the test server {}", TEST_SERVER);
// TEST_SERVER
// }).to_string();
let published = publish_np(&server_url, &self.get_rdf()?).await?;
if published {
if TEST_SERVER == server_url {
Expand Down

0 comments on commit 63093e4

Please sign in to comment.