extern crate djinn;
extern crate redis;
extern crate rustc_serialize;
use std::thread;
use redis::{Client, Commands};
use djinn::{Agent, Manager, Simulation, Population, Updates, Redis, WebSocketServer, run};
const HEALTH_START: usize = 10;
const HEALTH_CHANGE: usize = 10;
#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq, Clone)]
pub struct State {
health: usize,
}
#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq, Clone)]
pub struct World {
weather: String,
}
#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq, Clone)]
pub enum Update {
ChangeHealth(usize),
}
#[derive(Clone)]
pub struct BasicSim;
impl Simulation for BasicSim {
type State = State;
type Update = Update;
type World = World;
fn decide<R: Redis>(&self,
agent: &Agent<Self::State>,
world: &Self::World,
population: &Population<Self, R>,
updates: &mut Updates<Self>)
-> () {
updates.queue(agent.id, Update::ChangeHealth(HEALTH_CHANGE));
}
fn update(&self, mut state: &mut Self::State, updates: Vec<Self::Update>) -> bool {
let updated = updates.len() > 0;
for update in updates {
match update {
Update::ChangeHealth(health) => {
state.health += health;
}
}
}
updated
}
}
fn main() {
let sim = BasicSim {};
let world = World { weather: "sunny".to_string() };
let addr = "redis://127.0.0.1/";
let client = Client::open(addr).unwrap();
let mut manager = Manager::new(addr, client, sim.clone());
manager.spawn(State { health: 0 });
let id = manager.spawn(State { health: HEALTH_START });
let mut ws = WebSocketServer::new("127.0.0.1:3012", addr);
ws.start();
thread::sleep_ms(2000);
let n_steps = 10;
let log_t = thread::spawn(move || {
let client = Client::open(addr).unwrap();
let mut pubsub = client.get_pubsub().unwrap();
pubsub.subscribe("weather").unwrap();
for step in 0..n_steps {
let msg = pubsub.get_message().unwrap();
let payload: String = msg.get_payload().unwrap();
println!("[{:02}] This step's weather is {}", step, payload);
}
});
manager.register_reporter(1, |step, pop, conn| {
let world = pop.world();
let _: () = conn.publish("weather", world.weather.clone()).unwrap();
let _: () = conn.publish("ws", world.weather.clone()).unwrap();
});
manager = run(sim, world, manager, 4, n_steps);
log_t.join().unwrap();
let agent = match manager.population.get_agent(id) {
Some(a) => a,
None => panic!("Couldn't find the agent"),
};
println!("{:?}", agent);
assert_eq!(agent.state.health, HEALTH_START + (HEALTH_CHANGE * n_steps));
ws.shutdown();
}