From 6262bb75cdd91874dbefc76949c918c5a41bb40c Mon Sep 17 00:00:00 2001 From: nazeh Date: Sun, 15 Dec 2024 15:14:12 +0300 Subject: [PATCH] feat(homeserver,js): connect to testnet from js --- Cargo.lock | 5 +-- pubky-homeserver/src/core/config.rs | 4 +++ pubky-homeserver/src/io/mod.rs | 37 ++++++++++++++++++++-- pubky-homeserver/src/io/pkarr.rs | 4 +-- pubky/pkg/test/http.js | 1 - pubky/src/wasm.rs | 11 +++++-- pubky/src/wasm/http.rs | 2 ++ pubky/src/wasm/internals.rs | 48 +++++++++++++++++------------ 8 files changed, 81 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5095164..6ff0128 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1921,7 +1921,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkarr" version = "3.0.0" -source = "git+https://github.com/Pubky/pkarr?branch=v3#95f106e5a8a1d6275738aabf25c32c7cc7932a50" +source = "git+https://github.com/Pubky/pkarr?branch=v3#aac62e74f3ab5d94b1a52cd00ff355d8d50e29e1" dependencies = [ "base32", "byteorder", @@ -1952,13 +1952,14 @@ dependencies = [ "thiserror 2.0.6", "tokio", "tracing", + "url", "wasm-bindgen-futures", ] [[package]] name = "pkarr-relay" version = "0.1.0" -source = "git+https://github.com/Pubky/pkarr?branch=v3#95f106e5a8a1d6275738aabf25c32c7cc7932a50" +source = "git+https://github.com/Pubky/pkarr?branch=v3#aac62e74f3ab5d94b1a52cd00ff355d8d50e29e1" dependencies = [ "anyhow", "axum", diff --git a/pubky-homeserver/src/core/config.rs b/pubky-homeserver/src/core/config.rs index 1727b31..a9d344d 100644 --- a/pubky-homeserver/src/core/config.rs +++ b/pubky-homeserver/src/core/config.rs @@ -33,6 +33,8 @@ struct ConfigToml { /// Server configuration #[derive(Debug, Clone, PartialEq, Eq)] pub struct Config { + /// Run in [testnet](crate::Homeserver::start_testnet) mode. + pub testnet: bool, /// The configured port for this server. pub port: u16, /// Bootstrapping DHT nodes. @@ -99,6 +101,7 @@ impl Config { impl Default for Config { fn default() -> Self { Self { + testnet: false, port: 0, bootstrap: None, domain: None, @@ -138,6 +141,7 @@ impl TryFrom for Config { }; Ok(Config { + testnet: false, port: value.port.unwrap_or(0), bootstrap: value.bootstrap, domain: value.domain, diff --git a/pubky-homeserver/src/io/mod.rs b/pubky-homeserver/src/io/mod.rs index 1f9a46a..55725c1 100644 --- a/pubky-homeserver/src/io/mod.rs +++ b/pubky-homeserver/src/io/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use ::pkarr::{Keypair, PublicKey}; use anyhow::Result; use http::HttpServers; @@ -13,6 +15,12 @@ mod pkarr; pub struct HomeserverBuilder(Config); impl HomeserverBuilder { + pub fn testnet(mut self) -> Self { + self.0.testnet = true; + + self + } + /// Configure the Homeserver's keypair pub fn keypair(mut self, keypair: Keypair) -> Self { self.0.keypair = keypair; @@ -27,6 +35,13 @@ impl HomeserverBuilder { self } + /// Configure the storage path of the Homeserver + pub fn storage(mut self, storage: PathBuf) -> Self { + self.0.storage = storage; + + self + } + /// Start running a Homeserver /// /// # Safety @@ -68,7 +83,14 @@ impl Homeserver { info!("Publishing Pkarr packet.."); - let pkarr_server = PkarrServer::new(config, http_servers.https_address().await?.port())?; + let pkarr_server = PkarrServer::new( + &config, + if config.testnet { + http_servers.http_address().await?.port() + } else { + http_servers.https_address().await?.port() + }, + )?; pkarr_server.publish_server_packet().await?; info!("Homeserver listening on https://{}", core.public_key()); @@ -78,20 +100,27 @@ impl Homeserver { /// Start a homeserver in a Testnet mode. /// - /// - Homeserver address is hardcoded to `` + /// - Homeserver address is hardcoded to `8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo` /// - Run a pkarr Relay on port `15411` + /// - Use a temporary storage for the both homeserver and relay + /// - Only publish http port (ignore https port or domain configurations) /// /// # Safety /// See [Self::start] pub async unsafe fn start_testnet() -> Result { let testnet = ::pkarr::mainline::Testnet::new(10)?; + let storage = + std::env::temp_dir().join(pubky_common::timestamp::Timestamp::now().to_string()); + let relay = unsafe { let mut config = pkarr_relay::Config { http_port: 15411, + cache_path: Some(storage.join("pkarr-relay")), ..Default::default() }; config.pkarr_config.dht_config.bootstrap = testnet.bootstrap.clone(); + config.pkarr_config.resolvers = Some(vec![]); pkarr_relay::Relay::start(config).await? }; @@ -100,14 +129,16 @@ impl Homeserver { unsafe { Homeserver::builder() + .testnet() .keypair(Keypair::from_secret_key(&[0; 32])) .bootstrap(testnet.bootstrap) + .storage(storage.join("pubky-homeserver")) .build() .await } } - /// Test version of [Homeserver::start], using mainline Testnet, and a temporary storage. + /// Unit tests version of [Homeserver::start], using mainline Testnet, and a temporary storage. pub async fn start_test(testnet: &::pkarr::mainline::Testnet) -> Result { unsafe { Homeserver::start(Config::test(testnet)).await } } diff --git a/pubky-homeserver/src/io/pkarr.rs b/pubky-homeserver/src/io/pkarr.rs index fe46864..7a79273 100644 --- a/pubky-homeserver/src/io/pkarr.rs +++ b/pubky-homeserver/src/io/pkarr.rs @@ -11,7 +11,7 @@ pub struct PkarrServer { } impl PkarrServer { - pub fn new(config: Config, port: u16) -> Result { + pub fn new(config: &Config, port: u16) -> Result { let mut dht_config = pkarr::mainline::Config::default(); if let Some(bootstrap) = config.bootstrap.clone() { @@ -41,7 +41,7 @@ impl PkarrServer { } } -pub fn create_signed_packet(config: Config, port: u16) -> Result { +pub fn create_signed_packet(config: &Config, port: u16) -> Result { // TODO: Try to resolve first before publishing. let default = ".".to_string(); diff --git a/pubky/pkg/test/http.js b/pubky/pkg/test/http.js index 1edc295..16b04db 100644 --- a/pubky/pkg/test/http.js +++ b/pubky/pkg/test/http.js @@ -11,7 +11,6 @@ test.only("basic fetch", async (t) => { // Normal TLD { - let response = await client.fetch(`http://relay.pkarr.org/`); t.equal(response.status, 200); diff --git a/pubky/src/wasm.rs b/pubky/src/wasm.rs index c7abc9c..5c71155 100644 --- a/pubky/src/wasm.rs +++ b/pubky/src/wasm.rs @@ -13,7 +13,7 @@ impl Default for Client { } } -static TESTNET_RELAYS: [&str; 1] = ["http://localhost:15411/pkarr"]; +static TESTNET_RELAYS: [&str; 1] = ["http://localhost:15411/"]; #[wasm_bindgen] impl Client { @@ -27,13 +27,18 @@ impl Client { } /// Create a client with with configurations appropriate for local testing: - /// - set Pkarr relays to `["http://localhost:15411/pkarr"]` instead of default relay. + /// - set Pkarr relays to `["http://localhost:15411"]` instead of default relay. #[wasm_bindgen] pub fn testnet() -> Self { Self { http: reqwest::Client::builder().build().unwrap(), pkarr: pkarr::Client::builder() - .relays(TESTNET_RELAYS.into_iter().map(|s| s.to_string()).collect()) + .relays( + TESTNET_RELAYS + .into_iter() + .map(|s| url::Url::parse(s).expect("TESTNET_RELAYS should be valid urls")) + .collect(), + ) .build() .unwrap(), } diff --git a/pubky/src/wasm/http.rs b/pubky/src/wasm/http.rs index e1abdd8..3ea8790 100644 --- a/pubky/src/wasm/http.rs +++ b/pubky/src/wasm/http.rs @@ -19,6 +19,8 @@ impl Client { JsValue::from_str(&format!("pubky::Client::fetch(): Invalid `url`; {:?}", err)) })?; + self.transform_url(&mut url).await; + let js_req = web_sys::Request::new_with_str_and_init(url.as_str(), init).map_err(|err| { JsValue::from_str(&format!( diff --git a/pubky/src/wasm/internals.rs b/pubky/src/wasm/internals.rs index 272cab8..4fbdc5e 100644 --- a/pubky/src/wasm/internals.rs +++ b/pubky/src/wasm/internals.rs @@ -4,12 +4,12 @@ use reqwest::{IntoUrl, Method, RequestBuilder}; use url::Url; -use futures_lite::{pin, Stream, StreamExt}; +use futures_lite::StreamExt; -use pkarr::extra::endpoints::EndpointsResolver; +use pkarr::extra::endpoints::{Endpoint, EndpointsResolver}; use pkarr::PublicKey; -use crate::{error::Result, Client}; +use crate::Client; impl Client { /// A wrapper around [reqwest::Client::request], with the same signature between native and wasm. @@ -17,37 +17,45 @@ impl Client { let original_url = url.as_str(); let mut url = Url::parse(original_url).expect("Invalid url in inner_request"); + self.transform_url(&mut url).await; + + self.http.request(method, url).fetch_credentials_include() + } + + pub(super) async fn transform_url(&self, url: &mut Url) { if url.scheme() == "pubky" { - url.set_scheme("https"); + // TODO: use https for anything other than testnet + url.set_scheme("http") + .expect("couldn't replace pubky:// with http://"); + url.set_host(Some(&format!("_pubky.{}", url.host_str().unwrap_or("")))) + .expect("couldn't map pubk:// to https://_pubky."); } - if PublicKey::try_from(original_url).is_ok() { - let stream = self - .pkarr - .resolve_https_endpoints(url.host_str().unwrap_or("")); + let qname = url.host_str().unwrap_or("").to_string(); - let mut so_far = None; + if PublicKey::try_from(qname.to_string()).is_ok() { + let mut stream = self.pkarr.resolve_https_endpoints(&qname); - while let Some(endpoint) = stream.next().await { - if let Some(e) = so_far { - if e.domain() == "." && endpoint.domain() != "." { + let mut so_far: Option = None; + + // TODO: currently we return the first thing we can see, + // in the future we might want to failover to other endpoints + while so_far.is_none() { + while let Some(endpoint) = stream.next().await { + if 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(); + url.set_host(Some(e.domain())) + .expect("coultdn't use the resolved endpoint's domain"); + url.set_port(Some(e.port())) + .expect("coultdn't use the resolved endpoint's port"); } else { // TODO: didn't find any domain, what to do? } } - - self.http.request(method, url).fetch_credentials_include() } }