use super::serve::get_host_and_port;
use super::EngineOperation;
use crate::server::ServerOptions;
use crate::turbine::Turbine;
use crate::{i18n::TranslationsManager, init::PerseusAppBase, stores::MutableStore};
use fmterr::fmt_err;
use futures::Future;
use std::env;
use sycamore::web::SsrNode;
pub async fn run_dflt_engine_export_only<M, T, A>(op: EngineOperation, app: A) -> i32
where
M: MutableStore + 'static,
T: TranslationsManager + 'static,
A: Fn() -> PerseusAppBase<SsrNode, M, T> + 'static + Send + Sync + Clone,
{
let serve_fn = |_, _, _| async {
panic!("`run_dflt_engine_export_only` cannot run a server; you should use `run_dflt_engine` instead and import a server integration (e.g. `perseus-warp`)")
};
run_dflt_engine(op, app, serve_fn).await
}
pub async fn run_dflt_engine<M, T, F, A>(
op: EngineOperation,
app: A,
serve_fn: impl Fn(&'static Turbine<M, T>, ServerOptions, (String, u16)) -> F,
) -> i32
where
M: MutableStore + 'static,
T: TranslationsManager + 'static,
F: Future<Output = ()>,
A: Fn() -> PerseusAppBase<SsrNode, M, T> + 'static + Send + Sync + Clone,
{
let mut turbine = match Turbine::try_from(app()) {
Ok(turbine) => turbine,
Err(err) => {
eprintln!("{}", fmt_err(&err));
return 1;
}
};
match op {
EngineOperation::Build => match turbine.build().await {
Ok(_) => 0,
Err(err) => {
eprintln!("{}", fmt_err(&*err));
1
}
},
EngineOperation::Export => match turbine.export().await {
Ok(_) => 0,
Err(err) => {
eprintln!("{}", fmt_err(&*err));
1
}
},
EngineOperation::ExportErrorPage => {
match turbine.populate_after_build().await {
Ok(_) => (),
Err(err) => {
eprintln!("{}", fmt_err(&err));
return 1;
}
};
let args = env::args().collect::<Vec<String>>();
let code = match args.get(1) {
Some(arg) => {
match arg.parse::<u16>() {
Ok(err_code) => err_code,
Err(_) => {
eprintln!("HTTP status code for error page exporting must be a valid integer.");
return 1;
}
}
}
None => {
eprintln!("Error page exporting requires an HTTP status code for which to export the error page.");
return 1;
}
};
let output = match args.get(2) {
Some(output) => output,
None => {
eprintln!("Error page exporting requires an output location.");
return 1;
}
};
match turbine.export_error_page(code, output).await {
Ok(_) => 0,
Err(err) => {
eprintln!("{}", fmt_err(&*err));
1
}
}
}
EngineOperation::Serve => {
if !cfg!(debug_assertions) {
let binary_loc = env::current_exe().unwrap();
let binary_dir = binary_loc.parent().unwrap(); env::set_current_dir(binary_dir).unwrap();
}
match turbine.populate_after_build().await {
Ok(_) => (),
Err(err) => {
eprintln!("{} (if you're running `perseus snoop serve`, make sure you've run `perseus snoop build` first!)", fmt_err(&err));
return 1;
}
};
let addr = get_host_and_port();
#[cfg(not(debug_assertions))]
println!(
"Your production app is now live on <http://{host}:{port}>! To change this, re-run this command with different settings for the `PERSEUS_HOST` and `PERSEUS_PORT` environment variables.\nNote that the above address will not reflect any domains configured.",
host = &addr.0,
port = &addr.1
);
let turbine_static = Box::leak(Box::new(turbine));
serve_fn(turbine_static, ServerOptions::default(), addr).await;
0
}
EngineOperation::Tinker => match turbine.tinker() {
Ok(_) => 0,
Err(err) => {
eprintln!("{}", fmt_err(&err));
1
}
},
}
}