00000000: 2f2f 2120 5a43 4c41 5720 5361 6153 20e6 //! ZCLAW SaaS . 00000010: 9c8d e58a a1e5 85a5 e58f a30d 0a0d 0a75 ...............u 00000020: 7365 2061 7875 6d3a 3a65 7874 7261 6374 se axum::extract 00000030: 3a3a 5374 6174 653b 0d0a 7573 6520 746f ::State;..use to 00000040: 7765 725f 6874 7470 3a3a 7469 6d65 6f75 wer_http::timeou 00000050: 743a 3a54 696d 656f 7574 4c61 7965 723b t::TimeoutLayer; 00000060: 0d0a 7573 6520 7472 6163 696e 673a 3a69 ..use tracing::i 00000070: 6e66 6f3b 0d0a 7573 6520 7a63 6c61 775f nfo;..use zclaw_ 00000080: 7361 6173 3a3a 7b63 6f6e 6669 673a 3a53 saas::{config::S 00000090: 6161 5343 6f6e 6669 672c 2064 623a 3a69 aaSConfig, db::i 000000a0: 6e69 745f 6462 2c20 7374 6174 653a 3a41 nit_db, state::A 000000b0: 7070 5374 6174 657d 3b0d 0a75 7365 207a ppState};..use z 000000c0: 636c 6177 5f73 6161 733a 3a77 6f72 6b65 claw_saas::worke 000000d0: 7273 3a3a 576f 726b 6572 4469 7370 6174 rs::WorkerDispat 000000e0: 6368 6572 3b0d 0a75 7365 207a 636c 6177 cher;..use zclaw 000000f0: 5f73 6161 733a 3a77 6f72 6b65 7273 3a3a _saas::workers:: 00000100: 6c6f 675f 6f70 6572 6174 696f 6e3a 3a4c log_operation::L 00000110: 6f67 4f70 6572 6174 696f 6e57 6f72 6b65 ogOperationWorke 00000120: 723b 0d0a 7573 6520 7a63 6c61 775f 7361 r;..use zclaw_sa 00000130: 6173 3a3a 776f 726b 6572 733a 3a63 6c65 as::workers::cle 00000140: 616e 7570 5f72 6566 7265 7368 5f74 6f6b anup_refresh_tok 00000150: 656e 733a 3a43 6c65 616e 7570 5265 6672 ens::CleanupRefr 00000160: 6573 6854 6f6b 656e 7357 6f72 6b65 723b eshTokensWorker; 00000170: 0d0a 7573 6520 7a63 6c61 775f 7361 6173 ..use zclaw_saas 00000180: 3a3a 776f 726b 6572 733a 3a63 6c65 616e ::workers::clean 00000190: 7570 5f72 6174 655f 6c69 6d69 743a 3a43 up_rate_limit::C 000001a0: 6c65 616e 7570 5261 7465 4c69 6d69 7457 leanupRateLimitW 000001b0: 6f72 6b65 723b 0d0a 7573 6520 7a63 6c61 orker;..use zcla 000001c0: 775f 7361 6173 3a3a 776f 726b 6572 733a w_saas::workers: 000001d0: 3a72 6563 6f72 645f 7573 6167 653a 3a52 :record_usage::R 000001e0: 6563 6f72 6455 7361 6765 576f 726b 6572 ecordUsageWorker 000001f0: 3b0d 0a75 7365 207a 636c 6177 5f73 6161 ;..use zclaw_saa 00000200: 733a 3a77 6f72 6b65 7273 3a3a 7570 6461 s::workers::upda 00000210: 7465 5f6c 6173 745f 7573 6564 3a3a 5570 te_last_used::Up 00000220: 6461 7465 4c61 7374 5573 6564 576f 726b dateLastUsedWork 00000230: 6572 3b0d 0a0d 0a23 5b74 6f6b 696f 3a3a er;....#[tokio:: 00000240: 6d61 696e 5d0d 0a61 7379 6e63 2066 6e20 main]..async fn 00000250: 6d61 696e 2829 202d 3e20 616e 7968 6f77 main() -> anyhow 00000260: 3a3a 5265 7375 6c74 3c28 293e 207b 0d0a ::Result<()> {.. 00000270: 2020 2020 7472 6163 696e 675f 7375 6273 tracing_subs 00000280: 6372 6962 6572 3a3a 666d 7428 290d 0a20 criber::fmt().. 00000290: 2020 2020 2020 202e 7769 7468 5f65 6e76 .with_env 000002a0: 5f66 696c 7465 7228 0d0a 2020 2020 2020 _filter(.. 000002b0: 2020 2020 2020 7472 6163 696e 675f 7375 tracing_su 000002c0: 6273 6372 6962 6572 3a3a 456e 7646 696c bscriber::EnvFil 000002d0: 7465 723a 3a74 7279 5f66 726f 6d5f 6465 ter::try_from_de 000002e0: 6661 756c 745f 656e 7628 290d 0a20 2020 fault_env().. 000002f0: 2020 2020 2020 2020 2020 2020 202e 756e .un 00000300: 7772 6170 5f6f 725f 656c 7365 287c 5f7c wrap_or_else(|_| 00000310: 2022 7a63 6c61 775f 7361 6173 3d64 6562 "zclaw_saas=deb 00000320: 7567 2c74 6f77 6572 5f68 7474 703d 6465 ug,tower_http=de 00000330: 6275 6722 2e69 6e74 6f28 2929 2c0d 0a20 bug".into()),.. 00000340: 2020 2020 2020 2029 0d0a 2020 2020 2020 ).. 00000350: 2020 2e69 6e69 7428 293b 0d0a 0d0a 2020 .init();.... 00000360: 2020 6c65 7420 636f 6e66 6967 203d 2053 let config = S 00000370: 6161 5343 6f6e 6669 673a 3a6c 6f61 6428 aaSConfig::load( 00000380: 293f 3b0d 0a20 2020 2069 6e66 6f21 2822 )?;.. info!(" 00000390: 5361 6153 2063 6f6e 6669 6720 6c6f 6164 SaaS config load 000003a0: 6564 3a20 7b7d 3a7b 7d22 2c20 636f 6e66 ed: {}:{}", conf 000003b0: 6967 2e73 6572 7665 722e 686f 7374 2c20 ig.server.host, 000003c0: 636f 6e66 6967 2e73 6572 7665 722e 706f config.server.po 000003d0: 7274 293b 0d0a 0d0a 2020 2020 6c65 7420 rt);.... let 000003e0: 6462 203d 2069 6e69 745f 6462 2826 636f db = init_db(&co 000003f0: 6e66 6967 2e64 6174 6162 6173 652e 7572 nfig.database.ur 00000400: 6c29 2e61 7761 6974 3f3b 0d0a 2020 2020 l).await?;.. 00000410: 696e 666f 2128 2244 6174 6162 6173 6520 info!("Database 00000420: 696e 6974 6961 6c69 7a65 6422 293b 0d0a initialized");.. 00000430: 0d0a 2020 2020 2f2f 20e5 889d e5a7 8be5 .. // ....... 00000440: 8c96 2057 6f72 6b65 7220 e8b0 83e5 baa6 .. Worker ...... 00000450: e599 a820 2b20 e6b3 a8e5 868c e689 80e6 ... + .......... 00000460: 9c89 2057 6f72 6b65 720d 0a20 2020 206c .. Worker.. l 00000470: 6574 206d 7574 2064 6973 7061 7463 6865 et mut dispatche 00000480: 7220 3d20 576f 726b 6572 4469 7370 6174 r = WorkerDispat 00000490: 6368 6572 3a3a 6e65 7728 6462 2e63 6c6f cher::new(db.clo 000004a0: 6e65 2829 293b 0d0a 2020 2020 6469 7370 ne());.. disp 000004b0: 6174 6368 6572 2e72 6567 6973 7465 7228 atcher.register( 000004c0: 4c6f 674f 7065 7261 7469 6f6e 576f 726b LogOperationWork 000004d0: 6572 293b 0d0a 2020 2020 6469 7370 6174 er);.. dispat 000004e0: 6368 6572 2e72 6567 6973 7465 7228 436c cher.register(Cl 000004f0: 6561 6e75 7052 6566 7265 7368 546f 6b65 eanupRefreshToke 00000500: 6e73 576f 726b 6572 293b 0d0a 2020 2020 nsWorker);.. 00000510: 6469 7370 6174 6368 6572 2e72 6567 6973 dispatcher.regis 00000520: 7465 7228 436c 6561 6e75 7052 6174 654c ter(CleanupRateL 00000530: 696d 6974 576f 726b 6572 293b 0d0a 2020 imitWorker);.. 00000540: 2020 6469 7370 6174 6368 6572 2e72 6567 dispatcher.reg 00000550: 6973 7465 7228 5265 636f 7264 5573 6167 ister(RecordUsag 00000560: 6557 6f72 6b65 7229 3b0d 0a20 2020 2064 eWorker);.. d 00000570: 6973 7061 7463 6865 722e 7265 6769 7374 ispatcher.regist 00000580: 6572 2855 7064 6174 654c 6173 7455 7365 er(UpdateLastUse 00000590: 6457 6f72 6b65 7229 3b0d 0a20 2020 2069 dWorker);.. i 000005a0: 6e66 6f21 2822 576f 726b 6572 2064 6973 nfo!("Worker dis 000005b0: 7061 7463 6865 7220 696e 6974 6961 6c69 patcher initiali 000005c0: 7a65 6420 2835 2077 6f72 6b65 7273 2072 zed (5 workers r 000005d0: 6567 6973 7465 7265 6429 2229 3b0d 0a0d egistered)");... 000005e0: 0a20 2020 206c 6574 2073 7461 7465 203d . let state = 000005f0: 2041 7070 5374 6174 653a 3a6e 6577 2864 AppState::new(d 00000600: 622e 636c 6f6e 6528 292c 2063 6f6e 6669 b.clone(), confi 00000610: 672e 636c 6f6e 6528 292c 2064 6973 7061 g.clone(), dispa 00000620: 7463 6865 7229 3f3b 0d0a 0d0a 2020 2020 tcher)?;.... 00000630: 2f2f 20e5 90af e58a a8e5 a3b0 e698 8ee5 // ............. 00000640: bc8f 2053 6368 6564 756c 6572 efbc 88e4 .. Scheduler.... 00000650: bb8e 2054 4f4d 4c20 e985 8de7 bdae e8af .. TOML ........ 00000660: bbe5 8f96 e5ae 9ae6 97b6 e4bb bbe5 8aa1 ................ 00000670: efbc 890d 0a20 2020 206c 6574 2073 6368 ..... let sch 00000680: 6564 756c 6572 5f63 6f6e 6669 6720 3d20 eduler_config = 00000690: 2663 6f6e 6669 672e 7363 6865 6475 6c65 &config.schedule 000006a0: 723b 0d0a 2020 2020 7a63 6c61 775f 7361 r;.. zclaw_sa 000006b0: 6173 3a3a 7363 6865 6475 6c65 723a 3a73 as::scheduler::s 000006c0: 7461 7274 5f73 6368 6564 756c 6572 2873 tart_scheduler(s 000006d0: 6368 6564 756c 6572 5f63 6f6e 6669 672c cheduler_config, 000006e0: 2064 622e 636c 6f6e 6528 292c 2073 7461 db.clone(), sta 000006f0: 7465 2e77 6f72 6b65 725f 6469 7370 6174 te.worker_dispat 00000700: 6368 6572 2e63 6c6f 6e65 5f72 6566 2829 cher.clone_ref() 00000710: 293b 0d0a 2020 2020 696e 666f 2128 2253 );.. info!("S 00000720: 6368 6564 756c 6572 2073 7461 7274 6564 cheduler started 00000730: 2077 6974 6820 7b7d 206a 6f62 7322 2c20 with {} jobs", 00000740: 7363 6865 6475 6c65 725f 636f 6e66 6967 scheduler_config 00000750: 2e6a 6f62 732e 6c65 6e28 2929 3b0d 0a0d .jobs.len());... 00000760: 0a20 2020 202f 2f20 e590 afe5 8aa8 e586 . // ........ 00000770: 85e7 bdae 2044 4220 e6b8 85e7 9086 e4bb .... DB ........ 00000780: bbe5 8aa1 efbc 88e8 aebe e5a4 87e6 b885 ................ 00000790: e790 86e7 ad89 e4b8 8de9 809a e8bf 8720 ............... 000007a0: 576f 726b 6572 20e7 9a84 e4bb bbe5 8aa1 Worker ......... 000007b0: efbc 890d 0a20 2020 207a 636c 6177 5f73 ..... zclaw_s 000007c0: 6161 733a 3a73 6368 6564 756c 6572 3a3a aas::scheduler:: 000007d0: 7374 6172 745f 6462 5f63 6c65 616e 7570 start_db_cleanup 000007e0: 5f74 6173 6b73 2864 622e 636c 6f6e 6528 _tasks(db.clone( 000007f0: 2929 3b0d 0a0d 0a20 2020 202f 2f20 e590 ));.... // .. 00000800: afe5 8aa8 e586 85e5 ad98 e4b8 ade7 9a84 ................ 00000810: 2072 6174 6520 6c69 6d69 7420 e69d a1e7 rate limit .... 00000820: 9bae e6b8 85e7 9086 0d0a 2020 2020 6c65 .......... le 00000830: 7420 7261 7465 5f6c 696d 6974 5f73 7461 t rate_limit_sta 00000840: 7465 203d 2073 7461 7465 2e63 6c6f 6e65 te = state.clone 00000850: 2829 3b0d 0a20 2020 2074 6f6b 696f 3a3a ();.. tokio:: 00000860: 7370 6177 6e28 6173 796e 6320 6d6f 7665 spawn(async move 00000870: 207b 0d0a 2020 2020 2020 2020 6c65 7420 {.. let 00000880: 6d75 7420 696e 7465 7276 616c 203d 2074 mut interval = t 00000890: 6f6b 696f 3a3a 7469 6d65 3a3a 696e 7465 okio::time::inte 000008a0: 7276 616c 2873 7464 3a3a 7469 6d65 3a3a rval(std::time:: 000008b0: 4475 7261 7469 6f6e 3a3a 6672 6f6d 5f73 Duration::from_s 000008c0: 6563 7328 3330 3029 293b 0d0a 2020 2020 ecs(300));.. 000008d0: 2020 2020 6c6f 6f70 207b 0d0a 2020 2020 loop {.. 000008e0: 2020 2020 2020 2020 696e 7465 7276 616c interval 000008f0: 2e74 6963 6b28 292e 6177 6169 743b 0d0a .tick().await;.. 00000900: 2020 2020 2020 2020 2020 2020 7261 7465 rate 00000910: 5f6c 696d 6974 5f73 7461 7465 2e63 6c65 _limit_state.cle 00000920: 616e 7570 5f72 6174 655f 6c69 6d69 745f anup_rate_limit_ 00000930: 656e 7472 6965 7328 293b 0d0a 2020 2020 entries();.. 00000940: 2020 2020 7d0d 0a20 2020 207d 293b 0d0a }.. });.. 00000950: 0d0a 2020 2020 6c65 7420 6170 7020 3d20 .. let app = 00000960: 6275 696c 645f 726f 7574 6572 2873 7461 build_router(sta 00000970: 7465 292e 6177 6169 743b 0d0a 0d0a 2020 te).await;.... 00000980: 2020 6c65 7420 6c69 7374 656e 6572 203d let listener = 00000990: 2074 6f6b 696f 3a3a 6e65 743a 3a54 6370 tokio::net::Tcp 000009a0: 4c69 7374 656e 6572 3a3a 6269 6e64 2866 Listener::bind(f 000009b0: 6f72 6d61 7421 2822 7b7d 3a7b 7d22 2c20 ormat!("{}:{}", 000009c0: 636f 6e66 6967 2e73 6572 7665 722e 686f config.server.ho 000009d0: 7374 2c20 636f 6e66 6967 2e73 6572 7665 st, config.serve 000009e0: 722e 706f 7274 2929 0d0a 2020 2020 2020 r.port)).. 000009f0: 2020 2e61 7761 6974 3f3b 0d0a 2020 2020 .await?;.. 00000a00: 696e 666f 2128 2253 6161 5320 7365 7276 info!("SaaS serv 00000a10: 6572 206c 6973 7465 6e69 6e67 206f 6e20 er listening on 00000a20: 7b7d 3a7b 7d22 2c20 636f 6e66 6967 2e73 {}:{}", config.s 00000a30: 6572 7665 722e 686f 7374 2c20 636f 6e66 erver.host, conf 00000a40: 6967 2e73 6572 7665 722e 706f 7274 293b ig.server.port); 00000a50: 0d0a 0d0a 2020 2020 6178 756d 3a3a 7365 .... axum::se 00000a60: 7276 6528 6c69 7374 656e 6572 2c20 6170 rve(listener, ap 00000a70: 702e 696e 746f 5f6d 616b 655f 7365 7276 p.into_make_serv 00000a80: 6963 655f 7769 7468 5f63 6f6e 6e65 6374 ice_with_connect 00000a90: 5f69 6e66 6f3a 3a3c 7374 643a 3a6e 6574 _info::()) 00000ab0: 0d0a 2020 2020 2020 2020 2e77 6974 685f .. .with_ 00000ac0: 6772 6163 6566 756c 5f73 6875 7464 6f77 graceful_shutdow 00000ad0: 6e28 7368 7574 646f 776e 5f73 6967 6e61 n(shutdown_signa 00000ae0: 6c28 2929 0d0a 2020 2020 2020 2020 2e61 l()).. .a 00000af0: 7761 6974 3f3b 0d0a 2020 2020 4f6b 2828 wait?;.. Ok(( 00000b00: 2929 0d0a 7d0d 0a0d 0a61 7379 6e63 2066 ))..}....async f 00000b10: 6e20 6865 616c 7468 5f68 616e 646c 6572 n health_handler 00000b20: 2853 7461 7465 2873 7461 7465 293a 2053 (State(state): S 00000b30: 7461 7465 3c41 7070 5374 6174 653e 2920 tate) 00000b40: 2d3e 2061 7875 6d3a 3a4a 736f 6e3c 7365 -> axum::Json 00000b60: 207b 0d0a 2020 2020 2f2f 2068 6561 6c74 {.. // healt 00000b70: 6820 e5bf 85e9 a1bb e78b ace7 ab8b e5bf h .............. 00000b80: abe9 809f e8bf 94e5 9b9e efbc 8ce7 94a8 ................ 00000b90: 2033 7320 e8b6 85e6 97b6 e981 bfe5 858d 3s ............ 00000ba0: e8bf 9ee6 8ea5 e6b1 a0e6 bba1 e697 b6e9 ................ 00000bb0: 98bb e5a1 9e0d 0a20 2020 206c 6574 2064 ....... let d 00000bc0: 625f 6865 616c 7468 7920 3d20 746f 6b69 b_healthy = toki 00000bd0: 6f3a 3a74 696d 653a 3a74 696d 656f 7574 o::time::timeout 00000be0: 280d 0a20 2020 2020 2020 2073 7464 3a3a (.. std:: 00000bf0: 7469 6d65 3a3a 4475 7261 7469 6f6e 3a3a time::Duration:: 00000c00: 6672 6f6d 5f73 6563 7328 3329 2c0d 0a20 from_secs(3),.. 00000c10: 2020 2020 2020 2073 716c 783a 3a71 7565 sqlx::que 00000c20: 7279 5f73 6361 6c61 723a 3a3c 5f2c 2069 ry_scalar::<_, i 00000c30: 3332 3e28 2253 454c 4543 5420 3122 292e 32>("SELECT 1"). 00000c40: 6665 7463 685f 6f6e 6528 2673 7461 7465 fetch_one(&state 00000c50: 2e64 6229 2c0d 0a20 2020 2029 0d0a 2020 .db),.. ).. 00000c60: 2020 2e61 7761 6974 0d0a 2020 2020 2e6d .await.. .m 00000c70: 6170 287c 727c 2072 2e69 735f 6f6b 2829 ap(|r| r.is_ok() 00000c80: 290d 0a20 2020 202e 756e 7772 6170 5f6f ).. .unwrap_o 00000c90: 7228 6661 6c73 6529 3b0d 0a0d 0a20 2020 r(false);.... 00000ca0: 206c 6574 2073 7461 7475 7320 3d20 6966 let status = if 00000cb0: 2064 625f 6865 616c 7468 7920 7b20 2268 db_healthy { "h 00000cc0: 6561 6c74 6879 2220 7d20 656c 7365 207b ealthy" } else { 00000cd0: 2022 6465 6772 6164 6564 2220 7d3b 0d0a "degraded" };.. 00000ce0: 2020 2020 6c65 7420 5f63 6f64 6520 3d20 let _code = 00000cf0: 6966 2064 625f 6865 616c 7468 7920 7b20 if db_healthy { 00000d00: 3230 3020 7d20 656c 7365 207b 2035 3033 200 } else { 503 00000d10: 207d 3b0d 0a0d 0a20 2020 2061 7875 6d3a };.... axum: 00000d20: 3a4a 736f 6e28 7365 7264 655f 6a73 6f6e :Json(serde_json 00000d30: 3a3a 6a73 6f6e 2128 7b0d 0a20 2020 2020 ::json!({.. 00000d40: 2020 2022 7374 6174 7573 223a 2073 7461 "status": sta 00000d50: 7475 732c 0d0a 2020 2020 2020 2020 2264 tus,.. "d 00000d60: 6174 6162 6173 6522 3a20 6462 5f68 6561 atabase": db_hea 00000d70: 6c74 6879 2c0d 0a20 2020 2020 2020 2022 lthy,.. " 00000d80: 7469 6d65 7374 616d 7022 3a20 6368 726f timestamp": chro 00000d90: 6e6f 3a3a 5574 633a 3a6e 6f77 2829 2e74 no::Utc::now().t 00000da0: 6f5f 7266 6333 3333 3928 292c 0d0a 2020 o_rfc3339(),.. 00000db0: 2020 2020 2020 2276 6572 7369 6f6e 223a "version": 00000dc0: 2065 6e76 2128 2243 4152 474f 5f50 4b47 env!("CARGO_PKG 00000dd0: 5f56 4552 5349 4f4e 2229 2c0d 0a20 2020 _VERSION"),.. 00000de0: 207d 2929 0d0a 7d0d 0a0d 0a61 7379 6e63 }))..}....async 00000df0: 2066 6e20 6275 696c 645f 726f 7574 6572 fn build_router 00000e00: 2873 7461 7465 3a20 4170 7053 7461 7465 (state: AppState 00000e10: 2920 2d3e 2061 7875 6d3a 3a52 6f75 7465 ) -> axum::Route 00000e20: 7220 7b0d 0a20 2020 2075 7365 2061 7875 r {.. use axu 00000e30: 6d3a 3a6d 6964 646c 6577 6172 653b 0d0a m::middleware;.. 00000e40: 2020 2020 7573 6520 746f 7765 725f 6874 use tower_ht 00000e50: 7470 3a3a 636f 7273 3a3a 7b41 6e79 2c20 tp::cors::{Any, 00000e60: 436f 7273 4c61 7965 727d 3b0d 0a20 2020 CorsLayer};.. 00000e70: 2075 7365 2074 6f77 6572 5f68 7474 703a use tower_http: 00000e80: 3a74 7261 6365 3a3a 5472 6163 654c 6179 :trace::TraceLay 00000e90: 6572 3b0d 0a0d 0a20 2020 2075 7365 2061 er;.... use a 00000ea0: 7875 6d3a 3a68 7474 703a 3a48 6561 6465 xum::http::Heade 00000eb0: 7256 616c 7565 3b0d 0a20 2020 206c 6574 rValue;.. let 00000ec0: 2063 6f72 7320 3d20 7b0d 0a20 2020 2020 cors = {.. 00000ed0: 2020 206c 6574 2063 6f6e 6669 6720 3d20 let config = 00000ee0: 7374 6174 652e 636f 6e66 6967 2e72 6561 state.config.rea 00000ef0: 6428 292e 6177 6169 743b 0d0a 2020 2020 d().await;.. 00000f00: 2020 2020 6c65 7420 6973 5f64 6576 203d let is_dev = 00000f10: 2073 7464 3a3a 656e 763a 3a76 6172 2822 std::env::var(" 00000f20: 5a43 4c41 575f 5341 4153 5f44 4556 2229 ZCLAW_SAAS_DEV") 00000f30: 0d0a 2020 2020 2020 2020 2020 2020 2e6d .. .m 00000f40: 6170 287c 767c 2076 203d 3d20 2274 7275 ap(|v| v == "tru 00000f50: 6522 207c 7c20 7620 3d3d 2022 3122 290d e" || v == "1"). 00000f60: 0a20 2020 2020 2020 2020 2020 202e 756e . .un 00000f70: 7772 6170 5f6f 7228 6661 6c73 6529 3b0d wrap_or(false);. 00000f80: 0a20 2020 2020 2020 2069 6620 636f 6e66 . if conf 00000f90: 6967 2e73 6572 7665 722e 636f 7273 5f6f ig.server.cors_o 00000fa0: 7269 6769 6e73 2e69 735f 656d 7074 7928 rigins.is_empty( 00000fb0: 2920 7b0d 0a20 2020 2020 2020 2020 2020 ) {.. 00000fc0: 2069 6620 6973 5f64 6576 207b 0d0a 2020 if is_dev {.. 00000fd0: 2020 2020 2020 2020 2020 2020 2020 436f Co 00000fe0: 7273 4c61 7965 723a 3a6e 6577 2829 0d0a rsLayer::new().. 00000ff0: 2020 2020 2020 2020 2020 2020 2020 2020 00001000: 2020 2020 2e61 6c6c 6f77 5f6f 7269 6769 .allow_origi 00001010: 6e28 416e 7929 0d0a 2020 2020 2020 2020 n(Any).. 00001020: 2020 2020 2020 2020 2020 2020 2e61 6c6c .all 00001030: 6f77 5f6d 6574 686f 6473 2841 6e79 290d ow_methods(Any). 00001040: 0a20 2020 2020 2020 2020 2020 2020 2020 . 00001050: 2020 2020 202e 616c 6c6f 775f 6865 6164 .allow_head 00001060: 6572 7328 416e 7929 0d0a 2020 2020 2020 ers(Any).. 00001070: 2020 2020 2020 7d20 656c 7365 207b 0d0a } else {.. 00001080: 2020 2020 2020 2020 2020 2020 2020 2020 00001090: 7472 6163 696e 673a 3a65 7272 6f72 2128 tracing::error!( 000010a0: 22e7 949f e4ba a7e7 8eaf e5a2 83e5 bf85 "............... 000010b0: e9a1 bbe9 858d e7bd ae20 7365 7276 6572 ......... server 000010c0: 2e63 6f72 735f 6f72 6967 696e 73ef bc8c .cors_origins... 000010d0: e4b8 8de8 83bd e4bd bfe7 94a8 2061 6c6c ............ all 000010e0: 6f77 5f6f 7269 6769 6e28 416e 7929 2229 ow_origin(Any)") 000010f0: 3b0d 0a20 2020 2020 2020 2020 2020 2020 ;.. 00001100: 2020 2070 616e 6963 2128 22e7 949f e4ba panic!("..... 00001110: a7e7 8eaf e5a2 83e5 bf85 e9a1 bbe9 858d ................ 00001120: e7bd ae20 7365 7276 6572 2e63 6f72 735f ... server.cors_ 00001130: 6f72 6967 696e 7320 e799 bde5 908d e58d origins ........ 00001140: 95e3 8082 e5bc 80e5 8f91 e78e afe5 a283 ................ 00001150: e58f afe8 aebe e7bd ae20 5a43 4c41 575f ......... ZCLAW_ 00001160: 5341 4153 5f44 4556 3d74 7275 6520 e7bb SAAS_DEV=true .. 00001170: 95e8 bf87 e380 8222 293b 0d0a 2020 2020 .......");.. 00001180: 2020 2020 2020 2020 7d0d 0a20 2020 2020 }.. 00001190: 2020 207d 2065 6c73 6520 7b0d 0a20 2020 } else {.. 000011a0: 2020 2020 2020 2020 206c 6574 206f 7269 let ori 000011b0: 6769 6e73 3a20 5665 633c 4865 6164 6572 gins: Vec
= config. 000011d0: 7365 7276 6572 2e63 6f72 735f 6f72 6967 server.cors_orig 000011e0: 696e 732e 6974 6572 2829 0d0a 2020 2020 ins.iter().. 000011f0: 2020 2020 2020 2020 2020 2020 2e66 696c .fil 00001200: 7465 725f 6d61 7028 7c6f 3a20 2653 7472 ter_map(|o: &Str 00001210: 696e 677c 206f 2e70 6172 7365 3a3a 3c48 ing| o.parse::().ok 00001230: 2829 290d 0a20 2020 2020 2020 2020 2020 ()).. 00001240: 2020 2020 202e 636f 6c6c 6563 7428 293b .collect(); 00001250: 0d0a 2020 2020 2020 2020 2020 2020 436f .. Co 00001260: 7273 4c61 7965 723a 3a6e 6577 2829 0d0a rsLayer::new().. 00001270: 2020 2020 2020 2020 2020 2020 2020 2020 00001280: 2e61 6c6c 6f77 5f6f 7269 6769 6e28 6f72 .allow_origin(or 00001290: 6967 696e 7329 0d0a 2020 2020 2020 2020 igins).. 000012a0: 2020 2020 2020 2020 2e61 6c6c 6f77 5f6d .allow_m 000012b0: 6574 686f 6473 285b 0d0a 2020 2020 2020 ethods([.. 000012c0: 2020 2020 2020 2020 2020 2020 2020 6178 ax 000012d0: 756d 3a3a 6874 7470 3a3a 4d65 7468 6f64 um::http::Method 000012e0: 3a3a 4745 542c 0d0a 2020 2020 2020 2020 ::GET,.. 000012f0: 2020 2020 2020 2020 2020 2020 6178 756d axum 00001300: 3a3a 6874 7470 3a3a 4d65 7468 6f64 3a3a ::http::Method:: 00001310: 504f 5354 2c0d 0a20 2020 2020 2020 2020 POST,.. 00001320: 2020 2020 2020 2020 2020 2061 7875 6d3a axum: 00001330: 3a68 7474 703a 3a4d 6574 686f 643a 3a50 :http::Method::P 00001340: 5554 2c0d 0a20 2020 2020 2020 2020 2020 UT,.. 00001350: 2020 2020 2020 2020 2061 7875 6d3a 3a68 axum::h 00001360: 7474 703a 3a4d 6574 686f 643a 3a50 4154 ttp::Method::PAT 00001370: 4348 2c0d 0a20 2020 2020 2020 2020 2020 CH,.. 00001380: 2020 2020 2020 2020 2061 7875 6d3a 3a68 axum::h 00001390: 7474 703a 3a4d 6574 686f 643a 3a44 454c ttp::Method::DEL 000013a0: 4554 452c 0d0a 2020 2020 2020 2020 2020 ETE,.. 000013b0: 2020 2020 2020 2020 2020 6178 756d 3a3a axum:: 000013c0: 6874 7470 3a3a 4d65 7468 6f64 3a3a 4f50 http::Method::OP 000013d0: 5449 4f4e 532c 0d0a 2020 2020 2020 2020 TIONS,.. 000013e0: 2020 2020 2020 2020 5d29 0d0a 2020 2020 ]).. 000013f0: 2020 2020 2020 2020 2020 2020 2e61 6c6c .all 00001400: 6f77 5f68 6561 6465 7273 285b 0d0a 2020 ow_headers([.. 00001410: 2020 2020 2020 2020 2020 2020 2020 2020 00001420: 2020 6178 756d 3a3a 6874 7470 3a3a 6865 axum::http::he 00001430: 6164 6572 3a3a 4155 5448 4f52 495a 4154 ader::AUTHORIZAT 00001440: 494f 4e2c 0d0a 2020 2020 2020 2020 2020 ION,.. 00001450: 2020 2020 2020 2020 2020 6178 756d 3a3a axum:: 00001460: 6874 7470 3a3a 6865 6164 6572 3a3a 434f http::header::CO 00001470: 4e54 454e 545f 5459 5045 2c0d 0a20 2020 NTENT_TYPE,.. 00001480: 2020 2020 2020 2020 2020 2020 2020 2020 00001490: 2061 7875 6d3a 3a68 7474 703a 3a48 6561 axum::http::Hea 000014a0: 6465 724e 616d 653a 3a66 726f 6d5f 7374 derName::from_st 000014b0: 6174 6963 2822 782d 7265 7175 6573 742d atic("x-request- 000014c0: 6964 2229 2c0d 0a20 2020 2020 2020 2020 id"),.. 000014d0: 2020 2020 2020 205d 290d 0a20 2020 2020 ]).. 000014e0: 2020 207d 0d0a 2020 2020 7d3b 0d0a 0d0a }.. };.... 000014f0: 2020 2020 6c65 7420 7075 626c 6963 5f72 let public_r 00001500: 6f75 7465 7320 3d20 7a63 6c61 775f 7361 outes = zclaw_sa 00001510: 6173 3a3a 6175 7468 3a3a 726f 7574 6573 as::auth::routes 00001520: 2829 0d0a 2020 2020 2020 2020 2e72 6f75 ().. .rou 00001530: 7465 2822 2f61 7069 2f68 6561 6c74 6822 te("/api/health" 00001540: 2c20 6178 756d 3a3a 726f 7574 696e 673a , axum::routing: 00001550: 3a67 6574 2868 6561 6c74 685f 6861 6e64 :get(health_hand 00001560: 6c65 7229 290d 0a20 2020 2020 2020 202e ler)).. . 00001570: 6c61 7965 7228 6d69 6464 6c65 7761 7265 layer(middleware 00001580: 3a3a 6672 6f6d 5f66 6e5f 7769 7468 5f73 ::from_fn_with_s 00001590: 7461 7465 280d 0a20 2020 2020 2020 2020 tate(.. 000015a0: 2020 2073 7461 7465 2e63 6c6f 6e65 2829 state.clone() 000015b0: 2c0d 0a20 2020 2020 2020 2020 2020 207a ,.. z 000015c0: 636c 6177 5f73 6161 733a 3a6d 6964 646c claw_saas::middl 000015d0: 6577 6172 653a 3a70 7562 6c69 635f 7261 eware::public_ra 000015e0: 7465 5f6c 696d 6974 5f6d 6964 646c 6577 te_limit_middlew 000015f0: 6172 652c 0d0a 2020 2020 2020 2020 2929 are,.. )) 00001600: 3b0d 0a0d 0a20 2020 206c 6574 2070 726f ;.... let pro 00001610: 7465 6374 6564 5f72 6f75 7465 7320 3d20 tected_routes = 00001620: 7a63 6c61 775f 7361 6173 3a3a 6175 7468 zclaw_saas::auth 00001630: 3a3a 7072 6f74 6563 7465 645f 726f 7574 ::protected_rout 00001640: 6573 2829 0d0a 2020 2020 2020 2020 2e6d es().. .m 00001650: 6572 6765 287a 636c 6177 5f73 6161 733a erge(zclaw_saas: 00001660: 3a61 6363 6f75 6e74 3a3a 726f 7574 6573 :account::routes 00001670: 2829 290d 0a20 2020 2020 2020 202e 6d65 ()).. .me 00001680: 7267 6528 7a63 6c61 775f 7361 6173 3a3a rge(zclaw_saas:: 00001690: 6d6f 6465 6c5f 636f 6e66 6967 3a3a 726f model_config::ro 000016a0: 7574 6573 2829 290d 0a20 2020 2020 2020 utes()).. 000016b0: 202e 6d65 7267 6528 7a63 6c61 775f 7361 .merge(zclaw_sa 000016c0: 6173 3a3a 7265 6c61 793a 3a72 6f75 7465 as::relay::route 000016d0: 7328 2929 0d0a 2020 2020 2020 2020 2e6d s()).. .m 000016e0: 6572 6765 287a 636c 6177 5f73 6161 733a erge(zclaw_saas: 000016f0: 3a6d 6967 7261 7469 6f6e 3a3a 726f 7574 :migration::rout 00001700: 6573 2829 290d 0a20 2020 2020 2020 202e es()).. . 00001710: 6d65 7267 6528 7a63 6c61 775f 7361 6173 merge(zclaw_saas 00001720: 3a3a 726f 6c65 3a3a 726f 7574 6573 2829 ::role::routes() 00001730: 290d 0a20 2020 2020 2020 202e 6d65 7267 ).. .merg 00001740: 6528 7a63 6c61 775f 7361 6173 3a3a 7072 e(zclaw_saas::pr 00001750: 6f6d 7074 3a3a 726f 7574 6573 2829 290d ompt::routes()). 00001760: 0a20 2020 2020 2020 202e 6d65 7267 6528 . .merge( 00001770: 7a63 6c61 775f 7361 6173 3a3a 6167 656e zclaw_saas::agen 00001780: 745f 7465 6d70 6c61 7465 3a3a 726f 7574 t_template::rout 00001790: 6573 2829 290d 0a20 2020 2020 2020 202e es()).. . 000017a0: 6d65 7267 6528 7a63 6c61 775f 7361 6173 merge(zclaw_saas 000017b0: 3a3a 7465 6c65 6d65 7472 793a 3a72 6f75 ::telemetry::rou 000017c0: 7465 7328 2929 0d0a 2020 2020 2020 2020 tes()).. 000017d0: 2e6c 6179 6572 286d 6964 646c 6577 6172 .layer(middlewar 000017e0: 653a 3a66 726f 6d5f 666e 5f77 6974 685f e::from_fn_with_ 000017f0: 7374 6174 6528 0d0a 2020 2020 2020 2020 state(.. 00001800: 2020 2020 7374 6174 652e 636c 6f6e 6528 state.clone( 00001810: 292c 0d0a 2020 2020 2020 2020 2020 2020 ),.. 00001820: 7a63 6c61 775f 7361 6173 3a3a 6d69 6464 zclaw_saas::midd 00001830: 6c65 7761 7265 3a3a 6170 695f 7665 7273 leware::api_vers 00001840: 696f 6e5f 6d69 6464 6c65 7761 7265 2c0d ion_middleware,. 00001850: 0a20 2020 2020 2020 2029 290d 0a20 2020 . )).. 00001860: 2020 2020 202e 6c61 7965 7228 6d69 6464 .layer(midd 00001870: 6c65 7761 7265 3a3a 6672 6f6d 5f66 6e5f leware::from_fn_ 00001880: 7769 7468 5f73 7461 7465 280d 0a20 2020 with_state(.. 00001890: 2020 2020 2020 2020 2073 7461 7465 2e63 state.c 000018a0: 6c6f 6e65 2829 2c0d 0a20 2020 2020 2020 lone(),.. 000018b0: 2020 2020 207a 636c 6177 5f73 6161 733a zclaw_saas: 000018c0: 3a6d 6964 646c 6577 6172 653a 3a72 6571 :middleware::req 000018d0: 7565 7374 5f69 645f 6d69 6464 6c65 7761 uest_id_middlewa 000018e0: 7265 2c0d 0a20 2020 2020 2020 2029 290d re,.. )). 000018f0: 0a20 2020 2020 2020 202e 6c61 7965 7228 . .layer( 00001900: 6d69 6464 6c65 7761 7265 3a3a 6672 6f6d middleware::from 00001910: 5f66 6e5f 7769 7468 5f73 7461 7465 280d _fn_with_state(. 00001920: 0a20 2020 2020 2020 2020 2020 2073 7461 . sta 00001930: 7465 2e63 6c6f 6e65 2829 2c0d 0a20 2020 te.clone(),.. 00001940: 2020 2020 2020 2020 207a 636c 6177 5f73 zclaw_s 00001950: 6161 733a 3a6d 6964 646c 6577 6172 653a aas::middleware: 00001960: 3a72 6174 655f 6c69 6d69 745f 6d69 6464 :rate_limit_midd 00001970: 6c65 7761 7265 2c0d 0a20 2020 2020 2020 leware,.. 00001980: 2029 290d 0a20 2020 2020 2020 202e 6c61 )).. .la 00001990: 7965 7228 6d69 6464 6c65 7761 7265 3a3a yer(middleware:: 000019a0: 6672 6f6d 5f66 6e5f 7769 7468 5f73 7461 from_fn_with_sta 000019b0: 7465 280d 0a20 2020 2020 2020 2020 2020 te(.. 000019c0: 2073 7461 7465 2e63 6c6f 6e65 2829 2c0d state.clone(),. 000019d0: 0a20 2020 2020 2020 2020 2020 207a 636c . zcl 000019e0: 6177 5f73 6161 733a 3a61 7574 683a 3a61 aw_saas::auth::a 000019f0: 7574 685f 6d69 6464 6c65 7761 7265 2c0d uth_middleware,. 00001a00: 0a20 2020 2020 2020 2029 293b 0d0a 0d0a . ));.... 00001a10: 2020 2020 2f2f 20e9 9d9e e6b5 81e5 bc8f // ......... 00001a20: e8b7 afe7 94b1 e5ba 94e7 94a8 e585 a8e5 ................ 00001a30: b180 2031 3573 20e8 b685 e697 b6ef bc88 .. 15s ......... 00001a40: 7265 6c61 7920 5353 4520 e7ab afe7 82b9 relay SSE ...... 00001a50: e99c 80e8 a681 e69b b4e9 95bf e8b6 85e6 ................ 00001a60: 97b6 efbc 890d 0a20 2020 206c 6574 206e ....... let n 00001a70: 6f6e 5f73 7472 6561 6d69 6e67 5f72 6f75 on_streaming_rou 00001a80: 7465 7320 3d20 6178 756d 3a3a 526f 7574 tes = axum::Rout 00001a90: 6572 3a3a 6e65 7728 290d 0a20 2020 2020 er::new().. 00001aa0: 2020 202e 6d65 7267 6528 7075 626c 6963 .merge(public 00001ab0: 5f72 6f75 7465 7329 0d0a 2020 2020 2020 _routes).. 00001ac0: 2020 2e6d 6572 6765 2870 726f 7465 6374 .merge(protect 00001ad0: 6564 5f72 6f75 7465 7329 0d0a 2020 2020 ed_routes).. 00001ae0: 2020 2020 2e6c 6179 6572 2854 696d 656f .layer(Timeo 00001af0: 7574 4c61 7965 723a 3a6e 6577 2873 7464 utLayer::new(std 00001b00: 3a3a 7469 6d65 3a3a 4475 7261 7469 6f6e ::time::Duration 00001b10: 3a3a 6672 6f6d 5f73 6563 7328 3135 2929 ::from_secs(15)) 00001b20: 293b 0d0a 0d0a 2020 2020 6178 756d 3a3a );.... axum:: 00001b30: 526f 7574 6572 3a3a 6e65 7728 290d 0a20 Router::new().. 00001b40: 2020 2020 2020 202e 6d65 7267 6528 6e6f .merge(no 00001b50: 6e5f 7374 7265 616d 696e 675f 726f 7574 n_streaming_rout 00001b60: 6573 290d 0a20 2020 2020 2020 202e 6d65 es).. .me 00001b70: 7267 6528 7a63 6c61 775f 7361 6173 3a3a rge(zclaw_saas:: 00001b80: 7265 6c61 793a 3a72 6f75 7465 7328 2929 relay::routes()) 00001b90: 0d0a 2020 2020 2020 2020 2e6c 6179 6572 .. .layer 00001ba0: 2854 7261 6365 4c61 7965 723a 3a6e 6577 (TraceLayer::new 00001bb0: 5f66 6f72 5f68 7474 7028 2929 0d0a 2020 _for_http()).. 00001bc0: 2020 2020 2020 2e6c 6179 6572 2863 6f72 .layer(cor 00001bd0: 7329 0d0a 2020 2020 2020 2020 2e77 6974 s).. .wit 00001be0: 685f 7374 6174 6528 7374 6174 6529 0d0a h_state(state).. 00001bf0: 7d0d 0a0d 0a2f 2f2f 20e7 9b91 e590 ac20 }..../// ...... 00001c00: 4374 726c 2b43 20e4 bfa1 e58f b7ef bc8c Ctrl+C ......... 00001c10: e8a7 a6e5 8f91 2067 7261 6365 6675 6c20 ...... graceful 00001c20: 7368 7574 646f 776e 0d0a 6173 796e 6320 shutdown..async 00001c30: 666e 2073 6875 7464 6f77 6e5f 7369 676e fn shutdown_sign 00001c40: 616c 2829 207b 0d0a 2020 2020 746f 6b69 al() {.. toki 00001c50: 6f3a 3a73 6967 6e61 6c3a 3a63 7472 6c5f o::signal::ctrl_ 00001c60: 6328 290d 0a20 2020 2020 2020 202e 6177 c().. .aw 00001c70: 6169 740d 0a20 2020 2020 2020 202e 6578 ait.. .ex 00001c80: 7065 6374 2822 4661 696c 6564 2074 6f20 pect("Failed to 00001c90: 696e 7374 616c 6c20 4374 726c 2b43 2068 install Ctrl+C h 00001ca0: 616e 646c 6572 2229 3b0d 0a20 2020 2069 andler");.. i 00001cb0: 6e66 6f21 2822 5265 6365 6976 6564 2073 nfo!("Received s 00001cc0: 6875 7464 6f77 6e20 7369 676e 616c 2c20 hutdown signal, 00001cd0: 6472 6169 6e69 6e67 2063 6f6e 6e65 6374 draining connect 00001ce0: 696f 6e73 2e2e 2e22 293b 0d0a 7d0d 0a ions...");..}..