atproto blogging
1//! Weaver App main binary.
2
3#[allow(unused)]
4use dioxus::prelude::*;
5#[cfg(target_arch = "wasm32")]
6use lol_alloc::{FreeListAllocator, LockedAllocator};
7#[cfg(feature = "server")]
8use std::sync::Arc;
9#[cfg(feature = "server")]
10use tower::Service;
11#[allow(unused)]
12use weaver_app::{App, CONFIG, SubdomainApp, SubdomainContext, fetch};
13#[cfg(target_arch = "wasm32")]
14#[global_allocator]
15static ALLOCATOR: LockedAllocator<FreeListAllocator> =
16 LockedAllocator::new(FreeListAllocator::new());
17
18fn main() {
19 // Set up better panic messages for wasm
20 #[cfg(target_arch = "wasm32")]
21 console_error_panic_hook::set_once();
22
23 // Set up tracing subscriber with both console output and log capture (wasm only)
24 // Must happen before dioxus::launch so dioxus skips its own init
25 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
26 {
27 use tracing::Level;
28 use tracing::subscriber::set_global_default;
29 use tracing_subscriber::Registry;
30 use tracing_subscriber::filter::EnvFilter;
31 use tracing_subscriber::layer::SubscriberExt;
32
33 let console_level = if cfg!(debug_assertions) {
34 Level::TRACE
35 } else {
36 Level::INFO
37 };
38
39 let wasm_layer = tracing_wasm::WASMLayer::new(
40 tracing_wasm::WASMLayerConfigBuilder::new()
41 .set_max_level(console_level)
42 .build(),
43 );
44
45 // Filter out noisy crates
46 // Use weaver_app=trace for detailed editor debugging
47 let filter = EnvFilter::new(
48 "debug,weaver_app=trace,loro_internal=warn,jacquard_identity=info,jacquard_common=info,iroh=info,reqwest=warn",
49 );
50
51 let reg = Registry::default()
52 .with(filter)
53 .with(wasm_layer)
54 .with(weaver_app::components::editor::LogCaptureLayer);
55
56 let _ = set_global_default(reg);
57 }
58
59 // Initialize telemetry (metrics + tracing) before server starts.
60 // Loki task is spawned inside dioxus::serve where tokio runtime exists.
61 // Wrapped in Arc<Mutex> so the FnMut closure can clone and take() on first call.
62 #[cfg(feature = "server")]
63 let loki_task = {
64 use weaver_common::telemetry::{self, TelemetryConfig};
65 let config = TelemetryConfig::from_env("weaver-app");
66 std::sync::Arc::new(std::sync::Mutex::new(telemetry::init_sync(config)))
67 };
68
69 #[cfg(feature = "server")]
70 std::panic::set_hook(Box::new(|panic_info| {
71 tracing::error!("PANIC: {:?}", panic_info);
72 }));
73
74 // Run `serve()` on the server only
75 #[cfg(feature = "server")]
76 dioxus::serve({
77 let loki_task = loki_task.clone();
78 move || {
79 let loki_task = loki_task.clone();
80 async move {
81 #[cfg(feature = "fullstack-server")]
82 use axum::middleware;
83 use axum::middleware::Next;
84 use axum::{
85 Router, body::Body, extract::Request, response::Response, routing::get,
86 };
87 use axum_extra::extract::Host;
88 use jacquard::oauth::{client::OAuthClient, session::ClientData};
89 use std::convert::Infallible;
90 use weaver_app::auth::AuthStore;
91 use weaver_app::blobcache::BlobCache;
92 use weaver_common::telemetry;
93
94 // Spawn the Loki background task now that we're in tokio runtime
95 if let Some(task) = loki_task.lock().unwrap().take() {
96 telemetry::spawn_loki_task(task);
97 }
98
99 #[cfg(not(feature = "fullstack-server"))]
100 let router = {
101 Router::new()
102 .merge(dioxus::server::router(App))
103 .layer(middleware::from_fn(telemetry::http_metrics))
104 .layer(tower_http::trace::TraceLayer::new_for_http())
105 };
106
107 #[cfg(feature = "fullstack-server")]
108 let router = {
109 let fetcher = Arc::new(fetch::Fetcher::new(OAuthClient::new(
110 AuthStore::new(),
111 ClientData::new_public(CONFIG.oauth.clone()),
112 )));
113
114 let blob_cache = Arc::new(BlobCache::new(fetcher.clone()));
115 axum::Router::new()
116 .route("/favicon.ico", get(weaver_app::favicon))
117 .route("/metrics", get(|| async { telemetry::render() }))
118 .serve_dioxus_application(ServeConfig::builder(), App)
119 // Host context resolution.
120 .layer(middleware::from_fn({
121 let fetcher = fetcher.clone();
122 move |req: Request, next: Next| {
123 let fetcher = fetcher.clone();
124 async move {
125 weaver_app::middleware::host_context_middleware(
126 req, next, fetcher,
127 )
128 .await
129 }
130 }
131 }))
132 // Insert fetcher and blob cache into extensions.
133 .layer(middleware::from_fn({
134 let blob_cache = blob_cache.clone();
135 let fetcher = fetcher.clone();
136 move |mut req: Request, next: Next| {
137 let blob_cache = blob_cache.clone();
138 let fetcher = fetcher.clone();
139 async move {
140 req.extensions_mut().insert(blob_cache);
141 req.extensions_mut().insert(fetcher);
142 Ok::<_, Infallible>(next.run(req).await)
143 }
144 }
145 }))
146 // HTTP metrics (request count, duration)
147 .layer(middleware::from_fn(telemetry::http_metrics))
148 .layer(tower_http::trace::TraceLayer::new_for_http())
149 };
150 Ok(router)
151 }
152 }
153 });
154
155 #[cfg(not(feature = "server"))]
156 dioxus::launch(App);
157}