use anyhow::Result;
use geohash::Coord;
use kdam::tqdm;
use rand::distributions::{Alphanumeric, DistString};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use std::time::Instant;
extern crate libreloc_server;
use libreloc_server::datastore;
use libreloc_server::datastore::*;
use libreloc_shared::*;
const GLOBAL_DP_CNT: u32 = 1_000_000;
const BOB_N: usize = 18;
const BOB_ALI_N: usize = 10;
const ALI_N: usize = 10;
fn t(t0: Instant) -> Instant {
println!("Done in [{:6}ms]", t0.elapsed().as_millis());
Instant::now()
}
fn haversine_distance2(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 {
let lat1_rad = lat1.to_radians();
let lat2_rad = lat2.to_radians();
let dlat = lat2_rad - lat1_rad;
let dlon = lon2.to_radians() - lon1.to_radians();
let a =
(dlat / 2.0).sin().powi(2) + lat1_rad.cos() * lat2_rad.cos() * (dlon / 2.0).sin().powi(2);
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
let earth_radius_m = 6371000.0;
earth_radius_m * c
}
fn store(ds: &mut datastore::MemDatastore, lat: f64, lon: f64, mac: &Mac, ssid: &str) {
ds.insert_datapoint(lat, lon, mac, ssid);
}
fn generate_random_worldwide_blips(
ds: &mut MemDatastore,
rng: &mut StdRng,
t0: &mut Instant,
amount: u32,
) {
for _ in tqdm!(0..amount) {
let lat = rng.gen_range(-90.0..=90.0);
let lon = rng.gen_range(-180.0..=180.0);
let mac: Mac = rng.gen();
let ssid = Alphanumeric.sample_string(rng, 16);
store(ds, lat, lon, &mac, &ssid);
}
println!(
"{} writes per second",
GLOBAL_DP_CNT as f32 / t0.elapsed().as_secs_f32()
);
}
fn generate_random_localized_blips(
ds: &mut MemDatastore,
rng: &mut StdRng,
center: &Coord,
) -> Blips {
let mut bob_blips: Blips = vec![];
for _ in 0..BOB_N {
let r = 0.0003;
let pos = Coord {
x: center.x + rng.gen_range(-r..r),
y: center.y + rng.gen_range(-r..r),
};
let mac: Mac = rng.gen();
let ssid = Alphanumeric.sample_string(rng, 16);
store(ds, pos.y, pos.x, &mac, &ssid);
bob_blips.push((pos, mac, ssid));
}
bob_blips
}
#[tokio::main]
async fn main() -> Result<()> {
let mut t0 = Instant::now();
let mut rng: StdRng = SeedableRng::seed_from_u64(3);
let recreate = true;
println!("Open datastore");
let mut ds = datastore::open_mem_datastore();
if recreate {
t0 = t(t0);
generate_random_worldwide_blips(&mut ds, &mut rng, &mut t0, 1000);
t0 = t(t0);
};
println!("Bob uploads data from devices around home: https://geohash.jorren.nl/#sr2y7gt");
let bob_pos = Coord {
x: 12.477082,
y: 41.899386,
};
let bob_blips = generate_random_localized_blips(&mut ds, &mut rng, &bob_pos);
t0 = t(t0);
println!("Alices visit Bob and runs geolocation");
let alice_blips: Blips = {
let mut alice_blips: Blips = vec![];
for b in bob_blips {
alice_blips.push(b);
if alice_blips.len() >= BOB_ALI_N {
break;
}
}
for _ in 0..ALI_N {
let r = 0.0002;
let pos = Coord {
x: bob_pos.x + rng.gen_range(-r..r),
y: bob_pos.y + rng.gen_range(-r..r),
};
let mac: Mac = rng.gen();
let ssid = Alphanumeric.sample_string(&mut rng, 16);
alice_blips.push((pos, mac, ssid));
}
alice_blips
};
let ali_real_pos = Coord {
x: bob_pos.x + 0.0001,
y: bob_pos.y + 0.0001,
};
println!("Populating dataset with random data using a fixed seed");
let mut tot_blips_cnt = 1000;
let mut increase = 512;
while tot_blips_cnt < GLOBAL_DP_CNT {
let mut geopath = "".to_string();
for step in 0..4 {
let (sel, segment) = lookup_step(&ds.wifi_bt_bh, &alice_blips, &geopath);
geopath.push_str(&segment);
let dist = haversine_distance_gh(&ali_real_pos, &geopath);
println!(
"Alice zooms in to https://geohash.jorren.nl/#{:<10} Sel {:<2} Distance: {:<8}",
geopath,
(sel * 100.0) as u8,
dist
);
}
generate_random_worldwide_blips(&mut ds, &mut rng, &mut t0, increase);
tot_blips_cnt += increase;
increase *= 2;
}
println!("SUCCESS");
t(t0);
Ok(())
}