//! 充电柜矩阵系统 — 后端入口 mod config; mod db; mod error; mod middleware; mod redis; mod routes; mod tcp; use std::net::SocketAddr; use tracing_subscriber::EnvFilter; use tcp::commands::AppState; use tcp::connection::ConnectionPool; #[tokio::main] async fn main() { // 初始化日志 tracing_subscriber::fmt() .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into())) .init(); // 加载配置 let cfg = config::Config::from_env(); cfg.validate(); tracing::info!("配置加载完成"); // 初始化 MySQL 连接池 let db_pool = db::init_pool(&cfg.database_url) .await .expect("MySQL 连接失败"); tracing::info!("数据库连接成功"); // 执行自动迁移 db::migrate::run(&db_pool) .await .expect("数据库迁移失败"); tracing::info!("数据库迁移完成"); // 初始化 Redis 连接(ConnectionManager 内部管理重连,可直接 Clone 共享) let redis_conn = redis::init_connection(&cfg.redis_url) .await .expect("Redis 连接失败"); tracing::info!("Redis 连接成功"); // 初始化设备连接池 let device_pool = ConnectionPool::new(); // 构建共享状态 let state = AppState { device_pool: device_pool.clone(), redis: redis_conn.clone(), mysql: db_pool.clone(), }; // 启动 TCP 设备服务(后台) let tcp_addr = format!("{}:{}", cfg.host, cfg.tcp_port); tracing::info!("TCP 设备服务启动于 {}", tcp_addr); let tcp_pool = device_pool.clone(); let tcp_redis = redis_conn.clone(); let tcp_mysql = db_pool.clone(); tokio::spawn(async move { tcp::run_tcp_server(tcp_addr, tcp_pool, tcp_redis, tcp_mysql).await; }); // 构建 HTTP 路由(包含设备指令下发端点和认证中间件) let app = routes::build(state); // 启动 HTTP 服务 let addr: SocketAddr = format!("{}:{}", cfg.host, cfg.port) .parse() .expect("无效的监听地址"); tracing::info!("HTTP 服务器启动于 http://{}", addr); let listener = tokio::net::TcpListener::bind(addr) .await .expect("端口绑定失败"); axum::serve(listener, app) .await .expect("服务器运行失败"); }