1mod cli;
7mod db;
8mod routes;
9
10use colored::Colorize;
11use crate::db::schema;
13use quorum_core::db as core_db;
14use quorum_core::startup;
15use routes::route::create_router;
16use std::net::SocketAddr;
17use std::time::Instant;
18
19#[tokio::main]
20async fn main() {
21 print!("\x1B[2J\x1B[1;1H");
23
24 startup::print_banner();
25 startup::print_initializing();
26
27 let timer = startup::create_timer();
29 match quorum_core::utility::config::Config::load() {
30 Ok(_) => startup::print_step("Loading config", true, startup::elapsed(timer)),
31 Err(e) => {
32 startup::print_step("Loading config", false, startup::elapsed(timer));
33 eprintln!("{}", format!(" Error: {}", e).red());
34 std::process::exit(1);
35 }
36 };
37
38 let config = quorum_core::utility::config::Config::get();
40
41 let timer = startup::create_timer();
43 let _db = match core_db::init().await {
44 Ok(db) => {
45 startup::print_step("Opening database", true, startup::elapsed(timer));
46 db
47 }
48 Err(e) => {
49 startup::print_step("Opening database", false, startup::elapsed(timer));
50 eprintln!("{}", format!(" Error: {}", e).red());
51 std::process::exit(1);
52 }
53 };
54
55 let timer = startup::create_timer();
57 match schema::init(&_db).await {
58 Ok(_) => {
59 startup::print_step("Initializing schema", true, startup::elapsed(timer));
60 let _ = core_db::queries::server_logs::log_startup(
61 &_db,
62 startup::elapsed(timer).as_millis() as i64,
63 )
64 .await;
65 }
66 Err(e) => {
67 startup::print_step("Initializing schema", false, startup::elapsed(timer));
68 eprintln!("{}", format!(" Error: {}", e).red());
69 let _ = core_db::queries::server_logs::log_error(&_db, e.to_string(), 0).await;
70 std::process::exit(1);
71 }
72 }
73
74 startup::print_ready(config.server_port);
75
76 let server_start = Instant::now();
79
80 let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
82
83 let app = create_router(_db.clone());
85 let host = config
86 .server_host
87 .parse::<std::net::IpAddr>()
88 .expect("Invalid SERVER_HOST IP address");
89 let addr = SocketAddr::from((host, config.server_port));
90 let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
91 let server = axum::serve(
92 listener,
93 app.into_make_service_with_connect_info::<SocketAddr>(),
94 );
95
96 let server_task = tokio::spawn(async move {
97 server
98 .with_graceful_shutdown(async move {
99 let _ = shutdown_rx.changed().await;
100 })
101 .await
102 });
103
104 cli::spawn_cli(_db.clone(), server_start, shutdown_tx).await;
144
145 let shutdown = async {
146 let _ = tokio::signal::ctrl_c().await;
147 };
148
149 tokio::select! {
150 _ = server_task => {},
151 _ = shutdown => {
152 println!("\nShutting down...");
153 let _ = quorum_core::db::queries::server_logs::log_shutdown(&_db, server_start.elapsed().as_millis() as i64).await;
154 }
155 }
156}