this repo has no description
1use crate::state::AppState;
2use axum::{Json, extract::State, http::StatusCode, response::IntoResponse};
3use serde_json::json;
4use tracing::error;
5
6fn get_available_comms_channels() -> Vec<&'static str> {
7 let mut channels = vec!["email"];
8 if std::env::var("DISCORD_WEBHOOK_URL").is_ok() {
9 channels.push("discord");
10 }
11 if std::env::var("TELEGRAM_BOT_TOKEN").is_ok() {
12 channels.push("telegram");
13 }
14 if std::env::var("SIGNAL_CLI_PATH").is_ok() && std::env::var("SIGNAL_SENDER_NUMBER").is_ok() {
15 channels.push("signal");
16 }
17 channels
18}
19
20pub async fn robots_txt() -> impl IntoResponse {
21 (
22 StatusCode::OK,
23 [("content-type", "text/plain")],
24 "# Hello!\n\n# Crawling the public API is allowed\nUser-agent: *\nAllow: /\n",
25 )
26}
27pub fn is_self_hosted_did_web_enabled() -> bool {
28 std::env::var("ENABLE_SELF_HOSTED_DID_WEB")
29 .map(|v| v != "false" && v != "0")
30 .unwrap_or(true)
31}
32
33pub async fn describe_server() -> impl IntoResponse {
34 let pds_hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string());
35 let domains_str =
36 std::env::var("AVAILABLE_USER_DOMAINS").unwrap_or_else(|_| pds_hostname.clone());
37 let domains: Vec<&str> = domains_str.split(',').map(|s| s.trim()).collect();
38 let invite_code_required = std::env::var("INVITE_CODE_REQUIRED")
39 .map(|v| v == "true" || v == "1")
40 .unwrap_or(false);
41 let privacy_policy = std::env::var("PRIVACY_POLICY_URL").ok();
42 let terms_of_service = std::env::var("TERMS_OF_SERVICE_URL").ok();
43 let contact_email = std::env::var("CONTACT_EMAIL").ok();
44 let mut links = serde_json::Map::new();
45 if let Some(pp) = privacy_policy {
46 links.insert("privacyPolicy".to_string(), json!(pp));
47 }
48 if let Some(tos) = terms_of_service {
49 links.insert("termsOfService".to_string(), json!(tos));
50 }
51 let mut contact = serde_json::Map::new();
52 if let Some(email) = contact_email {
53 contact.insert("email".to_string(), json!(email));
54 }
55 Json(json!({
56 "availableUserDomains": domains,
57 "inviteCodeRequired": invite_code_required,
58 "did": format!("did:web:{}", pds_hostname),
59 "links": links,
60 "contact": contact,
61 "version": env!("CARGO_PKG_VERSION"),
62 "availableCommsChannels": get_available_comms_channels(),
63 "selfHostedDidWebEnabled": is_self_hosted_did_web_enabled()
64 }))
65}
66pub async fn health(State(state): State<AppState>) -> impl IntoResponse {
67 match sqlx::query!("SELECT 1 as one").fetch_one(&state.db).await {
68 Ok(_) => (StatusCode::OK, "OK"),
69 Err(e) => {
70 error!("Health check failed: {:?}", e);
71 (StatusCode::SERVICE_UNAVAILABLE, "Service Unavailable")
72 }
73 }
74}