build: add api server config loader
This commit is contained in:
@@ -94,7 +94,8 @@
|
||||
|
||||
- [x] 搭建 `main.rs` / `Router` / `with_state`
|
||||
交付物:[../server-rs/apps/api-server/src/main.rs](../server-rs/apps/api-server/src/main.rs)
|
||||
- [ ] 接入统一配置加载
|
||||
- [x] 接入统一配置加载
|
||||
交付物:[../server-rs/apps/api-server/src/config.rs](../server-rs/apps/api-server/src/config.rs)
|
||||
- [ ] 接入统一日志与 tracing
|
||||
- [ ] 接入 `request_id` 中间件
|
||||
- [ ] 接入统一错误处理中间件
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
3. `src/main.rs`
|
||||
4. `src/app.rs`
|
||||
5. `src/state.rs`
|
||||
6. `src/config.rs`
|
||||
|
||||
后续与本 package 直接相关的任务包括:
|
||||
|
||||
1. 接入统一配置加载
|
||||
2. 接入统一日志与 tracing
|
||||
3. 接入 `request_id`
|
||||
4. 接入统一错误处理中间件
|
||||
5. 接入 response envelope
|
||||
6. 接入 `/healthz`
|
||||
1. 接入统一日志与 tracing
|
||||
2. 接入 `request_id`
|
||||
3. 接入统一错误处理中间件
|
||||
4. 接入 response envelope
|
||||
5. 接入 `/healthz`
|
||||
|
||||
## 3. 边界约束
|
||||
|
||||
|
||||
44
server-rs/apps/api-server/src/config.rs
Normal file
44
server-rs/apps/api-server/src/config.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use std::{env, net::SocketAddr};
|
||||
|
||||
// 集中管理 api-server 的启动配置,避免入口层直接散落环境变量解析逻辑。
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AppConfig {
|
||||
pub bind_host: String,
|
||||
pub bind_port: u16,
|
||||
}
|
||||
|
||||
impl Default for AppConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bind_host: "127.0.0.1".to_string(),
|
||||
bind_port: 3000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
pub fn from_env() -> Self {
|
||||
let mut config = Self::default();
|
||||
|
||||
if let Ok(bind_host) = env::var("GENARRATIVE_API_HOST") {
|
||||
if !bind_host.trim().is_empty() {
|
||||
config.bind_host = bind_host;
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(bind_port) = env::var("GENARRATIVE_API_PORT") {
|
||||
if let Ok(parsed_port) = bind_port.parse::<u16>() {
|
||||
config.bind_port = parsed_port;
|
||||
}
|
||||
}
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
pub fn bind_socket_addr(&self) -> SocketAddr {
|
||||
let address = format!("{}:{}", self.bind_host, self.bind_port);
|
||||
address
|
||||
.parse()
|
||||
.unwrap_or_else(|_| SocketAddr::from(([127, 0, 0, 1], 3000)))
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
mod app;
|
||||
mod config;
|
||||
mod state;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
use crate::{app::build_router, state::AppState};
|
||||
use crate::{app::build_router, config::AppConfig, state::AppState};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), std::io::Error> {
|
||||
// 当前阶段先用固定地址启动最小骨架,后续再切到统一配置加载。
|
||||
let bind_address = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
// 统一先从配置对象读取监听地址,避免后续把环境变量读取散落到入口和路由层。
|
||||
let config = AppConfig::from_env();
|
||||
let bind_address = config.bind_socket_addr();
|
||||
let listener = TcpListener::bind(bind_address).await?;
|
||||
|
||||
let state = AppState::new();
|
||||
let state = AppState::new(config);
|
||||
let router = build_router(state);
|
||||
|
||||
axum::serve(listener, router).await
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
use crate::config::AppConfig;
|
||||
|
||||
// 当前阶段先保留最小共享状态壳,后续逐步接入配置、客户端与平台适配。
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct AppState;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AppState {
|
||||
// 配置会在后续中间件、路由和平台适配接入时逐步消费。
|
||||
#[allow(dead_code)]
|
||||
pub config: AppConfig,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
pub fn new(config: AppConfig) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user