troll-patrol/src/bin/simulation.rs

209 lines
6.0 KiB
Rust
Raw Normal View History

// Before running this, run:
// 1. rdsys
// 2. lox-distributor
// 3. troll-patrol with the feature "simulation"
use troll_patrol::{
extra_info::ExtraInfo,
2024-05-25 17:27:39 -04:00
increment_simulated_date,
simulation::{
bridge::Bridge,
censor::{Censor, Hides::*, Speed::*, Totality::*},
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,
time::Duration,
};
use tokio::{spawn, time::sleep};
#[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:8004".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.clone(),
sharing: config.sharing,
};
let mut rng = rand::thread_rng();
// Set up censors
let mut censors = HashMap::<String, Censor>::new();
for i in 0..config.probs_user_in_country.len() {
let cc = config.probs_user_in_country[i].0.clone();
censors.insert(cc.clone(), Censor::new(cc, Fast, Overt, Full));
}
// 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;
});
sleep(Duration::from_millis(1)).await;
let mut fp = 0;
let mut tp = 0;
// Main loop
2024-05-25 17:27:39 -04:00
for day in 1..=config.num_days {
println!("Starting day {} of the simulation", day);
// 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 = 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 more stats about new blockages
for (bridge, ccs) in new_blockages {
let fingerprint = array_bytes::hex2array(bridge).unwrap();
for cc in ccs {
let censor = censors.get(&cc).unwrap();
if censor.knows_bridge(&fingerprint) {
tp += 1;
} else {
fp += 1;
}
}
}
// 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();
}
println!("True Positives: {}", tp);
println!("False Positives: {}", fp);
}