// Before running this, run: // 1. rdsys // 2. lox-distributor // 3. troll-patrol with the feature "simulation" use troll_patrol::{ extra_info::ExtraInfo, increment_simulated_date, simulation::{bridge::Bridge, censor::Censor, extra_infos_server, state::State, user::User}, }; use clap::Parser; use lox_cli::{networking::*, *}; use rand::Rng; use serde::Deserialize; use std::{ collections::{HashMap, HashSet}, fs::File, io::BufReader, path::PathBuf, }; use tokio::spawn; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { /// Name/path of the configuration file #[arg(short, long, default_value = "simulation_config.json")] config: PathBuf, } #[derive(Debug, Deserialize)] pub struct Config { pub la_port: u16, pub la_test_port: u16, pub tp_port: u16, pub tp_test_port: u16, pub min_new_users_per_day: u32, pub max_new_users_per_day: u32, // How many days to simulate pub num_days: u32, pub prob_connection_fails: f64, pub prob_friend_in_same_country: f64, pub prob_user_invites_friend: f64, pub prob_user_is_censor: f64, pub prob_user_submits_reports: f64, pub probs_user_in_country: Vec<(String, f64)>, pub sharing: bool, } #[tokio::main] pub async fn main() { let args: Args = Args::parse(); let config: Config = serde_json::from_reader(BufReader::new( File::open(&args.config).expect("Could not read config file"), )) .expect("Reading config file from JSON failed"); let la_net = HyperNet { hostname: format!("http://localhost:{}", config.la_port), }; let la_net_test = HyperNet { hostname: format!("http://localhost:{}", config.la_test_port), }; let tp_net = HyperNet { hostname: format!("http://localhost:{}", config.tp_port), }; let tp_net_test = HyperNet { hostname: format!("http://localhost:{}", config.tp_test_port), }; let extra_infos_net = HyperNet { hostname: "http://localhost:8003".to_string(), }; let la_pubkeys = get_lox_auth_keys(&la_net).await; let state = State { la_net, tp_net, la_pubkeys, prob_connection_fails: config.prob_connection_fails, prob_friend_in_same_country: config.prob_friend_in_same_country, prob_user_invites_friend: config.prob_user_invites_friend, prob_user_is_censor: config.prob_user_is_censor, prob_user_submits_reports: config.prob_user_submits_reports, probs_user_in_country: config.probs_user_in_country, sharing: config.sharing, }; let mut rng = rand::thread_rng(); // Set up censors let mut censors = HashMap::::new(); // Set up bridges (no bridges yet) let mut bridges = HashMap::<[u8; 20], Bridge>::new(); // Set up users (no users yet) let mut users = Vec::::new(); // Set up extra-infos server spawn(async move { extra_infos_server::server().await; }); // Main loop for _ in 0..config.num_days { // USER TASKS // Add some new users let num_new_users: u32 = rng.gen_range(config.min_new_users_per_day..=config.max_new_users_per_day); for _ in 0..num_new_users { users.push(User::new(&state).await); } let mut new_users = Vec::::new(); // Users do daily actions for user in &mut users { // TODO: Refactor out connections from return let (mut invited_friends, _connections) = user.daily_tasks(&state, &mut bridges, &mut censors).await; // If this user invited any friends, add them to the list of users new_users.append(&mut invited_friends); } // Add new users users.append(&mut new_users); // CENSOR TASKS for (_, censor) in censors.iter_mut() { censor.end_of_day_tasks(&state, &mut bridges).await; } // BRIDGE TASKS let mut new_extra_infos = HashSet::::new(); for (_, bridge) in bridges.iter_mut() { // Bridge reports its connections for the day new_extra_infos.insert(bridge.gen_extra_info()); // Bridge resets for tomorrow bridge.reset_for_tomorrow(); } // Publish all the bridges' extra-infos for today extra_infos_net .request( "/add".to_string(), serde_json::to_string(&new_extra_infos).unwrap().into(), ) .await; // TROLL PATROL TASKS let new_blockages_resp = tp_net_test.request("/update".to_string(), vec![]).await; let new_blockages: HashMap> = serde_json::from_slice(&new_blockages_resp).unwrap(); // TODO: Track stats about new blockages // LOX AUTHORITY TASKS // Advance LA's time to tomorrow la_net_test .request( "/advancedays".to_string(), serde_json::to_string(&(1 as u16)).unwrap().into(), ) .await; // SIMULATION TASKS // Advance simulated time to tomorrow increment_simulated_date(); } }