tdm_server_rust/server/
mod.rs1use anyhow::{Context, Result};
20use axum::Router;
21use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, SanType};
22use std::fs;
23use std::net::SocketAddr;
24use std::path::{Path, PathBuf};
25use crate::config::ServerConfig;
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 = CertificateParams::new(vec!["localhost".into()])
56 .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.self_signed(&key_pair).context("签发 dev 自签证书失败")?;
68
69 fs::write(cert_path, cert.pem()).with_context(|| format!("写入证书失败: {cert_path:?}"))?;
70 fs::write(key_path, key_pair.serialize_pem()).with_context(|| {
71 format!("写入私钥失败: {key_path:?}")
72 })?;
73 tracing::info!(
74 "已生成 dev 自签 TLS 证书 cert={cert_path:?} key={key_path:?}"
75 );
76 Ok(())
77}
78
79fn install_rustls_provider() {
83 let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
84}
85
86pub async fn serve(
106 addr: &str,
107 app: Router,
108 server: &ServerConfig,
109 config_dir: &Path,
110 profile: &str,
111) -> Result<()> {
112 if server.ssl_enabled {
113 install_rustls_provider();
114 let cert_rel = server
115 .tls_cert
116 .as_deref()
117 .context("ssl_enabled=true 时需配置 server.tls_cert")?;
118 let key_rel = server
119 .tls_key
120 .as_deref()
121 .context("ssl_enabled=true 时需配置 server.tls_key")?;
122 let cert_path = resolve_tls_path(config_dir, cert_rel);
123 let key_path = resolve_tls_path(config_dir, key_rel);
124
125 if profile == "dev" || profile == "dev-h2" {
126 ensure_dev_tls_pem(&cert_path, &key_path)?;
127 }
128
129 let rustls_config = 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}