Add distance calculation
This commit is contained in:
parent
a3cf82135f
commit
0ff5d01c94
6 changed files with 86 additions and 5 deletions
|
@ -1,3 +1,5 @@
|
|||
IPINFO_TOKEN=<your ipinfo token>
|
||||
SERVER_LATITUDE=1
|
||||
SERVER_LONGITUDE=1
|
||||
ROCKET_PORT=8000
|
||||
ROCKET_ADDRESS=0.0.0.0
|
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -711,6 +711,12 @@ dependencies = [
|
|||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "haversine"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef9482608b217d89a3caeb5fe2336a0491d1dc0be5d89c67125ea514b1f6a660"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
@ -1943,6 +1949,7 @@ name = "speedtest-rs"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dotenv",
|
||||
"haversine",
|
||||
"ipinfo",
|
||||
"rand 0.8.4",
|
||||
"regex",
|
||||
|
|
|
@ -14,3 +14,4 @@ ipinfo = "0.2.0"
|
|||
serde_with = { version = "1.10.0", features = ["json"] }
|
||||
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "a062933" }
|
||||
dotenv = "0.15.0"
|
||||
haversine = "0.2.1"
|
||||
|
|
|
@ -14,7 +14,7 @@ Supported by all Librespeed frontends, though some features are missing (see bel
|
|||
- [x] IP Address, ISP
|
||||
- [x] Multiple Points of Test (optional)
|
||||
- [x] Compatible with PHP frontend predefined endpoints (with `.php` suffixes)
|
||||
- [ ] Distance from server (optional)
|
||||
- [x] Distance from server (optional)
|
||||
- [ ] Telemetry (optional)
|
||||
- [ ] Results sharing (optional)
|
||||
- [ ] [Proxy Protocol](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt)?
|
||||
|
@ -55,6 +55,10 @@ cargo build --release
|
|||
```sh
|
||||
# your ipinfo.io API token
|
||||
IPINFO_TOKEN=
|
||||
# your server's latitude
|
||||
SERVER_LATITUDE=1
|
||||
# your server's longitude
|
||||
SERVER_LONGITUDE=1
|
||||
# the port to bind to
|
||||
ROCKET_PORT=8000
|
||||
# the bind address (0.0.0.0 is all interfaces)
|
||||
|
|
|
@ -2,11 +2,11 @@ use ipinfo::{IpDetails, IpInfo, IpInfoConfig};
|
|||
use regex::Regex;
|
||||
use rocket::serde::{json::Json, Serialize};
|
||||
use rocket_client_addr::ClientRealAddr;
|
||||
|
||||
use std::env::var;
|
||||
use std::fmt;
|
||||
|
||||
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)]
|
||||
pub enum Distance {
|
||||
|
@ -15,7 +15,16 @@ pub enum Distance {
|
|||
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)]
|
||||
pub struct GetIPOptions {
|
||||
#[field(default = true)]
|
||||
|
@ -69,6 +78,11 @@ pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<Ge
|
|||
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));
|
||||
}
|
||||
|
||||
|
|
53
src/util.rs
53
src/util.rs
|
@ -1,5 +1,10 @@
|
|||
use std::env::var;
|
||||
|
||||
use haversine::{distance, Location, Units};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::get_ip::Distance;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -25,3 +30,51 @@ pub fn get_ip_type(ip: &str) -> (String, bool) {
|
|||
|
||||
(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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue