use std::path::Path;
use camel_api::CamelError;
use camel_bundles::BootHandle;
use camel_config::config::CamelConfig;
use camel_core::CamelContext;
use camel_core::RouteDefinition;
use crate::document::{RouteSource, ScenarioDocument};
use crate::env_layers::LayeredEnv;
pub struct ScenarioRun {
pub ctx: CamelContext,
pub boot: BootHandle,
}
pub async fn boot_scenario(
doc: &ScenarioDocument,
root: &Path,
env: &LayeredEnv,
) -> Result<ScenarioRun, CamelError> {
let config_path = root.join("Camel.toml");
let config = CamelConfig::from_file_sealed(
config_path.to_str().ok_or_else(|| {
CamelError::Config(format!(
"scenario config path is not valid utf-8: {}",
config_path.display()
))
})?,
doc.profile.as_deref().unwrap_or("default"),
&|name| env.lookup(name),
)
.map_err(|e| {
CamelError::Config(format!(
"failed to load scenario config {}: {e}",
config_path.display()
))
})?;
let mut ctx = CamelConfig::configure_context_with_beans(&config, None).await?;
let boot = camel_bundles::boot(&mut ctx, &config, root).await?;
for def in load_route_definitions(doc, root, env)? {
ctx.add_route_definition(def).await?;
}
ctx.start().await?;
Ok(ScenarioRun { ctx, boot })
}
fn load_route_definitions(
doc: &ScenarioDocument,
root: &Path,
env: &LayeredEnv,
) -> Result<Vec<RouteDefinition>, CamelError> {
match &doc.route_source {
RouteSource::RouteFiles(files) | RouteSource::RouteFilesFromRoot(files) => {
let mut defs = Vec::new();
for file in files {
let full = root.join(file);
let metadata = std::fs::metadata(&full)
.map_err(|e| CamelError::Io(format!("{}: {e}", full.display())))?;
if metadata.len() > camel_dsl::MAX_ROUTE_FILE_SIZE {
return Err(CamelError::RouteError(format!(
"{}: route file exceeds the {} byte cap",
full.display(),
camel_dsl::MAX_ROUTE_FILE_SIZE
)));
}
let content = std::fs::read_to_string(&full)
.map_err(|e| CamelError::Io(format!("{}: {e}", full.display())))?;
let interpolated =
camel_dsl::env_interpolation::interpolate_env_with(&content, &|name| {
env.lookup(name)
})
.map_err(|name| {
CamelError::Config(format!(
"{}: unresolved ${{env:{name}}} placeholder \
(no layer of the scenario environment defines it)",
full.display()
))
})?;
defs.extend(
camel_dsl::parse_yaml(&interpolated)
.map_err(|e| CamelError::RouteError(format!("{}: {e}", full.display())))?,
);
}
Ok(defs)
}
RouteSource::Inline(_) => Err(CamelError::Config(
"inline route sources cannot boot in v1: declare routeFiles \
(the document parser owns inline definitions; the boot \
receives the document by reference)"
.to_string(),
)),
}
}