use std::net::SocketAddr;
use std::{future::IntoFuture, sync::Arc};
use deeplx::{Config, DeepLX};
use tokio::sync::watch;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use crate::server::{biz, conf, data, pkgs::exit::shutdown_signal, routes};
use crate::{Bootstrap, Result, error::Error};
pub fn run(args: Bootstrap) -> Result<()> {
let manager = conf::Manager::new(args.conf.as_str());
let config = manager.config();
let conf::Config {
debug,
bind,
concurrent,
proxy,
..
} = config
.read()
.expect("Config lock poisoned - this is a critical error")
.clone();
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
format!(
"{}={}",
env!("CARGO_CRATE_NAME"),
if debug { "trace" } else { "info" }
)
.into()
}),
)
.with(tracing_subscriber::fmt::layer())
.init();
let cpus = std::thread::available_parallelism()?;
tracing::info!("OS: {}", std::env::consts::OS);
tracing::info!("Arch: {}", std::env::consts::ARCH);
tracing::info!("CPUs: {}", cpus);
tracing::info!("Concurrent: {}", concurrent);
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.worker_threads(cpus.into())
.build()?;
runtime.block_on(async move {
let translator = Arc::new(DeepLX::new(Config {
proxy,
..Config::default()
}));
let translate_repo = Arc::new(data::translate::TranslateRepo::new(translator));
let translate_uc = Arc::new(biz::translate::TranslateUsecase::new(translate_repo));
let state = routes::AppState {
translate_uc,
config,
};
let app = routes::router(state).layer(TraceLayer::new_for_http());
let socket = match bind {
SocketAddr::V4(_) => tokio::net::TcpSocket::new_v4()?,
SocketAddr::V6(_) => tokio::net::TcpSocket::new_v6()?,
};
socket.set_reuseaddr(true)?;
socket.bind(bind)?;
let listener = socket.listen(concurrent)?;
tracing::info!("listening on {}", listener.local_addr()?);
let (tx, rx) = watch::channel(());
let tx = Arc::new(tx);
tokio::pin! {
let serve_fut = axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal(Arc::clone(&tx)))
.into_future();
let manager_fut = manager
.with_watcher(shutdown_signal(Arc::clone(&tx)))
.into_future();
}
tokio::select! {
_ = &mut serve_fut => {
drop(rx);
let _ = &mut manager_fut.await;
},
_ = &mut manager_fut => {
drop(rx);
let _ = &mut serve_fut.await;
},
}
Ok::<(), Error>(())
})?;
Ok(())
}