| 61 | .content_type("text/event-stream") |
| 62 | .streaming(Box::pin(async_stream::stream! { |
| 63 | while let Some(line) = rx.recv().await { |
| 64 | yield Ok::<_, actix_web::Error>(web::Bytes::from(format!("{}\n", line))); |
| 65 | } |
| 66 | })) |
| 67 | } |
| 68 | |
| 69 | #[actix_web::main] |
| 70 | pub async fn init(tauri: AppHandle) -> std::io::Result<()> { |
| 71 | log::info!("Initializing API"); |
| 72 | |
| 73 | let app_data = web::Data::new(AppState { |
| 74 | tauri: tauri.clone(), |
| 75 | }); |
| 76 | |
| 77 | // Per-install TLS material, generated on first launch and rotated as it |
| 78 | // nears expiry. Nothing here ships inside the app bundle. |
| 79 | let local_tls = tls::ensure(&tauri).map_err(|e| { |
| 80 | log::error!("Failed to prepare local TLS material: {}", e); |
| 81 | std::io::Error::new(std::io::ErrorKind::Other, e) |
| 82 | })?; |
| 83 | |
| 84 | let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); |
| 85 | |
| 86 | builder |
| 87 | .set_private_key_file(&local_tls.key_path, SslFiletype::PEM) |
| 88 | .map_err(|e| { |
| 89 | log::error!("Failed to set private key file: {}", e); |
| 90 | std::io::Error::new(std::io::ErrorKind::Other, e) |
| 91 | })?; |
| 92 | log::debug!("Private key file set successfully"); |
| 93 | |
| 94 | builder |
| 95 | .set_certificate_chain_file(&local_tls.cert_path) |
| 96 | .map_err(|e| { |
| 97 | log::error!("Failed to set certificate chain file: {}", e); |
| 98 | std::io::Error::new(std::io::ErrorKind::Other, e) |
| 99 | })?; |
| 100 | log::debug!("Certificate chain file set successfully"); |
| 101 | |
| 102 | let http_server = HttpServer::new(move || { |
| 103 | let cors = Cors::default() |
| 104 | .allowed_origin_fn(|origin, _req_head| { |
| 105 | origin.to_str().map_or(false, |orig| { |
| 106 | debug!("Origin: {:?}", orig); |
| 107 | ["https://stack.lol", "https://exodus.stack.lol", "http://localhost:4321"].contains(&orig) |
| 108 | }) |
| 109 | }) |
| 110 | // .allow_any_origin() |
| 111 | .allow_any_method() |
| 112 | .allow_any_header() |
| 113 | .max_age(3600); |
| 114 | App::new() |
| 115 | .app_data(app_data.clone()) |
| 116 | .wrap(cors) |
| 117 | .service(index) |
| 118 | .service(health) |
| 119 | .service(run) |
| 120 | }) |