179 lines
5.2 KiB
Rust
179 lines
5.2 KiB
Rust
|
// 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::<String, Censor>::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::<User>::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::<User>::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::<ExtraInfo>::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<String, HashSet<String>> =
|
||
|
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();
|
||
|
}
|
||
|
}
|