|
|
|
@ -1,12 +1,15 @@ |
|
|
|
use crate::commands::{ClapArgs, Configurable, Executable}; |
|
|
|
use crate::commands::{ClapArgs, Configurable, Executable}; |
|
|
|
use crate::config::AppConfig; |
|
|
|
use crate::config::AppConfig; |
|
|
|
use crate::container::Container; |
|
|
|
use crate::container::Container; |
|
|
|
|
|
|
|
use crate::router; |
|
|
|
|
|
|
|
|
|
|
|
use anyhow::Result; |
|
|
|
use anyhow::Result; |
|
|
|
use async_trait::async_trait; |
|
|
|
use async_trait::async_trait; |
|
|
|
use config::ConfigBuilder; |
|
|
|
use config::ConfigBuilder; |
|
|
|
use config::builder::DefaultState; |
|
|
|
use config::builder::DefaultState; |
|
|
|
use serde::Deserialize; |
|
|
|
use serde::Deserialize; |
|
|
|
|
|
|
|
use tokio::net::TcpListener; |
|
|
|
|
|
|
|
use tracing::info; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)] |
|
|
|
#[derive(Debug, Deserialize, Clone)] |
|
|
|
pub struct Config { |
|
|
|
pub struct Config { |
|
|
|
@ -16,7 +19,7 @@ pub struct Config { |
|
|
|
|
|
|
|
|
|
|
|
#[derive(ClapArgs, Debug, Clone)] |
|
|
|
#[derive(ClapArgs, Debug, Clone)] |
|
|
|
pub struct ListenCmd { |
|
|
|
pub struct ListenCmd { |
|
|
|
#[arg(short, long, help = defaults::HELP_LISTEN_HOST)] |
|
|
|
#[arg(short = 'H', long, help = defaults::HELP_LISTEN_HOST)] |
|
|
|
pub host: Option<String>, |
|
|
|
pub host: Option<String>, |
|
|
|
|
|
|
|
|
|
|
|
#[arg(short, long, help = defaults::HELP_LISTEN_PORT)] |
|
|
|
#[arg(short, long, help = defaults::HELP_LISTEN_PORT)] |
|
|
|
@ -52,18 +55,53 @@ impl Configurable for ListenCmd { |
|
|
|
|
|
|
|
|
|
|
|
#[async_trait] |
|
|
|
#[async_trait] |
|
|
|
impl Executable for ListenCmd { |
|
|
|
impl Executable for ListenCmd { |
|
|
|
async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { |
|
|
|
async fn execute(&self, config: &AppConfig, _container: &Container) -> Result<()> { |
|
|
|
let config = config |
|
|
|
let listen_config = config |
|
|
|
.listen |
|
|
|
.listen |
|
|
|
.as_ref() |
|
|
|
.as_ref() |
|
|
|
.ok_or_else(|| anyhow::anyhow!("Decoder config missing"))?; |
|
|
|
.ok_or_else(|| anyhow::anyhow!("Listen config missing"))?; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: start axum server
|
|
|
|
let app = router::create_router(); |
|
|
|
|
|
|
|
let addr = format!("{}:{}", listen_config.host, listen_config.port); |
|
|
|
|
|
|
|
let listener = TcpListener::bind(&addr).await?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
info!("Starting server on {}", addr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
axum::serve(listener, app) |
|
|
|
|
|
|
|
.with_graceful_shutdown(shutdown_signal()) |
|
|
|
|
|
|
|
.await?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
info!("Server shut down gracefully"); |
|
|
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async fn shutdown_signal() { |
|
|
|
|
|
|
|
let ctrl_c = async { |
|
|
|
|
|
|
|
tokio::signal::ctrl_c() |
|
|
|
|
|
|
|
.await |
|
|
|
|
|
|
|
.expect("Failed to install Ctrl+C handler"); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(unix)] |
|
|
|
|
|
|
|
let terminate = async { |
|
|
|
|
|
|
|
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) |
|
|
|
|
|
|
|
.expect("Failed to install signal handler") |
|
|
|
|
|
|
|
.recv() |
|
|
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
info!("Received SIGTERM signal"); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(not(unix))] |
|
|
|
|
|
|
|
let terminate = std::future::pending::<()>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tokio::select! { |
|
|
|
|
|
|
|
_ = ctrl_c => {}, |
|
|
|
|
|
|
|
_ = terminate => {}, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
mod defaults { |
|
|
|
mod defaults { |
|
|
|
use const_format::formatcp; |
|
|
|
use const_format::formatcp; |
|
|
|
pub const LISTEN_HOST: &str = "0.0.0.0"; |
|
|
|
pub const LISTEN_HOST: &str = "0.0.0.0"; |
|
|
|
|