Add distance calculation

This commit is contained in:
drobson03 2021-10-03 21:52:23 +10:00
parent a3cf82135f
commit 0ff5d01c94
6 changed files with 86 additions and 5 deletions

View file

@ -1,3 +1,5 @@
IPINFO_TOKEN=<your ipinfo token> IPINFO_TOKEN=<your ipinfo token>
SERVER_LATITUDE=1
SERVER_LONGITUDE=1
ROCKET_PORT=8000 ROCKET_PORT=8000
ROCKET_ADDRESS=0.0.0.0 ROCKET_ADDRESS=0.0.0.0

7
Cargo.lock generated
View file

@ -711,6 +711,12 @@ dependencies = [
"ahash", "ahash",
] ]
[[package]]
name = "haversine"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef9482608b217d89a3caeb5fe2336a0491d1dc0be5d89c67125ea514b1f6a660"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.19"
@ -1943,6 +1949,7 @@ name = "speedtest-rs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dotenv", "dotenv",
"haversine",
"ipinfo", "ipinfo",
"rand 0.8.4", "rand 0.8.4",
"regex", "regex",

View file

@ -14,3 +14,4 @@ ipinfo = "0.2.0"
serde_with = { version = "1.10.0", features = ["json"] } serde_with = { version = "1.10.0", features = ["json"] }
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "a062933" } rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "a062933" }
dotenv = "0.15.0" dotenv = "0.15.0"
haversine = "0.2.1"

View file

@ -14,7 +14,7 @@ Supported by all Librespeed frontends, though some features are missing (see bel
- [x] IP Address, ISP - [x] IP Address, ISP
- [x] Multiple Points of Test (optional) - [x] Multiple Points of Test (optional)
- [x] Compatible with PHP frontend predefined endpoints (with `.php` suffixes) - [x] Compatible with PHP frontend predefined endpoints (with `.php` suffixes)
- [ ] Distance from server (optional) - [x] Distance from server (optional)
- [ ] Telemetry (optional) - [ ] Telemetry (optional)
- [ ] Results sharing (optional) - [ ] Results sharing (optional)
- [ ] [Proxy Protocol](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt)? - [ ] [Proxy Protocol](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt)?
@ -55,6 +55,10 @@ cargo build --release
```sh ```sh
# your ipinfo.io API token # your ipinfo.io API token
IPINFO_TOKEN= IPINFO_TOKEN=
# your server's latitude
SERVER_LATITUDE=1
# your server's longitude
SERVER_LONGITUDE=1
# the port to bind to # the port to bind to
ROCKET_PORT=8000 ROCKET_PORT=8000
# the bind address (0.0.0.0 is all interfaces) # the bind address (0.0.0.0 is all interfaces)

View file

@ -2,11 +2,11 @@ use ipinfo::{IpDetails, IpInfo, IpInfoConfig};
use regex::Regex; use regex::Regex;
use rocket::serde::{json::Json, Serialize}; use rocket::serde::{json::Json, Serialize};
use rocket_client_addr::ClientRealAddr; use rocket_client_addr::ClientRealAddr;
use std::env::var; use std::env::var;
use std::fmt;
use crate::serialized_ip_info::IpDetailsDef; use crate::serialized_ip_info::IpDetailsDef;
use crate::util::get_ip_type; use crate::util::{get_client_server_distance_string, get_ip_type};
#[derive(FromFormField, PartialEq)] #[derive(FromFormField, PartialEq)]
pub enum Distance { pub enum Distance {
@ -15,7 +15,16 @@ pub enum Distance {
Nm, Nm,
} }
#[allow(dead_code)] impl fmt::Display for Distance {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Distance::Km => write!(f, "km"),
Distance::Mi => write!(f, "mi"),
Distance::Nm => write!(f, "NM"),
}
}
}
#[derive(FromForm)] #[derive(FromForm)]
pub struct GetIPOptions { pub struct GetIPOptions {
#[field(default = true)] #[field(default = true)]
@ -69,6 +78,11 @@ pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<Ge
isp = format!("{}, {}", &isp, &ipinfo.country); isp = format!("{}, {}", &isp, &ipinfo.country);
} }
if !ipinfo.loc.is_empty() {
let distance = get_client_server_distance_string(ipinfo.loc, opts.distance);
isp = format!("{} ({})", &isp, &distance);
}
result.processed_string = Some(format!("{} - {}", &result.processed_string.unwrap(), &isp)); result.processed_string = Some(format!("{} - {}", &result.processed_string.unwrap(), &isp));
} }

View file

@ -1,5 +1,10 @@
use std::env::var;
use haversine::{distance, Location, Units};
use regex::Regex; use regex::Regex;
use crate::get_ip::Distance;
pub fn get_ip_type(ip: &str) -> (String, bool) { pub fn get_ip_type(ip: &str) -> (String, bool) {
let private_regex: Regex = Regex::new(r"^172\.(1[6-9]|2\d|3[01])\.").unwrap(); let private_regex: Regex = Regex::new(r"^172\.(1[6-9]|2\d|3[01])\.").unwrap();
@ -25,3 +30,51 @@ pub fn get_ip_type(ip: &str) -> (String, bool) {
(processed_string, is_special_ip) (processed_string, is_special_ip)
} }
pub fn parse_location_string(location: String) -> Result<Location, String> {
let location_parts: Vec<&str> = location.split(",").collect::<Vec<_>>();
if location_parts.len() != 2 {
return Err(format!("Unknown location format: {}", &location));
}
let latitude = location_parts[0].parse::<f64>().unwrap_or_default();
let longitude = location_parts[1].parse::<f64>().unwrap_or_default();
Ok(Location {
latitude,
longitude,
})
}
pub fn get_client_server_distance_string(client_location: String, units: Distance) -> String {
let client_location = parse_location_string(client_location).unwrap_or(Location {
latitude: 0.0,
longitude: 0.0,
});
let server_location = Location {
latitude: var("SERVER_LATITUDE")
.unwrap_or_default()
.parse::<f64>()
.unwrap_or_default(),
longitude: var("SERVER_LONGITUDE")
.unwrap_or_default()
.parse::<f64>()
.unwrap_or_default(),
};
let haversine_units = match units {
Distance::Km => Units::Kilometers,
Distance::Mi => Units::Miles,
Distance::Nm => Units::Kilometers,
};
let distance = distance(client_location, server_location, haversine_units);
let distance = match units {
Distance::Km => distance,
Distance::Mi => distance,
Distance::Nm => distance / 1.852,
};
format!("{:.2} {}", &distance, units)
}