use std::collections::VecDeque;
use arbiter_core::{database::ArbiterDB, environment::Environment, middleware::ArbiterMiddleware};
use futures_util::future::join_all;
use serde::de::DeserializeOwned;
use tokio::spawn;
use super::*;
use crate::{
agent::{Agent, AgentBuilder},
machine::{CreateStateMachine, MachineInstruction},
};
#[derive(Debug)]
pub struct World {
pub id: String,
pub agents: Option<HashMap<String, Agent>>,
pub environment: Option<Environment>,
pub messager: Messager,
}
use std::{fs::File, io::Read};
impl World {
pub fn new(id: &str) -> Self {
Self {
id: id.to_owned(),
agents: Some(HashMap::new()),
environment: Some(Environment::builder().build()),
messager: Messager::new(),
}
}
pub fn from_config<C: CreateStateMachine + Serialize + DeserializeOwned + Debug>(
config_path: &str,
) -> Result<Self, ArbiterEngineError> {
let cwd = std::env::current_dir()?;
let path = cwd.join(config_path);
info!("Reading from path: {:?}", path);
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
#[derive(Deserialize)]
struct Config<C> {
id: Option<String>,
#[serde(flatten)]
agents_map: HashMap<String, Vec<C>>,
}
let config: Config<C> = toml::from_str(&contents)?;
let mut world = World::new(&config.id.unwrap_or_else(|| "world".to_owned()));
for (agent, behaviors) in config.agents_map {
let mut next_agent = Agent::builder(&agent);
for behavior in behaviors {
let engine = behavior.create_state_machine();
next_agent = next_agent.with_engine(engine);
}
world.add_agent(next_agent);
}
Ok(world)
}
pub fn add_agent(&mut self, agent_builder: AgentBuilder) {
let id = agent_builder.id.clone();
let client = ArbiterMiddleware::new(self.environment.as_ref().unwrap(), Some(&id))
.expect("Failed to create RevmMiddleware client for agent");
let messager = self.messager.for_agent(&id);
let agent = agent_builder
.build(client, messager)
.expect("Failed to build agent from AgentBuilder");
let agents = self
.agents
.as_mut()
.expect("Agents collection not initialized");
agents.insert(id.to_owned(), agent);
}
pub async fn run(&mut self) -> Result<ArbiterDB, ArbiterEngineError> {
let agents = match self.agents.take() {
Some(agents) => agents,
None => {
return Err(ArbiterEngineError::WorldError(
"No agents found. Has the world already been ran?".to_owned(),
))
}
};
let mut tasks = vec![];
let mut messagers = VecDeque::new();
for (_, agent) in agents.iter() {
for _ in &agent.behavior_engines {
messagers.push_back(agent.messager.clone());
}
}
for (_, mut agent) in agents {
for mut engine in agent.behavior_engines.drain(..) {
let client = agent.client.clone();
let messager = messagers.pop_front().unwrap();
tasks.push(spawn(async move {
engine
.execute(MachineInstruction::Start(client, messager))
.await
}));
}
}
join_all(tasks).await;
let db = self.environment.take().unwrap().stop()?;
Ok(db)
}
}