diff --git a/Cargo.lock b/Cargo.lock index 511685a..f3a7857 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1057,6 +1057,7 @@ dependencies = [ "chrono", "clap", "futures", + "hex", "hex_fmt", "hyper", "julianday", diff --git a/crates/lox-distributor/Cargo.toml b/crates/lox-distributor/Cargo.toml index c81c8d0..e58f268 100644 --- a/crates/lox-distributor/Cargo.toml +++ b/crates/lox-distributor/Cargo.toml @@ -18,6 +18,7 @@ readme = "README.md" julianday = "1.2.0" base64 = "0.21.7" hyper = { version = "0.14.28", features = ["deprecated", "backports","server"] } +hex = "0.4.3" hex_fmt = "0.3" futures = "0.3.30" time = "0.3.36" diff --git a/crates/lox-distributor/src/fake_resource_state.rs b/crates/lox-distributor/src/fake_resource_state.rs new file mode 100644 index 0000000..096e816 --- /dev/null +++ b/crates/lox-distributor/src/fake_resource_state.rs @@ -0,0 +1,151 @@ +use crate::resource_parser::ACCEPTED_HOURS_OF_FAILURE; +use chrono::{Duration, Utc}; +use rand::{Rng, RngCore}; +use rdsys_backend::proto::{Resource, ResourceState, TestResults}; +use std::collections::HashMap; + +#[derive(Default)] +pub struct TestResourceState { + pub rstate: ResourceState, +} + +impl TestResourceState { + + // A previously working resources become not_working but within accepted failure time + pub fn working_with_accepted_failures(&mut self) { + match &mut self.rstate.working { + Some(resources) => { + if let Some(resource) = resources.pop() { + self.add_not_working_to_rstate(resource) + } + } + None => { + panic!("rstate.working Empty") + } + } + + assert_ne!(self.rstate.working, None); + assert_eq!(self.rstate.not_working, None); + } + + // Block resources that are working. Targeted blocked regions are specified in bridge_config.json + pub fn block_working(&mut self) { + match &mut self.rstate.working { + Some(resources) => { + for resource in resources { + resource.blocked_in = HashMap::from([ + ("AS".to_owned(), true), + ("IR".to_owned(), false), + ("RU".to_owned(), false), + ("CN".to_owned(), false), + ("SA".to_owned(), false), + ]); + } + } + None => { + panic!("rstate.working Empty") + } + } + assert_ne!(self.rstate.working, None); + assert_eq!(self.rstate.not_working, None); + } + + // Add a resource that is working + pub fn add_working_resource(&mut self) { + let working_resource = make_resource( + HashMap::from([ + ("AS".to_owned(), false), + ("IR".to_owned(), false), + ("RU".to_owned(), false), + ("CN".to_owned(), false), + ("SA".to_owned(), false), + ]), + ACCEPTED_HOURS_OF_FAILURE - 12, + ); + self.add_working_to_rstate(working_resource); + } + + // Add a not-working resource that has been failing for 1 hour longer than the accepted threshold + pub fn add_not_working_resource(&mut self) { + let not_working_resource = make_resource( + HashMap::from([ + ("AS".to_owned(), false), + ("IR".to_owned(), false), + ("RU".to_owned(), false), + ("CN".to_owned(), false), + ("SA".to_owned(), false), + ]), + ACCEPTED_HOURS_OF_FAILURE + 1, + ); + self.add_not_working_to_rstate(not_working_resource); + } + + // Add resource to rstate's working field + pub fn add_working_to_rstate(&mut self, working_resource: Resource) { + match &mut self.rstate.working { + Some(resources) => { + resources.push(working_resource); + } + None => { + self.rstate.working = Some(vec![working_resource]); + } + } + } + + // Add resource to rstate's not_working field + pub fn add_not_working_to_rstate(&mut self, not_working_resource: Resource) { + match &mut self.rstate.not_working { + Some(resources) => { + resources.push(not_working_resource); + } + None => { + self.rstate.not_working = Some(vec![not_working_resource]); + } + } + } +} + +pub fn make_resource(blocked_in: HashMap, last_passed: i64) -> Resource { + let mut flags = HashMap::new(); + flags.insert(String::from("fast"), true); + flags.insert(String::from("stable"), true); + let mut params = HashMap::new(); + params.insert( + String::from("password"), + String::from("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), + ); + Resource { + r#type: String::from("obfs4"), + blocked_in, + test_result: TestResults { + last_passed: Utc::now() - Duration::hours(last_passed), + }, + protocol: String::from("tcp"), + address: gen_ip(), + port: gen_port(), + fingerprint: gen_fingerprint(), + or_addresses: None, + distribution: String::from("https"), + flags: Some(flags), + params: Some(params), + } +} + +pub fn gen_fingerprint() -> String { + let mut rng = rand::thread_rng(); + let mut fingerprint_array: [u8; 16] = [0; 16]; + rng.fill_bytes(&mut fingerprint_array); + hex::encode_upper(fingerprint_array) +} + +pub fn gen_port() -> u16 { + rand::thread_rng().gen_range(0..u16::MAX) +} + +pub fn gen_ip() -> String { + let i = rand::thread_rng().gen_range(1..u8::MAX); + let ii = rand::thread_rng().gen_range(1..u8::MAX); + let iii = rand::thread_rng().gen_range(1..u8::MAX); + let iv = rand::thread_rng().gen_range(1..u8::MAX); + format!("{}.{}.{}.{}", i, ii, iii, iv) +} diff --git a/crates/lox-distributor/src/main.rs b/crates/lox-distributor/src/main.rs index 5ca5b96..66a9338 100644 --- a/crates/lox-distributor/src/main.rs +++ b/crates/lox-distributor/src/main.rs @@ -21,6 +21,7 @@ use std::{ mod db_handler; use db_handler::DB; +mod fake_resource_state; mod lox_context; mod metrics; use metrics::Metrics; diff --git a/crates/rdsys-backend-api/src/proto.rs b/crates/rdsys-backend-api/src/proto.rs index 7ce41e9..dfaa46f 100644 --- a/crates/rdsys-backend-api/src/proto.rs +++ b/crates/rdsys-backend-api/src/proto.rs @@ -57,7 +57,7 @@ impl Resource { } /// A ResourceState holds information about new, changed, or pruned resources -#[derive(Deserialize, PartialEq, Eq, Debug)] +#[derive(Deserialize, Default, PartialEq, Eq, Debug)] pub struct ResourceState { pub working: Option>, pub not_working: Option>,