use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use super::Source;
use crate::builder::{AimDb, BoxFuture};
use crate::router::RouterBuilder;
use crate::transport::{Connector, ConnectorConfig};
pub fn pump_sink(db: &AimDb, scheme: &str, sink: Arc<dyn Connector>) -> Vec<BoxFuture> {
let routes = db.collect_outbound_routes(scheme);
let mut futures: Vec<BoxFuture> = Vec::with_capacity(routes.len());
for crate::OutboundRoute {
topic: default_topic,
source,
config,
} in routes
{
let sink = sink.clone();
let runtime_ctx = db.runtime_ctx();
let cfg = ConnectorConfig::from_query(&config);
let scratch_capacity = source.serializer_scratch_capacity().unwrap_or(0);
futures.push(Box::pin(async move {
let mut reader = source.subscribe();
let mut scratch = vec![0_u8; scratch_capacity];
log_info!(
"pump_sink: publisher started for destination: {}",
default_topic
);
loop {
let msg = match reader
.recv_into(&runtime_ctx, scratch.as_mut_slice())
.await
{
Ok(m) => m,
Err(crate::DbError::BufferLagged { .. }) => {
log_warn!("pump_sink: consumer lagged for '{}'", default_topic);
continue;
}
Err(_e) => {
log_info!(
"pump_sink: publisher stopping for '{}': {:?}",
default_topic,
_e
);
break;
}
};
let crate::connector::SerializedValueInto { dest, payload } = msg;
let dest = dest.as_deref().unwrap_or(&default_topic);
let payload = match &payload {
crate::connector::SerializedPayload::Scratch { len } => {
let Some(payload) = scratch.get(..*len) else {
log_error!(
"pump_sink: serializer returned invalid length {} for {}-byte scratch buffer",
len,
scratch.len()
);
continue;
};
payload
}
crate::connector::SerializedPayload::Owned(payload) => payload.as_slice(),
};
if let Err(_e) = sink.publish(dest, &cfg, payload).await {
log_error!("pump_sink: failed to publish to '{}': {:?}", dest, _e);
} else {
log_debug!("pump_sink: published to: {}", dest);
}
}
log_info!(
"pump_sink: publisher stopped for destination: {}",
default_topic
);
}));
}
futures
}
pub fn pump_source(db: &AimDb, scheme: &str, mut src: impl Source + 'static) -> Vec<BoxFuture> {
let routes = db.collect_inbound_routes(scheme);
let router = Arc::new(RouterBuilder::from_routes(routes).build());
let ctx = db.runtime_ctx();
vec![Box::pin(async move {
log_info!(
"pump_source: reader started ({} topics)",
router.resource_ids().len()
);
while let Some((topic, payload)) = src.next().await {
if let Err(_e) = router.route(&topic, &payload, &ctx) {
log_error!(
"pump_source: failed to route message on '{}': {}",
topic,
_e
);
}
}
log_info!("pump_source: reader stopped");
})]
}