pubky_homeserver/
homeserver_app.rs1use crate::admin_server::{AdminServer, AdminServerBuildError};
9use crate::client_server::{ClientServer, ClientServerBuildError};
10use crate::metrics_server::{MetricsServer, MetricsServerBuildError};
11use crate::republishers::{
12 HomeserverKeyRepublisher, KeyRepublisherBuildError, UserKeysRepublisher,
13};
14use crate::tracing::init_tracing_logs_with_config_if_set;
15#[cfg(any(test, feature = "testing"))]
16use crate::MockDataDir;
17use crate::{app_context::AppContext, data_directory::PersistentDataDir};
18use anyhow::Result;
19use pubky_common::crypto::PublicKey;
20use std::path::PathBuf;
21use std::time::Duration;
22
23const INITIAL_DELAY_BEFORE_REPUBLISH: Duration = Duration::from_secs(60);
24
25#[derive(thiserror::Error, Debug)]
27pub enum HomeserverAppBuildError {
28 #[error("Failed to build homeserver: {0}")]
30 Homeserver(ClientServerBuildError),
31 #[error("Failed to build admin server: {0}")]
33 Admin(AdminServerBuildError),
34 #[error("Failed to build metrics server: {0}")]
36 Metrics(MetricsServerBuildError),
37}
38
39pub struct HomeserverApp {
44 context: AppContext,
45
46 #[allow(dead_code)] client_server: ClientServer,
48
49 #[allow(dead_code)]
50 pub(crate) user_keys_republisher: UserKeysRepublisher,
52
53 #[allow(dead_code)]
54 pub(crate) key_republisher: HomeserverKeyRepublisher,
56
57 #[allow(dead_code)] admin_server: Option<AdminServer>,
59
60 #[allow(dead_code)] metrics_server: Option<MetricsServer>,
62}
63
64impl HomeserverApp {
65 pub async fn start_with_persistent_data_dir_path(dir_path: PathBuf) -> Result<Self> {
67 let data_dir = PersistentDataDir::new(dir_path);
68 let context = AppContext::read_from(data_dir).await?;
69 Self::start(context).await
70 }
71
72 pub async fn start_with_persistent_data_dir(dir: PersistentDataDir) -> Result<Self> {
74 let context = AppContext::read_from(dir).await?;
75 Self::start(context).await
76 }
77
78 #[cfg(any(test, feature = "testing"))]
80 pub async fn start_with_mock_data_dir(dir: MockDataDir) -> Result<Self> {
81 let context = AppContext::read_from(dir).await?;
82 Self::start(context).await
83 }
84
85 pub async fn start(context: AppContext) -> Result<Self> {
87 let _ = init_tracing_logs_with_config_if_set(&context.config_toml);
89
90 tracing::debug!("Homeserver data dir: {}", context.data_dir.path().display());
91
92 let user_keys_republisher =
93 UserKeysRepublisher::start_delayed(&context, INITIAL_DELAY_BEFORE_REPUBLISH);
94
95 let admin_server = if context.config_toml.admin.enabled {
96 Some(AdminServer::start(&context).await?)
97 } else {
98 None
99 };
100 let metrics_server = if context.config_toml.metrics.enabled {
101 Some(MetricsServer::start(&context).await?)
102 } else {
103 None
104 };
105 let client_server = ClientServer::start(context.clone()).await?;
106
107 let key_republisher = HomeserverKeyRepublisher::start(
108 &context,
109 client_server.icann_http_socket.port(),
110 client_server.pubky_tls_socket.port(),
111 )
112 .await
113 .map_err(KeyRepublisherBuildError::KeyRepublisher)?;
114
115 Ok(Self {
116 context,
117 client_server,
118 admin_server,
119 metrics_server,
120 user_keys_republisher,
121 key_republisher,
122 })
123 }
124
125 pub fn client_server(&self) -> &ClientServer {
127 &self.client_server
128 }
129
130 pub fn admin_server(&self) -> Option<&AdminServer> {
132 self.admin_server.as_ref()
133 }
134
135 pub fn metrics_server(&self) -> Option<&MetricsServer> {
137 self.metrics_server.as_ref()
138 }
139
140 pub fn public_key(&self) -> PublicKey {
142 self.context.keypair.public_key()
143 }
144
145 pub fn pubky_url(&self) -> url::Url {
147 url::Url::parse(&format!("https://{}", self.public_key().z32())).expect("valid url")
148 }
149
150 pub fn icann_http_url(&self) -> url::Url {
152 url::Url::parse(&self.client_server.icann_http_url_string()).expect("valid url")
153 }
154}