use crate::{
service_activator_processor::ServiceActivatorProcessor,
spec::{
AlloraSpecYamlParser, ChannelSpecYamlParser, FilterSpecYamlParser, ServiceSpecYamlParser,
},
Channel, Error, Filter, Result,
};
use component_builders::{
build_channel_from_spec, build_channels_from_spec, build_filter_from_spec,
build_filters_from_spec, build_http_inbound_adapters_from_spec, build_service_from_spec,
build_http_outbound_adapters_from_spec,
};
use std::path::Path;
pub mod component_builders;
pub mod runtime;
use runtime::AlloraRuntime;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DslFormat {
Yaml,
Json,
Xml,
}
impl DslFormat {
pub fn from_path(path: &Path) -> Option<Self> {
match path
.extension()
.and_then(|e| e.to_str())
.map(|s| s.to_ascii_lowercase())
{
Some(ref ext) if ext == "yml" || ext == "yaml" => Some(DslFormat::Yaml),
Some(ref ext) if ext == "json" => Some(DslFormat::Json),
Some(ref ext) if ext == "xml" => Some(DslFormat::Xml),
_ => None,
}
}
}
pub fn build_channel_from_str(raw: &str, format: DslFormat) -> Result<Box<dyn Channel>> {
match format {
DslFormat::Yaml => {
let spec = ChannelSpecYamlParser::parse_str(raw)?;
build_channel_from_spec(spec)
}
DslFormat::Json => Err(Error::serialization("json format not yet supported")),
DslFormat::Xml => Err(Error::serialization("xml format not yet supported")),
}
}
pub fn build_channel(path: impl AsRef<Path>) -> Result<Box<dyn Channel>> {
let path_ref = path.as_ref();
let raw =
std::fs::read_to_string(path_ref).map_err(|e| Error::other(format!("read error: {e}")))?;
let format = DslFormat::from_path(path_ref)
.ok_or_else(|| Error::serialization("cannot infer DSL format from extension"))?;
build_channel_from_str(&raw, format)
}
fn build_filter_from_str(raw: &str, format: DslFormat) -> Result<Filter> {
match format {
DslFormat::Yaml => {
let spec = FilterSpecYamlParser::parse_str(raw)?;
build_filter_from_spec(spec)
}
DslFormat::Json => Err(Error::serialization("json format not yet supported")),
DslFormat::Xml => Err(Error::serialization("xml format not yet supported")),
}
}
pub fn build_filter(path: impl AsRef<Path>) -> Result<Filter> {
let path_ref = path.as_ref();
let raw =
std::fs::read_to_string(path_ref).map_err(|e| Error::other(format!("read error: {e}")))?;
let format = DslFormat::from_path(path_ref)
.ok_or_else(|| Error::serialization("cannot infer DSL format from extension"))?;
build_filter_from_str(&raw, format)
}
fn build_service_from_str(
raw: &str,
format: DslFormat,
) -> Result<component_builders::ServiceProcessor> {
match format {
DslFormat::Yaml => {
let spec = ServiceSpecYamlParser::parse_str(raw)?;
build_service_from_spec(spec)
}
DslFormat::Json => Err(Error::serialization("json format not yet supported")),
DslFormat::Xml => Err(Error::serialization("xml format not yet supported")),
}
}
pub fn build_service(path: impl AsRef<Path>) -> Result<component_builders::ServiceProcessor> {
let path_ref = path.as_ref();
let raw =
std::fs::read_to_string(path_ref).map_err(|e| Error::other(format!("read error: {e}")))?;
let format = DslFormat::from_path(path_ref)
.ok_or_else(|| Error::serialization("cannot infer DSL format from extension"))?;
build_service_from_str(&raw, format)
}
fn build_runtime_from_str(raw: &str, format: DslFormat) -> Result<AlloraRuntime> {
match format {
DslFormat::Yaml => {
let top = AlloraSpecYamlParser::parse_str(raw)?;
let filters_spec = top.filters_spec().cloned();
let services_spec = top.services_spec().cloned();
let http_inbound_spec = top.http_inbound_adapters_spec().cloned();
let http_outbound_spec = top.http_outbound_adapters_spec().cloned();
let channels_spec = top.into_channels_spec();
let channels = build_channels_from_spec(channels_spec)?;
let mut rt = AlloraRuntime::new(channels);
if let Some(fspec) = filters_spec {
let filters = build_filters_from_spec(fspec)?;
rt = rt.with_filters(filters);
}
if let Some(sspec) = services_spec {
let services =
component_builders::build_service_activators_from_spec(sspec.clone())?;
rt = rt.with_services(services);
let mut procs = Vec::new();
for s in sspec.services_activators() {
procs.push(ServiceActivatorProcessor::new(s.clone()));
}
rt = rt.with_service_processors(procs);
}
if let Some(hspec) = http_inbound_spec {
let lookup = |id: &str| rt.channel_ref_by_id(id);
let adapters = build_http_inbound_adapters_from_spec(hspec, &lookup)?;
rt = rt.with_http_inbound_adapters(adapters);
}
if let Some(ospec) = http_outbound_spec {
let outbound = build_http_outbound_adapters_from_spec(ospec)?;
rt = rt.with_http_outbound_adapters(outbound);
}
Ok(rt)
}
DslFormat::Json => Err(Error::serialization("json format not yet supported")),
DslFormat::Xml => Err(Error::serialization("xml format not yet supported")),
}
}
pub fn build(path: impl AsRef<Path>) -> Result<AlloraRuntime> {
let path_ref = path.as_ref();
let raw =
std::fs::read_to_string(path_ref).map_err(|e| Error::other(format!("read error: {e}")))?;
let format = DslFormat::from_path(path_ref)
.ok_or_else(|| Error::serialization("cannot infer DSL format from extension"))?;
build_runtime_from_str(&raw, format)
}