From 992607a7a7cc2e91d300ea2ce7f9ad7d3ab0471c Mon Sep 17 00:00:00 2001 From: nazeh Date: Tue, 17 Dec 2024 18:00:52 +0300 Subject: [PATCH] feat(homeserver): add http relay in homeserver testnet for js testing --- Cargo.lock | 6 ++- http-relay/cargo.toml | 1 + http-relay/src/lib.rs | 76 ++++++++++++++++++++++----------- pubky-homeserver/Cargo.toml | 1 + pubky-homeserver/src/io/http.rs | 22 +++++----- pubky-homeserver/src/io/mod.rs | 19 ++++++--- pubky/pkg/test/auth.js | 11 ++--- pubky/pkg/test/public.js | 14 +++--- pubky/src/shared/auth.rs | 4 +- 9 files changed, 98 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8096be..ce712da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1247,6 +1247,7 @@ dependencies = [ "axum-server", "futures-util", "tokio", + "tracing", "url", ] @@ -1944,7 +1945,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkarr" version = "3.0.0" -source = "git+https://github.com/Pubky/pkarr?branch=v3#aac62e74f3ab5d94b1a52cd00ff355d8d50e29e1" +source = "git+https://github.com/Pubky/pkarr?branch=v3#492639796bac0fedf42de7bbd3c069506b77fd19" dependencies = [ "base32", "byteorder", @@ -1982,7 +1983,7 @@ dependencies = [ [[package]] name = "pkarr-relay" version = "0.1.0" -source = "git+https://github.com/Pubky/pkarr?branch=v3#aac62e74f3ab5d94b1a52cd00ff355d8d50e29e1" +source = "git+https://github.com/Pubky/pkarr?branch=v3#492639796bac0fedf42de7bbd3c069506b77fd19" dependencies = [ "anyhow", "axum", @@ -2147,6 +2148,7 @@ dependencies = [ "futures-util", "heed 0.21.0", "hex", + "http-relay", "httpdate", "page_size", "pkarr", diff --git a/http-relay/cargo.toml b/http-relay/cargo.toml index 33035d1..2bca62c 100644 --- a/http-relay/cargo.toml +++ b/http-relay/cargo.toml @@ -9,4 +9,5 @@ axum = "0.7.9" axum-server = "0.7.1" futures-util = "0.3.31" tokio = { version = "1.42.0", features = ["full"] } +tracing = "0.1.41" url = "2.5.4" diff --git a/http-relay/src/lib.rs b/http-relay/src/lib.rs index e55e804..08e066d 100644 --- a/http-relay/src/lib.rs +++ b/http-relay/src/lib.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - net::SocketAddr, + net::{SocketAddr, TcpListener}, sync::{Arc, Mutex}, }; @@ -16,18 +16,45 @@ use axum::{ use axum_server::Handle; use tokio::sync::Notify; -use futures_util::stream::StreamExt; +use futures_util::{stream::StreamExt, TryFutureExt}; use url::Url; // Shared state to store GET requests and their notifications type SharedState = Arc, Arc)>>>; +#[derive(Debug, Default)] +pub struct Config { + pub http_port: u16, +} + +#[derive(Debug, Default)] +pub struct HttpRelayBuilder(Config); + +impl HttpRelayBuilder { + /// Configure the port used for HTTP server. + pub fn http_port(mut self, port: u16) -> Self { + self.0.http_port = port; + + self + } + + pub async fn build(self) -> Result { + HttpRelay::start(self.0).await + } +} + pub struct HttpRelay { pub(crate) http_handle: Handle, + + http_address: SocketAddr, } impl HttpRelay { - pub async fn start() -> Result { + pub fn builder() -> HttpRelayBuilder { + HttpRelayBuilder::default() + } + + pub async fn start(config: Config) -> Result { let shared_state: SharedState = Arc::new(Mutex::new(HashMap::new())); let app = Router::new() @@ -36,36 +63,35 @@ impl HttpRelay { let http_handle = Handle::new(); - let cloned = http_handle.clone(); - tokio::spawn(async { - axum_server::bind(SocketAddr::from(([127, 0, 0, 1], 0))) - .handle(cloned) - .serve(app.into_make_service()) - .await - .unwrap(); - }); + let http_listener = TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], config.http_port)))?; + let http_address = http_listener.local_addr()?; - Ok(Self { http_handle }) + tokio::spawn( + axum_server::from_tcp(http_listener) + .handle(http_handle.clone()) + .serve(app.into_make_service()) + .map_err(|error| tracing::error!(?error, "HttpRelay http server error")), + ); + + Ok(Self { + http_handle, + http_address, + }) } - pub async fn http_address(&self) -> Result { - match self.http_handle.listening().await { - Some(addr) => Ok(addr), - None => Err(anyhow::anyhow!("Failed to bind to http port")), - } + pub fn http_address(&self) -> SocketAddr { + self.http_address } /// Returns the localhost Url of this server. - pub async fn local_url(&self) -> Result { - match self.http_handle.listening().await { - Some(addr) => Ok(Url::parse(&format!("http://localhost:{}", addr.port()))?), - None => Err(anyhow::anyhow!("Failed to bind to http port")), - } + pub fn local_url(&self) -> Url { + Url::parse(&format!("http://localhost:{}", self.http_address.port())) + .expect("local_url should be formatted fine") } /// Returns the localhost URL of Link endpoints - pub async fn local_link_url(&self) -> Result { - let mut url = self.local_url().await?; + pub fn local_link_url(&self) -> Url { + let mut url = self.local_url(); let mut segments = url .path_segments_mut() @@ -75,7 +101,7 @@ impl HttpRelay { drop(segments); - Ok(url) + url } pub fn shutdown(&self) { diff --git a/pubky-homeserver/Cargo.toml b/pubky-homeserver/Cargo.toml index 333c3f9..de336dd 100644 --- a/pubky-homeserver/Cargo.toml +++ b/pubky-homeserver/Cargo.toml @@ -32,3 +32,4 @@ tower = "0.5.1" page_size = "0.6.0" pkarr-relay = { git = "https://github.com/Pubky/pkarr", branch = "v3", package = "pkarr-relay" } +http-relay = { version = "0.1.0", path = "../http-relay" } diff --git a/pubky-homeserver/src/io/http.rs b/pubky-homeserver/src/io/http.rs index 06176d1..65c0242 100644 --- a/pubky-homeserver/src/io/http.rs +++ b/pubky-homeserver/src/io/http.rs @@ -20,6 +20,9 @@ pub struct HttpServers { pub(crate) http_handle: Handle, /// Handle for the HTTPS server using Pkarr TLS pub(crate) https_handle: Handle, + + http_address: SocketAddr, + https_address: SocketAddr, } impl HttpServers { @@ -27,6 +30,7 @@ impl HttpServers { let http_listener = // TODO: add config to http port TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], 0)))?; + let http_address = http_listener.local_addr()?; let http_handle = Handle::new(); @@ -43,6 +47,7 @@ impl HttpServers { let https_listener = TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], core.config().port)))?; + let https_address = https_listener.local_addr()?; let https_handle = Handle::new(); @@ -63,21 +68,18 @@ impl HttpServers { Ok(Self { http_handle, https_handle, + + http_address, + https_address, }) } - pub async fn http_address(&self) -> Result { - match self.http_handle.listening().await { - Some(addr) => Ok(addr), - None => Err(anyhow::anyhow!("Failed to bind to http port")), - } + pub fn http_address(&self) -> SocketAddr { + self.http_address } - pub async fn https_address(&self) -> Result { - match self.https_handle.listening().await { - Some(addr) => Ok(addr), - None => Err(anyhow::anyhow!("Failed to bind to https port")), - } + pub fn https_address(&self) -> SocketAddr { + self.https_address } /// Shutdown all HTTP servers. diff --git a/pubky-homeserver/src/io/mod.rs b/pubky-homeserver/src/io/mod.rs index 55725c1..bf55a54 100644 --- a/pubky-homeserver/src/io/mod.rs +++ b/pubky-homeserver/src/io/mod.rs @@ -78,7 +78,7 @@ impl Homeserver { info!( "Homeserver listening on http://localhost:{}", - http_servers.http_address().await?.port() + http_servers.http_address().port() ); info!("Publishing Pkarr packet.."); @@ -86,9 +86,9 @@ impl Homeserver { let pkarr_server = PkarrServer::new( &config, if config.testnet { - http_servers.http_address().await?.port() + http_servers.http_address().port() } else { - http_servers.https_address().await?.port() + http_servers.https_address().port() }, )?; pkarr_server.publish_server_packet().await?; @@ -104,6 +104,7 @@ impl Homeserver { /// - 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) + /// - Run an HTTP relay on port `15412` /// /// # Safety /// See [Self::start] @@ -113,19 +114,27 @@ impl Homeserver { let storage = std::env::temp_dir().join(pubky_common::timestamp::Timestamp::now().to_string()); - let relay = unsafe { + let pkarr_relay = unsafe { let mut config = pkarr_relay::Config { http_port: 15411, cache_path: Some(storage.join("pkarr-relay")), + rate_limiter: None, ..Default::default() }; + config.pkarr_config.dht_config.bootstrap = testnet.bootstrap.clone(); config.pkarr_config.resolvers = Some(vec![]); pkarr_relay::Relay::start(config).await? }; - tracing::info!(relay_address=?relay.relay_address(), bootstrap=?relay.resolver_address(),"Running in Testnet mode"); + let http_relay = http_relay::HttpRelay::builder() + .http_port(15412) + .build() + .await?; + + tracing::info!(http_relay=?http_relay.local_link_url().as_str(), "Running http relay in Testnet mode"); + tracing::info!(relay_address=?pkarr_relay.relay_address(), bootstrap=?pkarr_relay.resolver_address(),"Running pkarr relay in Testnet mode"); unsafe { Homeserver::builder() diff --git a/pubky/pkg/test/auth.js b/pubky/pkg/test/auth.js index f93d012..e9961ca 100644 --- a/pubky/pkg/test/auth.js +++ b/pubky/pkg/test/auth.js @@ -2,7 +2,8 @@ import test from 'tape' import { Client, Keypair, PublicKey } from '../index.cjs' -const Homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo') +const HOMESERVER_PUBLICKEY = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo') +const TESTNET_HTTP_RELAY = "http://localhost:15412/link"; // TODO: test multiple users in wasm @@ -12,7 +13,7 @@ test('auth', async (t) => { const keypair = Keypair.random() const publicKey = keypair.publicKey() - await client.signup(keypair, Homeserver) + await client.signup(keypair, HOMESERVER_PUBLICKEY ) const session = await client.session(publicKey) t.ok(session, "signup") @@ -32,7 +33,7 @@ test('auth', async (t) => { } }) -test.skip("3rd party signin", async (t) => { +test("3rd party signin", async (t) => { let keypair = Keypair.random(); let pubky = keypair.publicKey().z32(); @@ -40,7 +41,7 @@ test.skip("3rd party signin", async (t) => { let capabilities = "/pub/pubky.app/:rw,/pub/foo.bar/file:r"; let client = Client.testnet(); let [pubkyauth_url, pubkyauthResponse] = client - .authRequest("https://demo.httprelay.io/link", capabilities); + .authRequest(TESTNET_HTTP_RELAY, capabilities); if (globalThis.document) { // Skip `sendAuthToken` in browser @@ -53,7 +54,7 @@ test.skip("3rd party signin", async (t) => { { let client = Client.testnet(); - await client.signup(keypair, Homeserver); + await client.signup(keypair, HOMESERVER_PUBLICKEY); await client.sendAuthToken(keypair, pubkyauth_url) } diff --git a/pubky/pkg/test/public.js b/pubky/pkg/test/public.js index 269ba00..a2cf823 100644 --- a/pubky/pkg/test/public.js +++ b/pubky/pkg/test/public.js @@ -2,14 +2,14 @@ import test from 'tape' import { Client, Keypair, PublicKey } from '../index.cjs' -const Homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo'); +const HOMESERVER_PUBLICKEY = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo') test.skip('public: put/get', async (t) => { const client = Client.testnet(); const keypair = Keypair.random(); - await client.signup(keypair, Homeserver); + await client.signup(keypair, HOMESERVER_PUBLICKEY); const publicKey = keypair.publicKey(); @@ -47,7 +47,7 @@ test.skip("not found", async (t) => { const keypair = Keypair.random(); - await client.signup(keypair, Homeserver); + await client.signup(keypair, HOMESERVER_PUBLICKEY); const publicKey = keypair.publicKey(); @@ -64,7 +64,7 @@ test.skip("unauthorized", async (t) => { const keypair = Keypair.random() const publicKey = keypair.publicKey() - await client.signup(keypair, Homeserver) + await client.signup(keypair, HOMESERVER_PUBLICKEY) const session = await client.session(publicKey) t.ok(session, "signup") @@ -91,7 +91,7 @@ test.skip("forbidden", async (t) => { const keypair = Keypair.random() const publicKey = keypair.publicKey() - await client.signup(keypair, Homeserver) + await client.signup(keypair, HOMESERVER_PUBLICKEY) const session = await client.session(publicKey) t.ok(session, "signup") @@ -117,7 +117,7 @@ test.skip("list", async (t) => { const publicKey = keypair.publicKey() const pubky = publicKey.z32() - await client.signup(keypair, Homeserver) + await client.signup(keypair, HOMESERVER_PUBLICKEY) @@ -248,7 +248,7 @@ test.skip('list shallow', async (t) => { const publicKey = keypair.publicKey() const pubky = publicKey.z32() - await client.signup(keypair, Homeserver) + await client.signup(keypair, HOMESERVER_PUBLICKEY) let urls = [ `pubky://${pubky}/pub/a.com/a.txt`, diff --git a/pubky/src/shared/auth.rs b/pubky/src/shared/auth.rs index 9bfee23..52e8a1b 100644 --- a/pubky/src/shared/auth.rs +++ b/pubky/src/shared/auth.rs @@ -271,8 +271,8 @@ mod tests { let testnet = Testnet::new(10).unwrap(); let server = Homeserver::start_test(&testnet).await.unwrap(); - let http_relay = HttpRelay::start().await.unwrap(); - let http_relay_url = http_relay.local_link_url().await.unwrap(); + let http_relay = HttpRelay::builder().build().await.unwrap(); + let http_relay_url = http_relay.local_link_url(); let keypair = Keypair::random(); let pubky = keypair.public_key();