pubky_testnet/
lib.rs

1#![doc = include_str!("../README.md")]
2//!
3
4#![deny(missing_docs)]
5#![deny(rustdoc::broken_intra_doc_links)]
6#![cfg_attr(any(), deny(clippy::unwrap_used))]
7
8use std::time::Duration;
9
10use anyhow::Result;
11use http_relay::HttpRelay;
12use pubky::{ClientBuilder, Keypair};
13use pubky_common::timestamp::Timestamp;
14use pubky_homeserver::Homeserver;
15use url::Url;
16
17/// A local test network for Pubky Core development.
18pub struct Testnet {
19    dht: mainline::Testnet,
20    relays: Vec<pkarr_relay::Relay>,
21}
22
23impl Testnet {
24    /// Run a new testnet.
25    pub async fn run() -> Result<Self> {
26        let dht = mainline::Testnet::new(3)?;
27
28        let mut testnet = Self {
29            dht,
30            relays: vec![],
31        };
32
33        testnet.run_pkarr_relay().await?;
34
35        Ok(testnet)
36    }
37
38    /// Create these components with hardcoded configurations:
39    ///
40    /// 1. A local DHT with bootstrapping nodes: `&["localhost:6881"]`
41    /// 3. A Pkarr Relay running on port [15411](pubky_common::constants::testnet_ports::PKARR_RELAY)
42    /// 2. A Homeserver with address is hardcoded to `8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo`
43    /// 4. An HTTP relay running on port [15412](pubky_common::constants::testnet_ports::HTTP_RELAY)
44    pub async fn run_with_hardcoded_configurations() -> Result<Self> {
45        let dht = mainline::Testnet::new(3)?;
46
47        dht.leak();
48
49        let storage = std::env::temp_dir().join(Timestamp::now().to_string());
50
51        let mut builder = pkarr_relay::Relay::builder();
52        builder
53            .http_port(15411)
54            .storage(storage.clone())
55            .disable_rate_limiter()
56            .pkarr(|pkarr| {
57                pkarr
58                    .request_timeout(Duration::from_millis(100))
59                    .bootstrap(&dht.bootstrap)
60                    .dht(|builder| {
61                        if !dht.bootstrap.first().unwrap().contains("6881") {
62                            builder.server_mode().port(6881);
63                        }
64
65                        builder
66                            .bootstrap(&dht.bootstrap)
67                            .request_timeout(Duration::from_millis(200))
68                    })
69            });
70        let relay = unsafe { builder.run() }.await?;
71
72        let mut builder = Homeserver::builder();
73        builder
74            .keypair(Keypair::from_secret_key(&[0; 32]))
75            .storage(storage)
76            .bootstrap(&dht.bootstrap)
77            .relays(&[relay.local_url()])
78            .domain("localhost")
79            .close_signups()
80            .admin_password("admin".to_string());
81        unsafe { builder.run().await }?;
82
83        HttpRelay::builder().http_port(15412).run().await?;
84
85        let testnet = Self {
86            dht,
87            relays: vec![relay],
88        };
89
90        Ok(testnet)
91    }
92
93    // === Getters ===
94
95    /// Returns a list of DHT bootstrapping nodes.
96    pub fn bootstrap(&self) -> &[String] {
97        &self.dht.bootstrap
98    }
99
100    /// Returns a list of pkarr relays.
101    pub fn relays(&self) -> Box<[Url]> {
102        self.relays.iter().map(|r| r.local_url()).collect()
103    }
104
105    // === Public Methods ===
106
107    /// Run a Pubky Homeserver
108    pub async fn run_homeserver(&self) -> Result<Homeserver> {
109        Homeserver::run_test(&self.dht.bootstrap).await
110    }
111
112    /// Run a Pubky Homeserver that requires signup tokens
113    pub async fn run_homeserver_with_signup_tokens(&self) -> Result<Homeserver> {
114        Homeserver::run_test_with_signup_tokens(&self.dht.bootstrap).await
115    }
116
117    /// Run an HTTP Relay
118    pub async fn run_http_relay(&self) -> Result<HttpRelay> {
119        HttpRelay::builder().run().await
120    }
121
122    /// Create a [ClientBuilder] and configure it to use this local test network.
123    pub fn client_builder(&self) -> ClientBuilder {
124        let bootstrap = self.bootstrap();
125        let relays = self.relays();
126
127        let mut builder = pubky::Client::builder();
128        builder.pkarr(|builder| {
129            builder
130                .bootstrap(bootstrap)
131                .relays(&relays)
132                .expect("testnet relays should be valid urls")
133        });
134
135        builder
136    }
137
138    /// Run a new Pkarr relay.
139    ///
140    /// You can access the list of relays at [Self::relays].
141    pub async fn run_pkarr_relay(&mut self) -> Result<Url> {
142        let relay = pkarr_relay::Relay::run_test(&self.dht).await?;
143
144        let url = relay.local_url();
145
146        self.relays.push(relay);
147
148        Ok(url)
149    }
150}