use std::vec;
use async_trait::async_trait;
use modular_agent_macros::modular_agent;
use crate::agent::{Agent, AgentData, AsAgent};
use crate::context::AgentContext;
use crate::error::AgentError;
use crate::modular_agent::ModularAgent;
use crate::spec::AgentSpec;
use crate::value::AgentValue;
const CATEGORY: &str = "Core/IO";
const PORT_VALUE: &str = "value";
const CONFIG_NAME: &str = "name";
#[modular_agent(
kind = "External",
title = "->ExtOut",
category = CATEGORY,
inputs = [PORT_VALUE],
string_config(
name = CONFIG_NAME,
)
)]
struct ExternalOutputAgent {
data: AgentData,
channel_name: Option<String>,
}
#[async_trait]
impl AsAgent for ExternalOutputAgent {
fn new(ma: ModularAgent, id: String, spec: AgentSpec) -> Result<Self, AgentError> {
let channel_name = spec
.configs
.as_ref()
.and_then(|c| c.get_string(CONFIG_NAME).ok());
Ok(Self {
data: AgentData::new(ma, id, spec),
channel_name,
})
}
fn configs_changed(&mut self) -> Result<(), AgentError> {
self.channel_name = self.configs()?.get_string(CONFIG_NAME).ok();
Ok(())
}
async fn process(
&mut self,
ctx: AgentContext,
_port: String,
value: AgentValue,
) -> Result<(), AgentError> {
let channel_name = self.channel_name.clone().unwrap_or_default();
if channel_name.is_empty() {
return Ok(());
}
let ma = self.ma();
ma.send_external_output(channel_name.clone(), ctx, value.clone())
.await?;
Ok(())
}
}
#[modular_agent(
kind = "External",
title = "ExtIn->",
category = CATEGORY,
outputs = [PORT_VALUE],
string_config(
name = CONFIG_NAME,
)
)]
struct ExternalInputAgent {
data: AgentData,
channel_name: Option<String>,
}
#[async_trait]
impl AsAgent for ExternalInputAgent {
fn new(ma: ModularAgent, id: String, spec: AgentSpec) -> Result<Self, AgentError> {
let channel_name = spec
.configs
.as_ref()
.and_then(|c| c.get_string(CONFIG_NAME).ok());
Ok(Self {
data: AgentData::new(ma, id, spec),
channel_name,
})
}
async fn start(&mut self) -> Result<(), AgentError> {
if let Some(channel_name) = &self.channel_name {
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(channel_name) {
nodes.push(self.data.id.clone());
} else {
external_input_agents.insert(channel_name.clone(), vec![self.data.id.clone()]);
}
}
Ok(())
}
async fn stop(&mut self) -> Result<(), AgentError> {
if let Some(channel_name) = &self.channel_name {
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(channel_name) {
nodes.retain(|x| x != &self.data.id);
}
}
Ok(())
}
fn configs_changed(&mut self) -> Result<(), AgentError> {
let channel_name = self.configs()?.get_string(CONFIG_NAME).ok();
if self.channel_name != channel_name {
if let Some(channel_name) = &self.channel_name {
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(channel_name) {
nodes.retain(|x| x != &self.data.id);
}
}
if let Some(channel_name) = &channel_name {
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(channel_name) {
nodes.push(self.data.id.clone());
} else {
external_input_agents.insert(channel_name.clone(), vec![self.data.id.clone()]);
}
}
self.channel_name = channel_name;
}
Ok(())
}
}
#[modular_agent(
kind = "Local",
title = "->LocalOut",
category = CATEGORY,
inputs = [PORT_VALUE],
string_config(
name = CONFIG_NAME,
)
)]
struct LocalOutputAgent {
data: AgentData,
var_name: Option<String>,
}
#[async_trait]
impl AsAgent for LocalOutputAgent {
fn new(ma: ModularAgent, id: String, spec: AgentSpec) -> Result<Self, AgentError> {
let var_name = spec
.configs
.as_ref()
.and_then(|c| c.get_string(CONFIG_NAME).ok());
Ok(Self {
data: AgentData::new(ma, id, spec),
var_name,
})
}
fn configs_changed(&mut self) -> Result<(), AgentError> {
self.var_name = self.configs()?.get_string(CONFIG_NAME).ok();
Ok(())
}
async fn process(
&mut self,
ctx: AgentContext,
_port: String,
value: AgentValue,
) -> Result<(), AgentError> {
let var_name = self.var_name.clone().unwrap_or_default();
if var_name.is_empty() {
return Ok(());
}
let channel_name = channel_name_for_local(self.preset_id(), &var_name);
let ma = self.ma();
ma.send_external_output(channel_name.clone(), ctx, value.clone())
.await?;
Ok(())
}
}
#[modular_agent(
kind = "Local",
title = "LocalIn->",
category = CATEGORY,
outputs = [PORT_VALUE],
string_config(
name = CONFIG_NAME,
)
)]
struct LocalInputAgent {
data: AgentData,
var_name: Option<String>,
}
#[async_trait]
impl AsAgent for LocalInputAgent {
fn new(ma: ModularAgent, id: String, spec: AgentSpec) -> Result<Self, AgentError> {
let var_name = spec
.configs
.as_ref()
.and_then(|c| c.get_string(CONFIG_NAME).ok());
Ok(Self {
data: AgentData::new(ma, id, spec),
var_name,
})
}
async fn start(&mut self) -> Result<(), AgentError> {
if let Some(var_name) = &self.var_name {
let channel_name = channel_name_for_local(self.preset_id(), var_name);
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(&channel_name) {
nodes.push(self.data.id.clone());
} else {
external_input_agents.insert(channel_name.clone(), vec![self.data.id.clone()]);
}
}
Ok(())
}
async fn stop(&mut self) -> Result<(), AgentError> {
if let Some(var_name) = &self.var_name {
let channel_name = channel_name_for_local(self.preset_id(), var_name);
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(&channel_name) {
nodes.retain(|x| x != &self.data.id);
}
}
Ok(())
}
fn configs_changed(&mut self) -> Result<(), AgentError> {
let new_var_name = self.configs()?.get_string(CONFIG_NAME).ok();
if self.var_name != new_var_name {
if let Some(var_name) = &self.var_name {
let channel_name = channel_name_for_local(self.preset_id(), var_name);
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(&channel_name) {
nodes.retain(|x| x != &self.data.id);
}
}
if let Some(var_name) = &new_var_name {
let channel_name = channel_name_for_local(self.preset_id(), var_name);
let ma = self.ma();
let mut external_input_agents = ma.external_input_agents.lock().unwrap();
if let Some(nodes) = external_input_agents.get_mut(&channel_name) {
nodes.push(self.data.id.clone());
} else {
external_input_agents.insert(channel_name.clone(), vec![self.data.id.clone()]);
}
}
self.var_name = new_var_name;
}
Ok(())
}
}
fn channel_name_for_local(flow_id: &str, var_name: &str) -> String {
format!("%{}/{}", flow_id, var_name)
}