use std::collections::BTreeMap;
use std::sync::{Arc, RwLock};
use vertep_core::session::SCXML_EVENT_PROCESSOR;
use crate::address::Address;
use crate::mailbox::{Envelope, Mailbox};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TransportError(pub String);
impl core::fmt::Display for TransportError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "transport error: {}", self.0)
}
}
impl std::error::Error for TransportError {}
pub trait Transport: Send + Sync {
fn type_iri(&self) -> &str;
fn aliases(&self) -> Vec<String> {
Vec::new()
}
fn location(&self, address: &Address) -> String {
address.as_str().to_owned()
}
fn deliver(&self, mailbox: &dyn Mailbox, env: Envelope) -> Result<(), TransportError>;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct LocalTransport;
impl Transport for LocalTransport {
fn type_iri(&self) -> &str {
SCXML_EVENT_PROCESSOR
}
fn aliases(&self) -> Vec<String> {
vec!["scxml".to_owned()]
}
fn deliver(&self, mailbox: &dyn Mailbox, env: Envelope) -> Result<(), TransportError> {
mailbox
.enqueue(env)
.map_err(|e| TransportError(e.to_string()))
}
}
pub trait Resolver: Send + Sync {
fn resolve(&self, address: &Address) -> Option<Arc<dyn Mailbox>>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ResolveError(pub String);
impl core::fmt::Display for ResolveError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "cannot resolve {}", self.0)
}
}
impl std::error::Error for ResolveError {}
#[derive(Default)]
pub struct Directory {
resolvers: RwLock<BTreeMap<String, Arc<dyn Resolver>>>,
}
impl std::fmt::Debug for Directory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let schemes: Vec<String> = self
.resolvers
.read()
.map(|r| r.keys().cloned().collect())
.unwrap_or_default();
f.debug_struct("Directory")
.field("schemes", &schemes)
.finish()
}
}
impl Directory {
pub fn register(&self, scheme: &str, resolver: Arc<dyn Resolver>) {
if let Ok(mut r) = self.resolvers.write() {
r.insert(scheme.to_ascii_lowercase(), resolver);
}
}
pub fn resolve(&self, address: &Address) -> Result<Arc<dyn Mailbox>, ResolveError> {
let r = self
.resolvers
.read()
.ok()
.and_then(|r| r.get(&address.scheme().to_ascii_lowercase()).cloned());
r.and_then(|r| r.resolve(address))
.ok_or_else(|| ResolveError(address.as_str().to_owned()))
}
}
#[derive(Clone, Default)]
pub struct Transports {
by_type: BTreeMap<String, Arc<dyn Transport>>,
primary: Vec<Arc<dyn Transport>>,
}
impl std::fmt::Debug for Transports {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Transports")
.field("types", &self.by_type.keys().collect::<Vec<_>>())
.finish()
}
}
impl Transports {
pub fn local() -> Self {
let mut t = Transports::default();
t.register(Arc::new(LocalTransport));
t
}
pub fn register(&mut self, t: Arc<dyn Transport>) {
self.by_type.insert(t.type_iri().to_owned(), t.clone());
for a in t.aliases() {
self.by_type.insert(a, t.clone());
}
self.primary.push(t);
}
pub fn get(&self, type_: &str) -> Option<&Arc<dyn Transport>> {
self.by_type.get(type_)
}
pub fn send_types(&self) -> Vec<String> {
self.by_type.keys().cloned().collect()
}
pub fn ioprocessors(&self, address: &Address) -> vertep_core::datamodel::Value {
use vertep_core::datamodel::Value;
let mut entries = Vec::new();
for (name, t) in &self.by_type {
entries.push((
name.clone(),
Value::Object(vec![(
"location".to_owned(),
Value::String(t.location(address)),
)]),
));
}
Value::Object(entries)
}
}