at main 157 lines 6.4 kB view raw
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}