feat: add ability to configure hs config with statictestnet (#104)

This commit is contained in:
Severin Alexander Bühler
2025-04-21 13:38:01 +03:00
committed by GitHub
parent f6f2ce6203
commit d4d44f7898
7 changed files with 84 additions and 37 deletions

14
Cargo.lock generated
View File

@@ -479,9 +479,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.30"
version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
dependencies = [
"clap_builder",
"clap_derive",
@@ -489,9 +489,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.30"
version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
dependencies = [
"anstream",
"anstyle",
@@ -501,9 +501,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.28"
version = "4.5.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
dependencies = [
"heck",
"proc-macro2",
@@ -2361,6 +2361,8 @@ name = "pubky-testnet"
version = "0.2.0-rc.1"
dependencies = [
"anyhow",
"clap",
"dirs",
"http-relay",
"mainline",
"pkarr",

View File

@@ -103,6 +103,7 @@ impl HomeserverCore {
/// - Creates the web server (router) for testing. Use `listen` to start the server.
pub async fn new(context: AppContext) -> std::result::Result<Self, HomeserverBuildError> {
let router = Self::create_router(&context);
let (icann_http_handle, icann_http_socket) =
Self::start_icann_http_server(&context, router.clone())
.await

View File

@@ -61,6 +61,18 @@ impl PersistentDataDir {
pub fn get_secret_file_path(&self) -> PathBuf {
self.expanded_path.join("secret")
}
/// Writes the keypair to the secret file.
/// If the file already exists, it will be overwritten.
pub fn write_keypair(&self, keypair: &pkarr::Keypair) -> anyhow::Result<()> {
let secret_file_path = self.get_secret_file_path();
let secret = keypair.secret_key();
let hex_string = hex::encode(secret);
std::fs::write(secret_file_path.clone(), hex_string)?;
std::fs::set_permissions(&secret_file_path, std::fs::Permissions::from_mode(0o600))?;
tracing::info!("Secret file created at {}", secret_file_path.display());
Ok(())
}
}
impl Default for PersistentDataDir {
@@ -107,12 +119,7 @@ impl DataDir for PersistentDataDir {
let secret_file_path = self.get_secret_file_path();
if !secret_file_path.exists() {
// Create a new secret file
let keypair = pkarr::Keypair::random();
let secret = keypair.secret_key();
let hex_string = hex::encode(secret);
std::fs::write(secret_file_path.clone(), hex_string)?;
std::fs::set_permissions(&secret_file_path, std::fs::Permissions::from_mode(0o600))?;
tracing::info!("Secret file created at {}", secret_file_path.display());
self.write_keypair(&pkarr::Keypair::random())?;
}
// Read the secret file
let secret = std::fs::read(secret_file_path)?;

View File

@@ -25,3 +25,5 @@ tempfile = "3.19.1"
tracing = "0.1.41"
pkarr = { workspace = true }
mainline = { workspace = true }
clap = "4.5.36"
dirs = "6.0.0"

View File

@@ -10,35 +10,35 @@ use crate::Testnet;
/// - An admin server for the homeserver.
pub struct EphemeralTestnet {
/// Inner flexible testnet.
pub flexible_testnet: Testnet,
pub testnet: Testnet,
}
impl EphemeralTestnet {
/// Run a new simple testnet.
pub async fn start() -> anyhow::Result<Self> {
let mut me = Self {
flexible_testnet: Testnet::new().await?,
testnet: Testnet::new().await?,
};
me.flexible_testnet.create_http_relay().await?;
me.flexible_testnet.create_homeserver_suite().await?;
me.testnet.create_http_relay().await?;
me.testnet.create_homeserver_suite().await?;
Ok(me)
}
/// Create a new pubky client builder.
pub fn pubky_client_builder(&self) -> pubky::ClientBuilder {
self.flexible_testnet.pubky_client_builder()
self.testnet.pubky_client_builder()
}
/// Create a new pkarr client builder.
pub fn pkarr_client_builder(&self) -> pkarr::ClientBuilder {
self.flexible_testnet.pkarr_client_builder()
self.testnet.pkarr_client_builder()
}
/// Get the homeserver in the testnet.
pub fn homeserver_suite(&self) -> &pubky_homeserver::HomeserverSuite {
self.flexible_testnet
self.testnet
.homeservers
.first()
.expect("homeservers should be non-empty")
@@ -46,7 +46,7 @@ impl EphemeralTestnet {
/// Get the http relay in the testnet.
pub fn http_relay(&self) -> &HttpRelay {
self.flexible_testnet
self.testnet
.http_relays
.first()
.expect("http relays should be non-empty")

View File

@@ -1,8 +1,20 @@
use std::path::PathBuf;
use anyhow::Result;
use clap::Parser;
use pubky_testnet::StaticTestnet;
#[derive(Parser, Debug)]
struct Cli {
/// Optional path to a homeserver config file. This overrides the default config.
#[clap(long)]
homeserver_config: Option<PathBuf>,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
tracing_subscriber::fmt()
.with_env_filter(
"pubky_homeserver=debug,http_relay=debug,pkarr_relay=info,tower_http=debug,pubky_testnet=debug"
@@ -10,7 +22,12 @@ async fn main() -> Result<()> {
)
.init();
let testnet = StaticTestnet::start().await?;
let testnet = if let Some(config_path) = args.homeserver_config {
StaticTestnet::start_with_homeserver_config(config_path).await?
} else {
StaticTestnet::start().await?
};
tracing::info!("Testnet running");
tracing::info!(
"DHT Bootstrap Nodes: {}",

View File

@@ -1,11 +1,12 @@
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
path::PathBuf,
str::FromStr,
};
use crate::Testnet;
use http_relay::HttpRelay;
use pubky_homeserver::{ConfigToml, DomainPort, HomeserverSuite, MockDataDir, SignupMode};
use pubky_homeserver::{ConfigToml, DomainPort, HomeserverSuite, MockDataDir};
/// A simple testnet with
///
@@ -16,7 +17,9 @@ use pubky_homeserver::{ConfigToml, DomainPort, HomeserverSuite, MockDataDir, Sig
/// - An admin server for the homeserver on port 6288.
pub struct StaticTestnet {
/// Inner flexible testnet.
pub flexible_testnet: Testnet,
pub testnet: Testnet,
/// Optional path to the homeserver config file if set.
pub homeserver_config: Option<PathBuf>,
#[allow(dead_code)]
fixed_bootstrap_node: Option<pkarr::mainline::Dht>, // Keep alive
#[allow(dead_code)]
@@ -24,16 +27,27 @@ pub struct StaticTestnet {
}
impl StaticTestnet {
/// Run a new simple testnet.
/// Run a new static testnet with the default homeserver config.
pub async fn start() -> anyhow::Result<Self> {
Self::new(None).await
}
/// Run a new static testnet with a custom homeserver config.
pub async fn start_with_homeserver_config(config_path: PathBuf) -> anyhow::Result<Self> {
Self::new(Some(config_path)).await
}
/// Run a new simple testnet.
pub async fn new(config_path: Option<PathBuf>) -> anyhow::Result<Self> {
let testnet = Testnet::new().await?;
let fixed_boostrap = Self::run_fixed_boostrap_node(&testnet.dht.bootstrap)
.map_err(|e| anyhow::anyhow!("Failed to run bootstrap node on port 6881: {}", e))?;
let mut testnet = Self {
flexible_testnet: testnet,
testnet,
fixed_bootstrap_node: fixed_boostrap,
temp_dirs: vec![],
homeserver_config: config_path,
};
testnet
@@ -54,16 +68,16 @@ impl StaticTestnet {
/// Create a new pubky client builder.
pub fn pubky_client_builder(&self) -> pubky::ClientBuilder {
self.flexible_testnet.pubky_client_builder()
self.testnet.pubky_client_builder()
}
pub fn pkarr_client_builder(&self) -> pkarr::ClientBuilder {
self.flexible_testnet.pkarr_client_builder()
self.testnet.pkarr_client_builder()
}
/// Get the homeserver in the testnet.
pub fn homeserver_suite(&self) -> &pubky_homeserver::HomeserverSuite {
self.flexible_testnet
self.testnet
.homeservers
.first()
.expect("homeservers should be non-empty")
@@ -71,7 +85,7 @@ impl StaticTestnet {
/// Get the http relay in the testnet.
pub fn http_relay(&self) -> &HttpRelay {
self.flexible_testnet
self.testnet
.http_relays
.first()
.expect("http relays should be non-empty")
@@ -79,7 +93,7 @@ impl StaticTestnet {
/// Get the pkarr relay in the testnet.
pub fn pkarr_relay(&self) -> &pkarr_relay::Relay {
self.flexible_testnet
self.testnet
.pkarr_relays
.first()
.expect("pkarr relays should be non-empty")
@@ -92,7 +106,7 @@ impl StaticTestnet {
nodes.push(dht.info().local_addr().to_string());
}
nodes.extend(
self.flexible_testnet
self.testnet
.dht_bootstrap_nodes()
.iter()
.map(|node| node.to_string()),
@@ -130,10 +144,10 @@ impl StaticTestnet {
.disable_rate_limiter()
.pkarr(|pkarr| {
pkarr.no_default_network();
pkarr.bootstrap(&self.flexible_testnet.dht.bootstrap)
pkarr.bootstrap(&self.testnet.dht.bootstrap)
});
let relay = unsafe { builder.run() }.await?;
self.flexible_testnet.pkarr_relays.push(relay);
self.testnet.pkarr_relays.push(relay);
self.temp_dirs.push(temp_dir);
Ok(())
}
@@ -144,20 +158,24 @@ impl StaticTestnet {
.http_port(15412) // Random available port
.run()
.await?;
self.flexible_testnet.http_relays.push(relay);
self.testnet.http_relays.push(relay);
Ok(())
}
async fn run_fixed_homeserver(&mut self) -> anyhow::Result<()> {
let mut config = if let Some(config_path) = &self.homeserver_config {
ConfigToml::from_file(config_path)?
} else {
ConfigToml::test()
};
let keypair = pkarr::Keypair::from_secret_key(&[0; 32]);
let mut config = ConfigToml::test();
config.pkdns.dht_bootstrap_nodes = Some(
self.bootstrap_nodes()
.iter()
.map(|node| DomainPort::from_str(node).unwrap())
.collect(),
);
config.general.signup_mode = SignupMode::Open;
config.pkdns.dht_relay_nodes = None;
config.drive.icann_listen_socket =
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 6286);
config.drive.pubky_listen_socket =
@@ -166,7 +184,7 @@ impl StaticTestnet {
let mock = MockDataDir::new(config, Some(keypair))?;
let homeserver = HomeserverSuite::start_with_mock_data_dir(mock).await?;
self.flexible_testnet.homeservers.push(homeserver);
self.testnet.homeservers.push(homeserver);
Ok(())
}
}