tdm_server_rust/server/
mod.rs1use crate::config::ServerConfig;
20use anyhow::{Context, Result};
21use axum::Router;
22use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, SanType};
23use std::fs;
24use std::net::SocketAddr;
25use std::path::{Path, PathBuf};
26
27fn resolve_tls_path(config_dir: &Path, relative: &str) -> PathBuf {
31 let path = PathBuf::from(relative);
32 if path.is_absolute() {
33 path
34 } else {
35 config_dir.join(path)
36 }
37}
38
39fn ensure_dev_tls_pem(cert_path: &Path, key_path: &Path) -> Result<()> {
48 if cert_path.is_file() && key_path.is_file() {
49 return Ok(());
50 }
51 if let Some(parent) = cert_path.parent() {
52 fs::create_dir_all(parent).with_context(|| format!("创建证书目录失败: {parent:?}"))?;
53 }
54
55 let mut params =
56 CertificateParams::new(vec!["localhost".into()]).context("构建证书参数失败")?;
57 params.distinguished_name = DistinguishedName::new();
58 params
59 .distinguished_name
60 .push(DnType::CommonName, "localhost");
61 params.subject_alt_names = vec![
62 SanType::DnsName("localhost".try_into()?),
63 SanType::IpAddress(std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST)),
64 ];
65
66 let key_pair = KeyPair::generate().context("生成 TLS 密钥对失败")?;
67 let cert = params
68 .self_signed(&key_pair)
69 .context("签发 dev 自签证书失败")?;
70
71 fs::write(cert_path, cert.pem()).with_context(|| format!("写入证书失败: {cert_path:?}"))?;
72 fs::write(key_path, key_pair.serialize_pem())
73 .with_context(|| format!("写入私钥失败: {key_path:?}"))?;
74 tracing::info!("已生成 dev 自签 TLS 证书 cert={cert_path:?} key={key_path:?}");
75 Ok(())
76}
77
78fn install_rustls_provider() {
82 let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
83}
84
85pub async fn serve(
105 addr: &str,
106 app: Router,
107 server: &ServerConfig,
108 config_dir: &Path,
109 profile: &str,
110) -> Result<()> {
111 if server.ssl_enabled {
112 install_rustls_provider();
113 let cert_rel = server
114 .tls_cert
115 .as_deref()
116 .context("ssl_enabled=true 时需配置 server.tls_cert")?;
117 let key_rel = server
118 .tls_key
119 .as_deref()
120 .context("ssl_enabled=true 时需配置 server.tls_key")?;
121 let cert_path = resolve_tls_path(config_dir, cert_rel);
122 let key_path = resolve_tls_path(config_dir, key_rel);
123
124 if profile == "dev" || profile == "dev-h2" {
125 ensure_dev_tls_pem(&cert_path, &key_path)?;
126 }
127
128 let rustls_config =
129 axum_server::tls_rustls::RustlsConfig::from_pem_file(&cert_path, &key_path)
130 .await
131 .with_context(|| format!("加载 TLS 证书失败 cert={cert_path:?}"))?;
132
133 let socket_addr: SocketAddr = addr.parse().context("解析监听地址失败")?;
134 tracing::info!("HTTPS/HTTP2 监听 {addr}");
135 axum_server::bind_rustls(socket_addr, rustls_config)
136 .serve(app.into_make_service())
137 .await
138 .context("HTTPS 服务异常退出")?;
139 } else {
140 let listener = tokio::net::TcpListener::bind(addr)
141 .await
142 .with_context(|| format!("绑定端口失败: {addr}"))?;
143 tracing::info!("HTTP/1.1 监听 {addr}");
144 axum::serve(listener, app)
145 .await
146 .context("HTTP 服务异常退出")?;
147 }
148 Ok(())
149}