wip(js): migrate wasm bindings to support pubky in host

This commit is contained in:
nazeh
2024-11-26 19:14:00 +03:00
parent 6f64831ae7
commit b1bef6aa3e
15 changed files with 96 additions and 44 deletions

1
Cargo.lock generated
View File

@@ -1914,6 +1914,7 @@ dependencies = [
"bytes",
"cookie",
"cookie_store",
"futures-lite",
"js-sys",
"pkarr",
"pubky-common",

View File

@@ -31,7 +31,7 @@ tokio = { version = "1.37.0", features = ["full"] }
# Wasm dependencies
[target.'cfg(target_arch = "wasm32")'.dependencies]
reqwest = { version = "0.12.5", default-features = false }
futures-lite = { version = "2.5.0", default-features = false }
wasm-bindgen = "0.2.92"
wasm-bindgen-futures = "0.4.42"
@@ -43,8 +43,6 @@ anyhow = "1.0.93"
pubky-homeserver = { path = "../pubky-homeserver" }
tokio = "1.37.0"
[features]
[package.metadata.docs.rs]
all-features = true

View File

@@ -22,12 +22,14 @@ pub enum Error {
#[error(transparent)]
PublicKeyError(#[from] pkarr::errors::PublicKeyError),
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
PkarrPublishError(#[from] pkarr::errors::PublishError),
#[error(transparent)]
SignedPacketError(#[from] pkarr::errors::SignedPacketError),
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
PkarrClientWasShutdown(#[from] pkarr::errors::ClientWasShutdown),

View File

@@ -23,11 +23,13 @@ pub use crate::shared::list_builder::ListBuilder;
#[derive(Clone)]
#[wasm_bindgen]
pub struct Client {
#[cfg(not(target_arch = "wasm32"))]
pub(crate) cookie_store: Arc<native::CookieJar>,
http: reqwest::Client,
pkarr: pkarr::Client,
#[cfg(not(target_arch = "wasm32"))]
cookie_store: Arc<native::CookieJar>,
#[cfg(not(target_arch = "wasm32"))]
icann_http: reqwest::Client,
pub(crate) pkarr: pkarr::Client,
}
impl Debug for Client {

View File

@@ -7,6 +7,7 @@ use crate::Client;
mod api;
mod cookies;
mod http;
mod internal;
pub(crate) use cookies::CookieJar;

View File

@@ -0,0 +1,12 @@
//! Native specific implementation of methods used in the shared module
//!
use reqwest::{IntoUrl, Method, RequestBuilder};
use crate::Client;
impl Client {
pub(crate) async fn inner_request<T: IntoUrl>(&self, method: Method, url: T) -> RequestBuilder {
self.request(method, url)
}
}

View File

@@ -1,7 +1,7 @@
use std::collections::HashMap;
use base64::{alphabet::URL_SAFE, engine::general_purpose::NO_PAD, Engine};
use reqwest::StatusCode;
use reqwest::{Method, StatusCode};
use url::Url;
use pkarr::{Keypair, PublicKey};
@@ -28,7 +28,8 @@ impl Client {
homeserver: &PublicKey,
) -> Result<Session> {
let response = self
.post(format!("https://{}/signup", homeserver))
.inner_request(Method::POST, format!("https://{}/signup", homeserver))
.await
.body(AuthToken::sign(keypair, vec![Capability::root()]).serialize())
.send()
.await?
@@ -38,6 +39,7 @@ impl Client {
.await?;
// Store the cookie to the correct URL.
#[cfg(not(target_arch = "wasm32"))]
self.cookie_store
.store_session_after_signup(&response, &keypair.public_key());
@@ -52,7 +54,8 @@ impl Client {
/// if the response has any other `>=404` status code.
pub(crate) async fn inner_session(&self, pubky: &PublicKey) -> Result<Option<Session>> {
let res = self
.get(format!("pubky://{}/session", pubky))
.inner_request(Method::GET, format!("pubky://{}/session", pubky))
.await
.send()
.await?;
@@ -71,7 +74,8 @@ impl Client {
/// Signout from a homeserver.
pub(crate) async fn inner_signout(&self, pubky: &PublicKey) -> Result<()> {
self.delete(format!("pubky://{}/session", pubky))
self.inner_request(Method::DELETE, format!("pubky://{}/session", pubky))
.await
.send()
.await?
.error_for_status()?;
@@ -135,7 +139,8 @@ impl Client {
path_segments.push(&channel_id);
drop(path_segments);
self.post(callback)
self.inner_request(Method::POST, callback)
.await
.body(encrypted_token)
.send()
.await?
@@ -146,7 +151,8 @@ impl Client {
pub(crate) async fn signin_with_authtoken(&self, token: &AuthToken) -> Result<Session> {
let response = self
.post(format!("pubky://{}/session", token.pubky()))
.inner_request(Method::POST, format!("pubky://{}/session", token.pubky()))
.await
.body(token.serialize())
.send()
.await?

View File

@@ -90,7 +90,12 @@ impl<'a> ListBuilder<'a> {
drop(query);
let response = self.client.request(Method::GET, url).send().await?;
let response = self
.client
.inner_request(Method::GET, url)
.await
.send()
.await?;
response.error_for_status_ref()?;

View File

@@ -3,6 +3,7 @@ use wasm_bindgen::prelude::*;
use crate::Client;
mod api;
mod http;
mod internals;
mod wrappers;

View File

@@ -1,8 +1,11 @@
//! Wasm bindings for the Auth api
use url::Url;
use pubky_common::capabilities::Capabilities;
use crate::Client;
use crate::Error;
use crate::wasm::wrappers::keys::{Keypair, PublicKey};

View File

@@ -1,4 +1,3 @@
pub mod http;
pub mod recovery_file;
// TODO: put the Homeserver API behind a feature flag

View File

@@ -1,5 +1,9 @@
//! Wasm bindings for the /pub/ api
use wasm_bindgen::prelude::*;
use reqwest::{Method, StatusCode};
use js_sys::{Array, Uint8Array};
use crate::Client;
@@ -24,7 +28,11 @@ impl Client {
/// Delete a file at a path relative to a pubky author.
#[wasm_bindgen]
pub async fn delete(&self, url: &str) -> Result<(), JsValue> {
self.inner_delete(url).await.map_err(|e| e.into())
self.inner_request(Method::DELETE, url)
.await
.send()
.await
.map_err(|e| e.into())
}
/// Returns a list of Pubky urls (as strings).

View File

@@ -7,8 +7,6 @@ use reqwest::Url;
use crate::Client;
use super::super::internals::resolve;
#[wasm_bindgen]
impl Client {
#[wasm_bindgen]
@@ -21,10 +19,6 @@ impl Client {
JsValue::from_str(&format!("pubky::Client::fetch(): Invalid `url`; {:?}", err))
})?;
resolve(&self.pkarr, &mut url)
.await
.map_err(|err| JsValue::from_str(&format!("pubky::Client::fetch(): {:?}", err)))?;
let js_req =
web_sys::Request::new_with_str_and_init(url.as_str(), init).map_err(|err| {
JsValue::from_str(&format!(

View File

@@ -1,33 +1,53 @@
use reqwest::{Method, RequestBuilder};
//! Wasm specific implementation of methods used in the shared module
//!
use reqwest::{IntoUrl, Method, RequestBuilder};
use url::Url;
use futures_lite::{pin, Stream, StreamExt};
use pkarr::extra::endpoints::EndpointsResolver;
use pkarr::PublicKey;
use crate::{error::Result, Client};
// TODO: remove expect
pub async fn resolve(pkarr: &pkarr::Client, url: &mut Url) -> Result<()> {
let qname = url.host_str().expect("URL TO HAVE A HOST!").to_string();
// If http and has a Pubky TLD, switch to socket addresses.
if url.scheme() == "http" && PublicKey::try_from(qname.as_str()).is_ok() {
let endpoint = pkarr.resolve_endpoint(&qname).await?;
if let Some(socket_address) = endpoint.to_socket_addrs().into_iter().next() {
url.set_host(Some(&socket_address.to_string()))?;
let _ = url.set_port(Some(socket_address.port()));
} else if let Some(port) = endpoint.port() {
url.set_host(Some(endpoint.target()))?;
let _ = url.set_port(Some(port));
}
};
Ok(())
}
impl Client {
/// A wrapper around [reqwest::Client::request], with the same signature between native and wasm.
pub(crate) async fn inner_request(&self, method: Method, url: Url) -> RequestBuilder {
pub(crate) async fn inner_request<T: IntoUrl>(&self, method: Method, url: T) -> RequestBuilder {
let original_url = url.as_str();
let mut url = Url::parse(original_url).expect("Invalid url in inner_request");
if url.scheme() == "pubky" {
url.set_scheme("https");
}
if PublicKey::try_from(original_url).is_ok() {
let stream = self
.pkarr
.resolve_https_endpoints(url.host_str().unwrap_or(""));
let mut so_far = None;
while let Some(endpoint) = stream.next().await {
if let Some(e) = so_far {
if e.domain() == "." && endpoint.domain() != "." {
so_far = Some(endpoint);
}
} else {
so_far = Some(endpoint)
}
}
if let Some(e) = so_far {
url.set_host(Some(e.domain()));
url.set_port(Some(e.port()));
return self.http.request(method, url).fetch_credentials_include();
} else {
// TODO: didn't find any domain, what to do?
}
}
self.http.request(method, url).fetch_credentials_include()
}
}

View File

@@ -81,7 +81,7 @@ impl PublicKey {
.ok_or("Couldn't create a PublicKey from this type of value")?;
Ok(PublicKey(
pkarr::PublicKey::try_from(string).map_err(Error::Pkarr)?,
pkarr::PublicKey::try_from(string).map_err(Error::PublicKeyError)?,
))
}
}