use crate::cli::Cli;
use crate::config::FrameConfig;
use crate::embedded::EmbeddedLiminal;
use crate::error::HostError;
use crate::manifest;
use crate::runtime::HostRuntime;
use crate::serve::{ServeStop, serve};
pub fn run(cli: &Cli) -> Result<(), HostError> {
let config = FrameConfig::load(&cli.config)?;
let runtime = HostRuntime::new()?;
let logger = runtime.spawn_event_logger()?;
if let Err(error) = runtime.install_demo_component() {
match runtime.registry().remove(manifest::component_id()) {
Ok(outcome) => {
tracing::warn!(outcome = ?outcome, "removed demo component after failed boot");
}
Err(cleanup) => tracing::error!(%cleanup, "cleanup after failed boot also failed"),
}
return Err(error);
}
let liminal = match EmbeddedLiminal::boot(&config.liminal) {
Ok(liminal) => liminal,
Err(error) => {
if let Err(teardown) = runtime.shutdown(logger) {
tracing::error!(
%teardown,
"frame-core teardown after liminal boot failure also failed"
);
}
return Err(error);
}
};
let liminal_endpoint = liminal.websocket_endpoint();
tracing::info!(
endpoint = %liminal_endpoint,
"embedded liminal component booted; /frame/config.json advertises its real bound WebSocket address"
);
let tokio_runtime = match tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
{
Ok(tokio_runtime) => tokio_runtime,
Err(source) => {
if let Err(teardown) = liminal.shutdown() {
tracing::error!(%teardown, "embedded liminal teardown after async-runtime build failure also failed");
}
if let Err(teardown) = runtime.shutdown(logger) {
tracing::error!(%teardown, "frame-core teardown after async-runtime build failure also failed");
}
return Err(HostError::AsyncRuntime { source });
}
};
let serve_outcome = tokio_runtime.block_on(serve(&config, &liminal, liminal_endpoint));
let liminal_shutdown = liminal.shutdown();
if let Err(ref error) = liminal_shutdown {
tracing::error!(%error, "embedded liminal graceful shutdown failed");
}
let host_shutdown = runtime.shutdown(logger);
if let Err(ref error) = host_shutdown {
tracing::error!(%error, "frame-core ordered shutdown failed");
}
let stop = serve_outcome?;
if let ServeStop::LiminalExited { detail } = stop {
return Err(HostError::LiminalExited { detail });
}
liminal_shutdown?;
host_shutdown?;
tracing::info!("frame server exited cleanly");
Ok(())
}