add argument to commandline
This commit is contained in:
parent
927219667d
commit
b2c8afcd69
6 changed files with 679 additions and 382 deletions
921
Cargo.lock
generated
921
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
17
Cargo.toml
17
Cargo.toml
|
@ -1,15 +1,14 @@
|
|||
[package]
|
||||
name = "speedtest-rs"
|
||||
version = "0.1.0"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
license = "LGPL-3.0+"
|
||||
|
||||
[dependencies]
|
||||
rocket = { version = "0.5.0-rc.1", features = ["json"] }
|
||||
rand = { version = "0.8.4" }
|
||||
rocket-client-addr = "0.5.0"
|
||||
regex = "1.5.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"
|
||||
rocket = { version = "0.5.0-rc.2", features = ["json"] }
|
||||
rocket-client-addr = "0.5.2"
|
||||
rand = { version = "0.8.5" }
|
||||
regex = "1"
|
||||
ipinfo = "0.3.1"
|
||||
serde_with = { version = "2.0.1", features = ["json"] }
|
||||
clap = "4.0.11"
|
||||
|
|
30
README.md
30
README.md
|
@ -2,6 +2,10 @@
|
|||
|
||||
This is a lightweight backend written in Rust for [Librespeed](https://github.com/librespeed/speedtest).
|
||||
|
||||
Fork from: https://github.com/camilohe/speedtest-rs.git
|
||||
|
||||
Original repos: https://github.com/drobson03/speedtest-rs.git
|
||||
|
||||
## Compatibility
|
||||
Supported by all Librespeed frontends, though some features are missing (see below).
|
||||
|
||||
|
@ -30,7 +34,7 @@ You need Rust 1.55+ to compile the binary.
|
|||
1. Clone this repository:
|
||||
|
||||
```bash
|
||||
git clone github.com/drobson03/speedtest-rs
|
||||
git clone https://cloud.silique.fr/gitea/Silique/speedtest-rs.git
|
||||
# Change current working directory to the repository
|
||||
cd speedtest-rs
|
||||
```
|
||||
|
@ -41,29 +45,15 @@ cd speedtest-rs
|
|||
cargo build --release
|
||||
```
|
||||
|
||||
3. Copy the `assets` directory and the compiled `speedtest-rs` binary into a single directory along with a copy of `.env.example` named `.env` with your preferred port, listen address and [IPinfo.io](https://ipinfo.io/) API token.
|
||||
3. Copy the `assets` directory and the compiled `speedtest-rs` binary into a single directory.
|
||||
|
||||
|
||||
5. Put `assets` folder under the same directory as your compiled binary.
|
||||
4. Put `assets` folder under the same directory as your compiled binary.
|
||||
- Make sure font files and JavaScript files are in the `assets` directory
|
||||
- You can have multiple HTML pages under `assets` directory. They can be access directly under the server root
|
||||
(e.g. `/example-singleServer-full.html`)
|
||||
- It's possible to have a default page mapped to `/`, simply put a file named `index.html` under `assets`
|
||||
|
||||
6. Change `.env` according to your environment:
|
||||
|
||||
```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)
|
||||
ROCKET_ADDRESS=0.0.0.0
|
||||
```
|
||||
5. Launch: ./speedtest-rs
|
||||
|
||||
## Differences between Go and PHP implementation
|
||||
|
||||
|
@ -74,6 +64,8 @@ Copyright (C) 2016-2021 Federico Dossena
|
|||
|
||||
Copyright (C) 2021 Darcy Robson
|
||||
|
||||
Copyright (C) 2022 Emmanuel Garette
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
|
@ -85,4 +77,4 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/lgpl>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/lgpl>.
|
||||
|
|
|
@ -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 rocket::State;
|
||||
|
||||
use crate::haversine::Units;
|
||||
use crate::serialized_ip_info::IpDetailsDef;
|
||||
use crate::util::{get_client_server_distance_string, get_ip_type};
|
||||
use crate::util::{get_client_server_distance_string, get_ip_type, Config};
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct GetIPOptions {
|
||||
|
@ -27,7 +27,7 @@ pub struct GetIPResponse {
|
|||
}
|
||||
|
||||
#[get("/getIP?<opts..>")]
|
||||
pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<GetIPResponse> {
|
||||
pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions, state: &State<Config>) -> Json<GetIPResponse> {
|
||||
let mut result = GetIPResponse {
|
||||
processed_string: None,
|
||||
raw_isp_info: None,
|
||||
|
@ -42,7 +42,8 @@ pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<Ge
|
|||
}
|
||||
|
||||
if opts.isp {
|
||||
let ipinfo = get_ipinfo(&ip).await;
|
||||
let config = state.inner();
|
||||
let ipinfo = get_ipinfo(&ip, &config).await;
|
||||
result.raw_isp_info = Some(ipinfo.to_owned());
|
||||
|
||||
let org_regex = Regex::new(r"AS\d+\s").unwrap();
|
||||
|
@ -62,7 +63,7 @@ pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<Ge
|
|||
}
|
||||
|
||||
if !ipinfo.loc.is_empty() {
|
||||
let distance = get_client_server_distance_string(ipinfo.loc, opts.distance);
|
||||
let distance = get_client_server_distance_string(ipinfo.loc, opts.distance, config);
|
||||
isp = format!("{} ({})", &isp, &distance);
|
||||
}
|
||||
|
||||
|
@ -73,25 +74,26 @@ pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<Ge
|
|||
}
|
||||
|
||||
#[get("/getIP.php?<opts..>")]
|
||||
pub async fn get_ip_php(client_addr: &ClientRealAddr, opts: GetIPOptions) -> Json<GetIPResponse> {
|
||||
get_ip(client_addr, opts).await
|
||||
pub async fn get_ip_php(client_addr: &ClientRealAddr, opts: GetIPOptions, state: &State<Config>) -> Json<GetIPResponse> {
|
||||
get_ip(client_addr, opts, state).await
|
||||
}
|
||||
|
||||
#[get("/backend/getIP.php?<opts..>")]
|
||||
pub async fn get_backend_ip_php(
|
||||
client_addr: &ClientRealAddr,
|
||||
opts: GetIPOptions,
|
||||
state: &State<Config>,
|
||||
) -> Json<GetIPResponse> {
|
||||
get_ip(client_addr, opts).await
|
||||
get_ip(client_addr, opts, state).await
|
||||
}
|
||||
|
||||
pub async fn get_ipinfo(ip: &str) -> IpDetails {
|
||||
let config = IpInfoConfig {
|
||||
token: Some(var("IPINFO_TOKEN").unwrap_or(String::new())),
|
||||
pub async fn get_ipinfo(ip: &str, config: &Config) -> IpDetails {
|
||||
let ipconfig = IpInfoConfig {
|
||||
token: Some(config.ipinfo_token.to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut ipinfo_client = IpInfo::new(config).expect("should construct");
|
||||
let mut ipinfo_client = IpInfo::new(ipconfig).expect("should construct");
|
||||
|
||||
let res = ipinfo_client.lookup(&[ip]).unwrap();
|
||||
let ipinfo = res.get(ip).unwrap();
|
||||
|
|
44
src/main.rs
44
src/main.rs
|
@ -1,3 +1,4 @@
|
|||
#![allow(unused_must_use)]
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
|
@ -11,19 +12,30 @@ pub mod haversine;
|
|||
pub mod serialized_ip_info;
|
||||
pub mod util;
|
||||
|
||||
use dotenv::dotenv;
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{arg, Command, value_parser};
|
||||
use rocket::fs::FileServer;
|
||||
use rocket::http::Method;
|
||||
|
||||
use empty::*;
|
||||
use garbage::*;
|
||||
use get_ip::*;
|
||||
use util::Config;
|
||||
|
||||
#[rocket::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
dotenv().ok();
|
||||
|
||||
let args = Command::new("speedtest-rs")
|
||||
.version("1.0.0")
|
||||
.author("Emmanuel Garette <egarette@silique.fr>")
|
||||
.about("Alternative implemention of the Librespeed server API")
|
||||
.arg(arg!(-i --ip <VALUE>).default_value("127.0.0.1"))
|
||||
.arg(arg!(-p --port <VALUE>).value_parser(value_parser!(u16)).default_value("8000"))
|
||||
.arg(arg!(-a --assets <VALUE>).default_value("assets"))
|
||||
.arg(arg!(-t --ipinfo_token <VALUE>).default_value(""))
|
||||
.arg(arg!(-l --latitude <VALUE>).value_parser(value_parser!(f64)).default_value("0.0"))
|
||||
.arg(arg!(-o --longitude <VALUE>).value_parser(value_parser!(f64)).default_value("0.0"))
|
||||
.get_matches();
|
||||
|
||||
let routes = routes![get_ip::get_ip, get_backend_ip_php];
|
||||
|
||||
|
@ -44,17 +56,23 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
];
|
||||
|
||||
let routes = vec![routes, garbage_routes, empty_routes].concat();
|
||||
let config = Config {
|
||||
ip: args.get_one::<String>("ip").expect("required").to_string(),
|
||||
port: *args.get_one::<u16>("port").expect("required"),
|
||||
assets: args.get_one::<String>("assets").expect("required").to_string(),
|
||||
ipinfo_token: args.get_one::<String>("ipinfo_token").expect("required").to_string(),
|
||||
latitude: *args.get_one::<f64>("latitude").expect("required"),
|
||||
longitude: *args.get_one::<f64>("longitude").expect("required"),
|
||||
};
|
||||
let figment = rocket::Config::figment()
|
||||
.merge(("address", &config.ip))
|
||||
.merge(("port", &config.port));
|
||||
|
||||
let mut rocketship = rocket::build().mount("/", routes);
|
||||
|
||||
let asset_path = std::env::current_dir().unwrap().join("assets");
|
||||
if asset_path.exists() {
|
||||
let fileserver = FileServer::from(asset_path);
|
||||
|
||||
rocketship = rocketship.mount("/", fileserver);
|
||||
}
|
||||
|
||||
rocketship.launch().await?;
|
||||
let asset_path = std::env::current_dir().unwrap().join(args.get_one::<String>("assets").expect("required"));
|
||||
rocket::custom(figment).mount("/", routes)
|
||||
.manage(config)
|
||||
.mount("/", FileServer::from(asset_path))
|
||||
.launch().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
23
src/util.rs
23
src/util.rs
|
@ -1,5 +1,3 @@
|
|||
use std::env::var;
|
||||
|
||||
use crate::haversine::{distance, Location, Units};
|
||||
use regex::Regex;
|
||||
|
||||
|
@ -43,24 +41,27 @@ pub fn parse_location_string(location: String) -> Result<Location, String> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_client_server_distance_string(client_location: String, units: Units) -> String {
|
||||
pub fn get_client_server_distance_string(client_location: String, units: Units, config: &Config) -> 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(),
|
||||
latitude: config.latitude,
|
||||
longitude: config.longitude,
|
||||
};
|
||||
|
||||
let distance = distance(client_location, server_location, &units);
|
||||
|
||||
format!("{:.2} {}", distance, units)
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
pub ip: String,
|
||||
pub port: u16,
|
||||
pub assets: String,
|
||||
pub ipinfo_token: String,
|
||||
pub latitude: f64,
|
||||
pub longitude: f64,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue