use super::super::{GenerationStateAccess, transport};
use super::*;
use super::{edges::Edge, output::Client};
use crate::{
capability::{StateStore, Upstream},
transform::{Converted, Report},
};
use std::collections::BTreeSet;
impl<A: Edge> Fanout<A> {
pub(super) async fn run<U: Upstream, S: StateStore>(
&mut self,
upstream: (&U, &U::Target),
limits: CodecLimits,
_state: &GenerationStateAccess<'_, S>,
progress: &mut FanoutProgress<A::Native>,
mut facts: impl FnMut(usize, &A::Native) -> Result<A::Facts, TransformError>,
) -> Result<Converted<A::Client>, TransformError> {
let (upstream, target) = upstream;
if self.children.len() < 2 {
return Err(limit());
}
for child in &self.children {
if encode(child.request(), limits)?.len() as u64 > upstream.limits().write_bytes {
return Err(limit());
}
}
if self.started || !progress.children.is_empty() {
return Err(conflict(
"fanout already started; a started POST is never repeated",
));
}
self.started = true;
progress.children = (0..self.children.len())
.map(|_| GenerationProgress::default())
.collect();
for index in 0..self.children.len() {
let sent = transport::send(
upstream,
target,
self.endpoint.clone(),
self.children[index].request().clone(),
limits,
&mut progress.children[index],
)
.await?;
if !sent {
return Err(TransformError::invalid_result(
"fanout.child",
format!(
"child {index} rejected the request; native HTTP result retained, group is incomplete"
),
));
}
}
let mut report = Report::default();
let mut mapped = Vec::new();
let mut natives = Vec::new();
let mut seen = BTreeSet::new();
for (index, child) in self.children.iter_mut().enumerate() {
let native = transport::recover_native(&mut progress.children[index], limits)?;
let supplied = facts(index, &native)?;
let converted = child.convert(native.clone(), supplied)?;
report
.diagnostics
.extend(child.report().diagnostics.clone());
report.diagnostics.extend(converted.report.diagnostics);
mapped.push(converted.value);
natives.push(native);
}
for (index, (native, client)) in natives.iter().zip(&mut mapped).enumerate() {
output::normalize(native, client, self.children[index].identities(), &mut seen)?;
}
let value = A::Client::aggregate(mapped, self.group_id.clone(), &mut report)?;
encode(&value, limits)?;
Ok(Converted { value, report })
}
}