pubky_testnet/
static_testnet.rs1use crate::pubky::Pubky;
2
3use std::{
4 net::{IpAddr, Ipv4Addr, SocketAddr},
5 path::PathBuf,
6 str::FromStr,
7};
8
9use crate::Testnet;
10use http_relay::HttpRelay;
11use pubky_homeserver::{ConfigToml, DomainPort, HomeserverApp, MockDataDir};
12
13pub struct StaticTestnet {
21 pub testnet: Testnet,
23 pub homeserver_config: Option<PathBuf>,
25 #[allow(dead_code)]
26 fixed_bootstrap_node: Option<pkarr::mainline::Dht>, #[allow(dead_code)]
28 temp_dirs: Vec<tempfile::TempDir>, }
30
31impl StaticTestnet {
32 pub async fn start() -> anyhow::Result<Self> {
34 Self::new(None).await
35 }
36
37 pub async fn start_with_homeserver_config(config_path: PathBuf) -> anyhow::Result<Self> {
39 Self::new(Some(config_path)).await
40 }
41
42 pub async fn new(config_path: Option<PathBuf>) -> anyhow::Result<Self> {
44 let testnet = Testnet::new().await?;
45 let fixed_boostrap = Self::run_fixed_boostrap_node(&testnet.dht.bootstrap)
46 .map_err(|e| anyhow::anyhow!("Failed to run bootstrap node on port 6881: {}", e))?;
47
48 let mut testnet = Self {
49 testnet,
50 fixed_bootstrap_node: fixed_boostrap,
51 temp_dirs: vec![],
52 homeserver_config: config_path,
53 };
54
55 testnet
56 .run_fixed_pkarr_relays()
57 .await
58 .map_err(|e| anyhow::anyhow!("Failed to run pkarr relay on port 15411: {}", e))?;
59 testnet
60 .run_fixed_http_relay()
61 .await
62 .map_err(|e| anyhow::anyhow!("Failed to run http relay on port 15412: {}", e))?;
63 testnet
64 .run_fixed_homeserver()
65 .await
66 .map_err(|e| anyhow::anyhow!("Failed to run homeserver on port 6288: {}", e))?;
67
68 Ok(testnet)
69 }
70
71 pub async fn create_random_homeserver(
73 &mut self,
74 ) -> anyhow::Result<&pubky_homeserver::HomeserverApp> {
75 self.testnet.create_random_homeserver().await
76 }
77
78 pub fn client_builder(&self) -> pubky::PubkyHttpClientBuilder {
80 self.testnet.client_builder()
81 }
82
83 pub fn client(&self) -> Result<pubky::PubkyHttpClient, pubky::BuildError> {
85 self.testnet.client()
86 }
87
88 pub fn sdk(&self) -> Result<Pubky, pubky::BuildError> {
92 self.testnet.sdk()
93 }
94
95 pub fn pkarr_client_builder(&self) -> pkarr::ClientBuilder {
97 self.testnet.pkarr_client_builder()
98 }
99
100 pub fn homeserver_app(&self) -> &pubky_homeserver::HomeserverApp {
102 self.testnet
103 .homeservers
104 .first()
105 .expect("homeservers should be non-empty")
106 }
107
108 pub fn http_relay(&self) -> &HttpRelay {
110 self.testnet
111 .http_relays
112 .first()
113 .expect("http relays should be non-empty")
114 }
115
116 pub fn pkarr_relay(&self) -> &pkarr_relay::Relay {
118 self.testnet
119 .pkarr_relays
120 .first()
121 .expect("pkarr relays should be non-empty")
122 }
123
124 pub fn bootstrap_nodes(&self) -> Vec<String> {
126 let mut nodes = vec![];
127 if let Some(dht) = &self.fixed_bootstrap_node {
128 nodes.push(dht.info().local_addr().to_string());
129 }
130 nodes.extend(
131 self.testnet
132 .dht_bootstrap_nodes()
133 .iter()
134 .map(|node| node.to_string()),
135 );
136 nodes
137 }
138
139 fn run_fixed_boostrap_node(
142 other_bootstrap_nodes: &[String],
143 ) -> anyhow::Result<Option<pkarr::mainline::Dht>> {
144 if other_bootstrap_nodes
145 .iter()
146 .any(|node| node.contains("6881"))
147 {
148 return Ok(None);
149 }
150
151 let mut builder = pkarr::mainline::Dht::builder();
152 let dht = builder
153 .port(6881)
154 .bootstrap(other_bootstrap_nodes)
155 .server_mode()
156 .build()?;
157 Ok(Some(dht))
158 }
159
160 async fn run_fixed_pkarr_relays(&mut self) -> anyhow::Result<()> {
162 let temp_dir = tempfile::tempdir()?; let mut builder = pkarr_relay::Relay::builder();
164 builder
165 .http_port(15411)
166 .storage(temp_dir.path().to_path_buf())
167 .disable_rate_limiter()
168 .pkarr(|pkarr| {
169 pkarr.no_default_network();
170 pkarr.bootstrap(&self.testnet.dht.bootstrap)
171 });
172 let relay = unsafe { builder.run() }.await?;
173 self.testnet.pkarr_relays.push(relay);
174 self.temp_dirs.push(temp_dir);
175 Ok(())
176 }
177
178 async fn run_fixed_http_relay(&mut self) -> anyhow::Result<()> {
180 let relay = HttpRelay::builder()
181 .http_port(15412) .cors_allow_all(true)
183 .run()
184 .await?;
185 self.testnet.http_relays.push(relay);
186 Ok(())
187 }
188
189 async fn run_fixed_homeserver(&mut self) -> anyhow::Result<()> {
190 let mut config = if let Some(config_path) = &self.homeserver_config {
191 ConfigToml::from_file(config_path)?
192 } else {
193 ConfigToml::default_test_config()
194 };
195 let keypair = pubky_common::crypto::Keypair::from_secret(&[0; 32]);
196 config.pkdns.dht_bootstrap_nodes = Some(
197 self.bootstrap_nodes()
198 .iter()
199 .map(|node| DomainPort::from_str(node).unwrap())
200 .collect(),
201 );
202 config.pkdns.dht_relay_nodes = None;
203 config.drive.icann_listen_socket =
204 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 6286);
205 config.drive.pubky_listen_socket =
206 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 6287);
207 config.admin.enabled = true; config.admin.listen_socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 6288);
209 let mock = MockDataDir::new(config, Some(keypair))?;
210
211 let homeserver = HomeserverApp::start_with_mock_data_dir(mock).await?;
212 self.testnet.homeservers.push(homeserver);
213 Ok(())
214 }
215}