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>
|
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
7
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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 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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue