futu_opend/startup/mod.rs
1//! v1.4.110 P1-2 + Layer 3 A: daemon startup orchestrator.
2//!
3//! 旧 `async fn main()` 体 ~1267 LoC, 拆出来后 main.rs < 100 LoC.
4//! 本 orchestrator 把完整 startup 顺序 (args → config → auth → bridge →
5//! handlers → push dispatcher → REST/MCP/WS surface server) 切成 4 个 phase 子文件:
6//!
7//! - `phase1.rs` — pre-runtime tz apply / keys-pre-validate / logging /
8//! panic hook / metrics / listen_addr 计算 / 端口冲突探测
9//! - `phase2.rs` — bridge 构造 / 7-tier 密码解析 / `--reset-device` /
10//! `--verify-code` / bridge.initialize / `--setup-only` 早退 /
11//! dev-flag injection
12//! - `phase3.rs` — ApiServer 构造 / handler 注册 / WebSocket+gRPC broadcaster /
13//! push dispatcher 启动
14//! - `phase4.rs` — WS / REST / gRPC / Telnet server spawn / card_num expand /
15//! SIGHUP unified handler / TCP fail-closed gate / 主 `tokio::select!` 循环
16//!
17//! orchestrator (`run_daemon`) 只做 4 个 phase 串行调用, 不含业务逻辑.
18
19mod phase1;
20mod phase2;
21mod phase3;
22mod phase4;
23
24use anyhow::Result;
25
26use crate::config::RuntimeConfig;
27
28/// Apply process-wide timezone config before constructing the Tokio runtime.
29///
30/// `std::env::set_var("TZ", ...)` is unsafe once other threads may read the
31/// environment. Production `main()` calls this after config merge and before
32/// `tokio::runtime::Builder::new_multi_thread()`.
33pub fn apply_pre_runtime_tz(config: &RuntimeConfig) {
34 phase1::apply_pre_runtime_tz(config);
35}
36
37/// 完整 daemon startup orchestrator. 调用方在 main() 里:
38/// ```ignore
39/// let config = merge_config(args)?;
40/// startup::apply_pre_runtime_tz(&config);
41/// startup::run_daemon(config, inject_auth_failure_every).await?
42/// ```
43pub async fn run_daemon(
44 config: RuntimeConfig,
45 inject_auth_failure_every: Option<u64>,
46) -> Result<()> {
47 let phase1 = phase1::run_phase1(&config).await?;
48 let phase2 =
49 phase2::run_phase2(&config, &phase1.listen_addr, inject_auth_failure_every).await?;
50 if phase2.setup_only_done {
51 // `--setup-only`: bridge.initialize Ok 已打印早退日志, 直接返回不启 server.
52 return Ok(());
53 }
54 let (shutdown_tx, shutdown_rx) = tokio::sync::watch::channel(false);
55 let phase3 = phase3::run_phase3(
56 &config,
57 &phase2.bridge,
58 &phase1.listen_addr,
59 phase2.push_receiver,
60 shutdown_tx.clone(),
61 );
62 phase4::run_phase4(
63 &config,
64 phase1,
65 phase2.bridge,
66 phase3,
67 shutdown_tx,
68 shutdown_rx,
69 )
70 .await
71}