use std::sync::Arc;
use dashmap::DashMap;
use eyre::Result;
use crate::{
node::base::BaseNode,
types::{ActionKey, DEFAULT_ACTION, Params, SharedState},
};
pub struct Flow {
params: Params,
pub(crate) start_node: Option<Arc<dyn BaseNode>>,
node_map: DashMap<ActionKey, Arc<dyn BaseNode>>,
}
impl Default for Flow {
fn default() -> Self {
Self::new()
}
}
impl Flow {
pub fn new() -> Self {
Self {
params: Default::default(),
start_node: None,
node_map: Default::default(),
}
}
pub fn set_params(&mut self, params: Params) -> &mut Self {
self.params = params;
self
}
pub fn start(&mut self, node: Arc<dyn BaseNode>) -> &mut Self {
self.start_node = Some(node);
self
}
pub fn get_node(&self, action: &str) -> Option<Arc<dyn BaseNode>> {
self.node_map.get(action).map(|node| node.clone())
}
pub fn run(&self, shared: &SharedState) -> Result<String> {
let start_node = self
.start_node
.as_ref()
.ok_or_else(|| eyre::eyre!("Flow has no start node"))?;
let mut current_node = start_node.clone();
let _params = self.params.clone();
let mut prep_res = current_node.prep(shared)?;
let mut exec_res = current_node.exec(&prep_res)?;
let mut action_result = current_node.post(shared, &prep_res, &exec_res)?;
loop {
let next_node_key = if action_result.is_empty() {
DEFAULT_ACTION.to_string()
} else {
action_result.clone()
};
let next_node_opt = self.node_map.get(&next_node_key).map(|node| node.clone());
if next_node_opt.is_none() {
break;
}
current_node = next_node_opt.expect("Next node not found in flow");
prep_res = current_node.prep(shared)?;
exec_res = current_node.exec(&prep_res)?;
action_result = current_node.post(shared, &prep_res, &exec_res)?;
}
Ok(action_result)
}
}
pub struct BatchFlow {
pub(crate) inner: Flow,
}
impl Default for BatchFlow {
fn default() -> Self {
Self::new()
}
}
impl BatchFlow {
pub fn new() -> Self {
Self { inner: Flow::new() }
}
pub fn set_params(&mut self, params: Params) -> &mut Self {
self.inner.set_params(params);
self
}
pub fn start(&mut self, node: Arc<dyn BaseNode>) -> &mut Self {
self.inner.start(node);
self
}
pub fn run(&self, shared: &SharedState) -> Result<String> {
let prep_res = self
.inner
.start_node
.as_ref()
.ok_or_else(|| eyre::eyre!("BatchFlow has no start node"))?
.prep(shared)?;
let batch_items = prep_res
.as_array()
.ok_or_else(|| eyre::eyre!("BatchFlow prep must return an array"))?;
for item in batch_items {
let mut params = self.inner.params.clone();
if let Some(item_obj) = item.as_object() {
for (k, v) in item_obj {
params.insert(k.clone(), v.clone());
}
}
self.inner.run(shared)?;
}
Ok(DEFAULT_ACTION.to_string())
}
}