use crate::config::GLOBAL_CONFIG;
use crate::manifest::load_manifest;
use crate::mode::{GLOBAL_MODE, Mode};
use axum::routing::{Router, get};
use colored::Colorize;
use ssr_rs::Ssr;
use tower_http::services::ServeDir;
use tuono_internal::config::Config;
use tuono_internal::tuono_println;
use crate::env::load_env_vars;
use crate::{
catch_all::catch_all, services::logger::LoggerLayer, vite_reverse_proxy::vite_reverse_proxy,
vite_websocket_proxy::vite_websocket_proxy,
};
const DEV_PUBLIC_DIR: &str = "public";
const PROD_PUBLIC_DIR: &str = "out/client";
pub fn tuono_internal_init_v8_platform() {
Ssr::create_platform();
}
#[derive(Debug)]
pub struct Server {
router: Router,
mode: Mode,
pub listener: tokio::net::TcpListener,
pub address: String,
pub origin: Option<String>,
}
impl Server {
fn display_start_message(&self) {
let server_base_url = format!("http://{}", self.address);
if self.mode == Mode::Prod {
tuono_println!("Production server at: {}\n", server_base_url.blue().bold());
if let Some(origin) = &self.origin {
tuono_println!("Origin: {}\n", origin.blue().bold());
}
} else {
tuono_println!("Ready\n");
}
}
pub async fn init(router: Router, mode: Mode) -> Server {
let config = Config::get().expect("[SERVER] Failed to load config");
let _ = GLOBAL_MODE.set(mode);
let _ = GLOBAL_CONFIG.set(config.clone());
if mode == Mode::Prod {
if let Err(err) = load_manifest() {
tuono_println!("Failed to load vite manifest: {}", err.to_string().red());
}
}
let server_address = format!("{}:{}", config.server.host, config.server.port);
unsafe {
load_env_vars(mode);
}
Server {
router,
mode,
address: server_address.clone(),
origin: config.server.origin.clone(),
listener: tokio::net::TcpListener::bind(&server_address)
.await
.expect("[SERVER] Failed to bind to address"),
}
}
pub async fn start(self) {
self.display_start_message();
if self.mode == Mode::Dev {
let router = self
.router
.to_owned()
.layer(LoggerLayer::new())
.route("/vite-server/", get(vite_websocket_proxy))
.route("/vite-server/{*path}", get(vite_reverse_proxy))
.fallback_service(
ServeDir::new(DEV_PUBLIC_DIR)
.fallback(get(catch_all).layer(LoggerLayer::new())),
);
axum::serve(self.listener, router)
.await
.expect("Failed to serve development server");
} else {
let router = self
.router
.to_owned()
.layer(LoggerLayer::new())
.fallback_service(
ServeDir::new(PROD_PUBLIC_DIR)
.fallback(get(catch_all).layer(LoggerLayer::new())),
);
axum::serve(self.listener, router)
.await
.expect("Failed to serve production server");
}
}
}