🔥 使用 Rust 重构 #5
149
Cargo.lock
generated
149
Cargo.lock
generated
@ -526,6 +526,25 @@ version = "0.28.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http 0.2.11",
|
||||||
|
"indexmap",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -537,7 +556,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -569,7 +588,7 @@ dependencies = [
|
|||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bytes",
|
"bytes",
|
||||||
"headers-core",
|
"headers-core",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"mime",
|
"mime",
|
||||||
"sha1",
|
"sha1",
|
||||||
@ -581,7 +600,7 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -608,6 +627,17 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -619,6 +649,17 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http 0.2.11",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-body"
|
name = "http-body"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -626,7 +667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -637,8 +678,8 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -654,6 +695,30 @@ version = "1.0.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.3.23",
|
||||||
|
"http 0.2.11",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -663,9 +728,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.4.1",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
@ -682,7 +747,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper 1.1.0",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -699,9 +764,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"hyper",
|
"hyper 1.1.0",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -897,7 +962,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -1187,10 +1252,10 @@ dependencies = [
|
|||||||
"cookie",
|
"cookie",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"headers",
|
"headers",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"hyper",
|
"hyper 1.1.0",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"mime",
|
"mime",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
@ -1202,6 +1267,7 @@ dependencies = [
|
|||||||
"poem-derive",
|
"poem-derive",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
"regex",
|
"regex",
|
||||||
|
"reqwest 0.11.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rfc7239",
|
"rfc7239",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -1265,7 +1331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d5d485fb9cc4ca9a8364beedd4ea81294b1f028d459c8fd7bb352e38f87f8ffa"
|
checksum = "d5d485fb9cc4ca9a8364beedd4ea81294b1f028d459c8fd7bb352e38f87f8ffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"mime",
|
"mime",
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
@ -1418,6 +1484,41 @@ version = "0.8.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.3.23",
|
||||||
|
"http 0.2.11",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"hyper 0.14.28",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"system-configuration",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"winreg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.23"
|
version = "0.11.23"
|
||||||
@ -1428,11 +1529,11 @@ dependencies = [
|
|||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.4.1",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper 1.1.0",
|
||||||
"hyper-tls",
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
@ -1472,7 +1573,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"mime",
|
"mime",
|
||||||
@ -1482,7 +1583,7 @@ dependencies = [
|
|||||||
"queryst",
|
"queryst",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest 0.11.23 (git+https://github.com/seanmonstar/reqwest.git?branch=hyper-v1)",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -2123,7 +2224,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"http",
|
"http 1.0.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
|
@ -13,7 +13,7 @@ hyper-util = { version = "0.1.2", features = ["full"] }
|
|||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
mime = "0.3.17"
|
mime = "0.3.17"
|
||||||
percent-encoding = "2.3.1"
|
percent-encoding = "2.3.1"
|
||||||
poem = { version = "2.0.0", features = ["tokio-metrics", "websocket", "static-files"] }
|
poem = { version = "2.0.0", features = ["tokio-metrics", "websocket", "static-files", "reqwest"] }
|
||||||
poem-openapi = { version = "4.0.0", features = ["swagger-ui"] }
|
poem-openapi = { version = "4.0.0", features = ["swagger-ui"] }
|
||||||
queryst = "3.0.0"
|
queryst = "3.0.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::config::loader::load_settings;
|
use crate::config::loader::load_settings;
|
||||||
|
|
||||||
|
33
src/main.rs
33
src/main.rs
@ -2,11 +2,28 @@ mod config;
|
|||||||
mod proxies;
|
mod proxies;
|
||||||
mod sideload;
|
mod sideload;
|
||||||
|
|
||||||
use poem::{listener::TcpListener, EndpointExt, Route, Server};
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use poem::{listener::TcpListener, Route, Server};
|
||||||
use poem_openapi::OpenApiService;
|
use poem_openapi::OpenApiService;
|
||||||
|
use proxies::RoadInstance;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
use tracing::{error, info, Level};
|
use tracing::{error, info, Level};
|
||||||
|
|
||||||
use crate::proxies::route;
|
use crate::proxies::{metrics::RoadMetrics, route};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref ROAD: Mutex<RoadInstance> = Mutex::new(RoadInstance {
|
||||||
|
regions: vec![],
|
||||||
|
metrics: RoadMetrics {
|
||||||
|
requests_count: 0,
|
||||||
|
failures_count: 0,
|
||||||
|
recent_successes: VecDeque::new(),
|
||||||
|
recent_errors: VecDeque::new(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
@ -19,19 +36,17 @@ async fn main() -> Result<(), std::io::Error> {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
// Prepare all the stuff
|
// Prepare all the stuff
|
||||||
let mut instance = proxies::Instance::new();
|
|
||||||
|
|
||||||
info!("Loading proxy regions...");
|
info!("Loading proxy regions...");
|
||||||
match proxies::loader::scan_regions(
|
match proxies::loader::scan_regions(
|
||||||
config::C
|
config::C
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.await
|
||||||
.get_string("regions")
|
.get_string("regions")
|
||||||
.unwrap_or("./regions".to_string()),
|
.unwrap_or("./regions".to_string()),
|
||||||
) {
|
) {
|
||||||
Err(_) => error!("Loading proxy regions... failed"),
|
Err(_) => error!("Loading proxy regions... failed"),
|
||||||
Ok((regions, count)) => {
|
Ok((regions, count)) => {
|
||||||
instance.regions = regions;
|
ROAD.lock().await.regions = regions;
|
||||||
info!(count, "Loading proxy regions... done")
|
info!(count, "Loading proxy regions... done")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -40,11 +55,11 @@ async fn main() -> Result<(), std::io::Error> {
|
|||||||
let proxies_server = Server::new(TcpListener::bind(
|
let proxies_server = Server::new(TcpListener::bind(
|
||||||
config::C
|
config::C
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.await
|
||||||
.get_string("listen.proxies")
|
.get_string("listen.proxies")
|
||||||
.unwrap_or("0.0.0.0:80".to_string()),
|
.unwrap_or("0.0.0.0:80".to_string()),
|
||||||
))
|
))
|
||||||
.run(route::handle.data(instance));
|
.run(route::handle);
|
||||||
|
|
||||||
// Sideload
|
// Sideload
|
||||||
let sideload = OpenApiService::new(sideload::SideloadApi, "Sideload API", "1.0")
|
let sideload = OpenApiService::new(sideload::SideloadApi, "Sideload API", "1.0")
|
||||||
@ -54,7 +69,7 @@ async fn main() -> Result<(), std::io::Error> {
|
|||||||
let sideload_server = Server::new(TcpListener::bind(
|
let sideload_server = Server::new(TcpListener::bind(
|
||||||
config::C
|
config::C
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.await
|
||||||
.get_string("listen.sideload")
|
.get_string("listen.sideload")
|
||||||
.unwrap_or("0.0.0.0:81".to_string()),
|
.unwrap_or("0.0.0.0:81".to_string()),
|
||||||
))
|
))
|
||||||
|
80
src/proxies/metrics.rs
Normal file
80
src/proxies/metrics.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use poem_openapi::Object;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::config::{Destination, Location, Region};
|
||||||
|
|
||||||
|
#[derive(Debug, Object, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct RoadTrace {
|
||||||
|
pub region: String,
|
||||||
|
pub location: String,
|
||||||
|
pub destination: String,
|
||||||
|
pub error: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoadTrace {
|
||||||
|
pub fn from_structs(reg: Region, loc: Location, end: Destination) -> RoadTrace {
|
||||||
|
RoadTrace {
|
||||||
|
region: reg.id,
|
||||||
|
location: loc.id,
|
||||||
|
destination: end.id,
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_structs_with_error(
|
||||||
|
reg: Region,
|
||||||
|
loc: Location,
|
||||||
|
end: Destination,
|
||||||
|
err: String,
|
||||||
|
) -> RoadTrace {
|
||||||
|
RoadTrace {
|
||||||
|
region: reg.id,
|
||||||
|
location: loc.id,
|
||||||
|
destination: end.id,
|
||||||
|
error: Some(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RoadMetrics {
|
||||||
|
pub requests_count: u64,
|
||||||
|
pub failures_count: u64,
|
||||||
|
|
||||||
|
pub recent_successes: VecDeque<RoadTrace>,
|
||||||
|
pub recent_errors: VecDeque<RoadTrace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoadMetrics {
|
||||||
|
pub fn get_success_rate(&self) -> f64 {
|
||||||
|
if self.requests_count > 0 {
|
||||||
|
(self.requests_count - self.failures_count) as f64 / self.requests_count as f64
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_success_request(&mut self, reg: Region, loc: Location, end: Destination) {
|
||||||
|
self.requests_count += 1;
|
||||||
|
self.recent_successes
|
||||||
|
.push_back(RoadTrace::from_structs(reg, loc, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_faliure_request(
|
||||||
|
&mut self,
|
||||||
|
reg: Region,
|
||||||
|
loc: Location,
|
||||||
|
end: Destination,
|
||||||
|
err: String, // For some reason error is rarely clonable, so we use preformatted message
|
||||||
|
) {
|
||||||
|
self.requests_count += 1;
|
||||||
|
self.failures_count += 1;
|
||||||
|
self.recent_errors
|
||||||
|
.push_back(RoadTrace::from_structs_with_error(reg, loc, end, err));
|
||||||
|
if self.recent_errors.len() > 10 {
|
||||||
|
self.recent_errors.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,30 +1,35 @@
|
|||||||
use http::Method;
|
use http::Method;
|
||||||
use poem::http::{HeaderMap, Uri};
|
use poem::http::{HeaderMap, Uri};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use wildmatch::WildMatch;
|
use wildmatch::WildMatch;
|
||||||
|
|
||||||
use self::config::{Location, Region};
|
use self::{
|
||||||
|
config::{Location, Region},
|
||||||
|
metrics::RoadMetrics,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod browser;
|
pub mod browser;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
|
pub mod metrics;
|
||||||
pub mod responder;
|
pub mod responder;
|
||||||
pub mod route;
|
pub mod route;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Instance {
|
pub struct RoadInstance {
|
||||||
pub regions: Vec<Region>,
|
pub regions: Vec<Region>,
|
||||||
|
pub metrics: RoadMetrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl RoadInstance {
|
||||||
pub fn new() -> Instance {
|
pub fn filter(
|
||||||
Instance { regions: vec![] }
|
&self,
|
||||||
}
|
uri: &Uri,
|
||||||
|
method: Method,
|
||||||
pub fn filter(&self, uri: &Uri, method: Method, headers: &HeaderMap) -> Option<&Location> {
|
headers: &HeaderMap,
|
||||||
|
) -> Option<(&Region, &Location)> {
|
||||||
self.regions.iter().find_map(|region| {
|
self.regions.iter().find_map(|region| {
|
||||||
region.locations.iter().find(|location| {
|
let location = region.locations.iter().find(|location| {
|
||||||
let mut hosts = location.hosts.iter();
|
let mut hosts = location.hosts.iter();
|
||||||
if !hosts.any(|item| {
|
if !hosts.any(|item| {
|
||||||
WildMatch::new(item.as_str()).matches(uri.host().unwrap_or("localhost"))
|
WildMatch::new(item.as_str()).matches(uri.host().unwrap_or("localhost"))
|
||||||
@ -64,7 +69,9 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
})
|
});
|
||||||
|
|
||||||
|
location.map(|location| (region, location))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,30 @@
|
|||||||
|
use http::Method;
|
||||||
use poem::{
|
use poem::{
|
||||||
handler,
|
handler,
|
||||||
http::{HeaderMap, StatusCode, Uri},
|
http::{HeaderMap, StatusCode, Uri},
|
||||||
web::{websocket::WebSocket, Data},
|
web::websocket::WebSocket,
|
||||||
Body, Error, FromRequest, IntoResponse, Request, Response, Result,
|
Body, Error, FromRequest, IntoResponse, Request, Response, Result,
|
||||||
};
|
};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use reqwest::Method;
|
|
||||||
|
|
||||||
use crate::proxies::{
|
use crate::{
|
||||||
config::{Destination, DestinationType},
|
proxies::{
|
||||||
responder,
|
config::{Destination, DestinationType},
|
||||||
|
responder,
|
||||||
|
},
|
||||||
|
ROAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[handler]
|
#[handler]
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
app: Data<&super::Instance>,
|
|
||||||
req: &Request,
|
req: &Request,
|
||||||
uri: &Uri,
|
uri: &Uri,
|
||||||
headers: &HeaderMap,
|
headers: &HeaderMap,
|
||||||
method: Method,
|
method: Method,
|
||||||
body: Body,
|
body: Body,
|
||||||
) -> Result<impl IntoResponse, Error> {
|
) -> Result<impl IntoResponse, Error> {
|
||||||
let location = match app.filter(uri, method.clone(), headers) {
|
let readable_app = ROAD.lock().await;
|
||||||
|
let (region, location) = match readable_app.filter(uri, method.clone(), headers) {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None => {
|
None => {
|
||||||
return Err(Error::from_string(
|
return Err(Error::from_string(
|
||||||
@ -93,5 +96,27 @@ pub async fn handle(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forward(destination, req, uri, headers, method, body).await
|
let reg = region.clone();
|
||||||
|
let loc = location.clone();
|
||||||
|
let end = destination.clone();
|
||||||
|
|
||||||
|
match forward(&end, req, uri, headers, method, body).await {
|
||||||
|
Ok(resp) => {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let writable_app = &mut ROAD.lock().await;
|
||||||
|
writable_app.metrics.add_success_request(reg, loc, end);
|
||||||
|
});
|
||||||
|
Ok(resp)
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let message = format!("{:}", err);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let writable_app = &mut ROAD.lock().await;
|
||||||
|
writable_app
|
||||||
|
.metrics
|
||||||
|
.add_faliure_request(reg, loc, end, message);
|
||||||
|
});
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,81 @@
|
|||||||
use poem_openapi::{param::Query, payload::PlainText, OpenApi};
|
use poem_openapi::{payload::Json, ApiResponse, Object, OpenApi};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
proxies::{
|
||||||
|
config::{Destination, Location},
|
||||||
|
metrics::RoadTrace,
|
||||||
|
},
|
||||||
|
ROAD,
|
||||||
|
};
|
||||||
|
|
||||||
use super::SideloadApi;
|
use super::SideloadApi;
|
||||||
|
|
||||||
|
#[derive(ApiResponse)]
|
||||||
|
enum OverviewResponse {
|
||||||
|
/// Return the overview data.
|
||||||
|
#[oai(status = 200)]
|
||||||
|
Ok(Json<OverviewData>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Object, Clone, PartialEq)]
|
||||||
|
struct OverviewData {
|
||||||
|
/// Loaded regions count
|
||||||
|
#[oai(read_only)]
|
||||||
|
regions: usize,
|
||||||
|
/// Loaded locations count
|
||||||
|
#[oai(read_only)]
|
||||||
|
locations: usize,
|
||||||
|
/// Loaded destnations count
|
||||||
|
#[oai(read_only)]
|
||||||
|
destinations: usize,
|
||||||
|
/// Recent requests count
|
||||||
|
requests_count: u64,
|
||||||
|
/// Recent requests success count
|
||||||
|
faliures_count: u64,
|
||||||
|
/// Recent requests falied count
|
||||||
|
successes_count: u64,
|
||||||
|
/// Recent requests success rate
|
||||||
|
success_rate: f64,
|
||||||
|
/// Recent successes
|
||||||
|
recent_successes: Vec<RoadTrace>,
|
||||||
|
/// Recent errors
|
||||||
|
recent_errors: Vec<RoadTrace>,
|
||||||
|
}
|
||||||
|
|
||||||
#[OpenApi]
|
#[OpenApi]
|
||||||
impl SideloadApi {
|
impl SideloadApi {
|
||||||
#[oai(path = "/hello", method = "get")]
|
#[oai(path = "/", method = "get")]
|
||||||
async fn index(&self, name: Query<Option<String>>) -> PlainText<String> {
|
async fn index(&self) -> OverviewResponse {
|
||||||
match name.0 {
|
let locked_app = ROAD.lock().await;
|
||||||
Some(name) => PlainText(format!("hello, {name}!")),
|
let regions = locked_app.regions.clone();
|
||||||
None => PlainText("hello!".to_string()),
|
let locations = regions
|
||||||
}
|
.iter()
|
||||||
|
.flat_map(|item| item.locations.clone())
|
||||||
|
.collect::<Vec<Location>>();
|
||||||
|
let destinations = locations
|
||||||
|
.iter()
|
||||||
|
.flat_map(|item| item.destinations.clone())
|
||||||
|
.collect::<Vec<Destination>>();
|
||||||
|
OverviewResponse::Ok(Json(OverviewData {
|
||||||
|
regions: regions.len(),
|
||||||
|
locations: locations.len(),
|
||||||
|
destinations: destinations.len(),
|
||||||
|
requests_count: locked_app.metrics.requests_count,
|
||||||
|
successes_count: locked_app.metrics.requests_count - locked_app.metrics.failures_count,
|
||||||
|
faliures_count: locked_app.metrics.failures_count,
|
||||||
|
success_rate: locked_app.metrics.get_success_rate(),
|
||||||
|
recent_successes: locked_app
|
||||||
|
.metrics
|
||||||
|
.recent_successes
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
recent_errors: locked_app
|
||||||
|
.metrics
|
||||||
|
.recent_errors
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user