Files
NxMesh-old/crates/nxmesh-master/src/lib.rs
GW_MC 4eddf7e094 feat: Implement initial setup service for admin user creation
- Added `SetupService` to handle the generation and validation of setup tokens.
- Integrated setup token generation during application startup if no admin users exist.
- Created API endpoints for checking setup status and completing the initial setup.
- Updated `AuthService` to include functionality for creating the initial admin user.
- Enhanced error handling for setup and authentication processes.
- Added frontend components for login and protected routes.
- Implemented Zustand store for managing authentication state.
- Updated Vite configuration to check setup status and serve the setup page if required.
- Documented the initial setup process in `setup.md`.
2026-03-03 07:46:49 +00:00

118 lines
3.9 KiB
Rust

//! NxMesh Master Library
//!
//! This crate implements the control plane for NxMesh.
pub mod api;
pub mod config;
pub mod db;
pub mod domain;
pub mod events;
pub mod grpc;
pub mod infrastructure;
pub mod services;
use std::sync::Arc;
use config::Settings;
use db::{Database, Migrator};
use sea_orm_migration::MigratorTrait;
use tokio::net::TcpListener;
use tracing::{error, info};
/// Start the master server
pub async fn start(settings: Settings) -> Result<(), Box<dyn std::error::Error>> {
let settings = Arc::new(settings);
info!("Connecting to database...");
let db = Database::connect(&settings.database.url).await.map_err(|e| {
error!("Failed to connect to database: {}", e);
e
})?;
info!("Running database migrations...");
Migrator::up(db.conn(), None).await.map_err(|e| {
error!("Failed to run migrations: {}", e);
e
})?;
info!("Database migrations complete");
// Create application state
let app_state = api::routes::AppState::new(db.clone(), settings.clone());
// Generate setup token if no admin exists
match app_state.setup_service.has_admin_users().await {
Ok(false) => {
info!("=================================================================");
info!(" INITIAL SETUP REQUIRED ");
info!("=================================================================");
info!("No admin user found. A setup token has been generated.");
info!("");
match app_state.setup_service.generate_setup_token().await {
Ok(token_info) => {
info!("SETUP TOKEN: {}", token_info.plain_token);
info!("EXPIRES AT: {}", token_info.expires_at);
info!("");
info!("Use this token to create the first admin account at:");
info!(" http://{}:{}/setup", settings.server.bind_address, settings.server.port);
info!("");
info!("WARNING: This token is single-use and will expire in 24 hours.");
info!(" It is displayed only once in these logs.");
}
Err(e) => {
error!("Failed to generate setup token: {}", e);
}
}
info!("=================================================================");
}
Ok(true) => {
info!("Admin user exists - initial setup already completed");
}
Err(e) => {
error!("Failed to check admin status: {}", e);
}
}
// Create router
let app = api::routes::create_router(app_state);
// Start HTTP server
let http_addr = format!("{}:{}", settings.server.bind_address, settings.server.port);
info!("Starting HTTP server on {}", http_addr);
let http_listener = TcpListener::bind(&http_addr).await?;
// Start gRPC server in a separate task
let grpc_settings = settings.clone();
let grpc_db = db.clone();
let grpc_handle = tokio::spawn(async move {
let grpc_addr = format!("{}:{}", grpc_settings.grpc.bind_address, grpc_settings.grpc.port);
info!("Starting gRPC server on {}", grpc_addr);
if let Err(e) = grpc::server::start(&grpc_addr, grpc_db).await {
error!("gRPC server error: {}", e);
}
});
// Run HTTP server
info!("Master server ready!");
tokio::select! {
result = axum::serve(http_listener, app) => {
if let Err(e) = result {
error!("HTTP server error: {}", e);
}
}
_ = tokio::signal::ctrl_c() => {
info!("Shutdown signal received");
}
}
// Cancel gRPC server
grpc_handle.abort();
info!("Master server shutdown complete");
Ok(())
}