Built for people who think better out loud.
1use sqlx::PgPool;
2use tokio::net::TcpListener;
3use tower_http::cors::{AllowOrigin, CorsLayer};
4
5mod config;
6mod application;
7mod logging;
8mod domain;
9mod http;
10mod infrastructure;
11mod state;
12#[cfg(test)]
13mod test_support;
14
15use crate::{
16 config::Config,
17 logging::Logger,
18 infrastructure::{
19 oauth::build_oauth_dependencies,
20 whisper::WhisperClient,
21 },
22 state::AppState,
23};
24
25#[tokio::main]
26async fn main() {
27 let config = Config::from_env().expect("failed to load configuration");
28 let addr = config.bind_addr.clone();
29 let logger = Logger::from_config(&config).expect("failed to configure Axiom logger");
30 let whisper_client = WhisperClient::new(config.clone());
31 let db_pool = PgPool::connect(&config.database_url)
32 .await
33 .expect("failed to connect to Postgres");
34 let oauth_dependencies = build_oauth_dependencies(&config, db_pool.clone());
35 let app_state = AppState {
36 config,
37 whisper_client,
38 logger,
39 db_pool,
40 http_client: oauth_dependencies.http_client,
41 oauth_client_config: oauth_dependencies.oauth_client_config,
42 oauth_request_storage: oauth_dependencies.oauth_request_storage,
43 did_document_storage: oauth_dependencies.did_document_storage,
44 key_resolver: oauth_dependencies.key_resolver,
45 identity_resolver: oauth_dependencies.identity_resolver,
46 oauth_signing_key: oauth_dependencies.oauth_signing_key,
47 };
48 let app = if cfg!(debug_assertions) {
49 let allowed_origins = [
50 "http://localhost:4321",
51 "http://localhost:6007",
52 ]
53 .into_iter()
54 .filter_map(|origin| origin.parse().ok())
55 .collect::<Vec<_>>();
56 let allowed_headers = [
57 axum::http::header::ACCEPT,
58 axum::http::header::AUTHORIZATION,
59 axum::http::header::CONTENT_TYPE,
60 ];
61 let allowed_methods = [
62 axum::http::Method::GET,
63 axum::http::Method::POST,
64 axum::http::Method::OPTIONS,
65 ];
66 http::routers::router(app_state).layer(
67 CorsLayer::new()
68 .allow_origin(AllowOrigin::list(allowed_origins))
69 .allow_methods(allowed_methods)
70 .allow_headers(allowed_headers)
71 .allow_credentials(true),
72 )
73 } else {
74 http::routers::router(app_state)
75 };
76 let listener = TcpListener::bind(&addr)
77 .await
78 .expect("failed to bind to configured address");
79
80 println!("slipnote-backend listening on http://{addr}");
81
82 axum::serve(listener, app)
83 .await
84 .expect("axum server failed");
85}