use crate::core::ctx::Ctx;
use crate::core::engine::Engine;
use crate::middleware::SpawnerLayer;
use crate::store::output::OutputRef;
use crate::types::{CapToken, TaskId};
use crate::worker::adapter::{SpawnError, SpawnerAdapter};
use crate::worker::Worker;
use async_trait::async_trait;
use serde_json::Value;
use std::sync::Arc;
pub const INPUT_REFS_KEY: &str = "input_refs";
pub struct InputInjectMiddleware {
refs: Vec<OutputRef>,
}
impl InputInjectMiddleware {
pub fn new(refs: Vec<OutputRef>) -> Self {
Self { refs }
}
pub fn refs(&self) -> &[OutputRef] {
&self.refs
}
}
impl SpawnerLayer for InputInjectMiddleware {
fn wrap(&self, inner: Arc<dyn SpawnerAdapter>) -> Arc<dyn SpawnerAdapter> {
Arc::new(InputInjectWrapped {
inner,
refs: self.refs.clone(),
})
}
}
struct InputInjectWrapped {
inner: Arc<dyn SpawnerAdapter>,
refs: Vec<OutputRef>,
}
#[async_trait]
impl SpawnerAdapter for InputInjectWrapped {
async fn spawn(
&self,
engine: &Engine,
ctx: &Ctx,
task_id: TaskId,
attempt: u32,
token: CapToken,
) -> Result<Box<dyn Worker>, SpawnError> {
let mut new_ctx = ctx.clone();
let refs_json: Vec<Value> = self
.refs
.iter()
.map(|r| Value::String(r.0.clone()))
.collect();
new_ctx
.meta
.runtime
.insert(INPUT_REFS_KEY.to_string(), Value::Array(refs_json));
self.inner
.spawn(engine, &new_ctx, task_id, attempt, token)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_layer_holds_refs() {
let r1 = OutputRef::new();
let r2 = OutputRef::new();
let layer = InputInjectMiddleware::new(vec![r1.clone(), r2.clone()]);
assert_eq!(layer.refs(), &[r1, r2]);
}
#[test]
fn empty_refs_are_valid() {
let layer = InputInjectMiddleware::new(vec![]);
assert!(layer.refs().is_empty());
}
}