✨ Metrics
This commit is contained in:
parent
905b70349b
commit
f02977b7d7
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"
|
||||
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]]
|
||||
name = "h2"
|
||||
version = "0.4.1"
|
||||
@ -537,7 +556,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
@ -569,7 +588,7 @@ dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
@ -581,7 +600,7 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||
dependencies = [
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -608,6 +627,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "http"
|
||||
version = "1.0.0"
|
||||
@ -619,6 +649,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "http-body"
|
||||
version = "1.0.0"
|
||||
@ -626,7 +667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -637,8 +678,8 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.0.0",
|
||||
"http-body 1.0.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@ -654,6 +695,30 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "hyper"
|
||||
version = "1.1.0"
|
||||
@ -663,9 +728,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"h2 0.4.1",
|
||||
"http 1.0.0",
|
||||
"http-body 1.0.0",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
@ -682,7 +747,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper 1.1.0",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
@ -699,9 +764,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"http 1.0.0",
|
||||
"http-body 1.0.0",
|
||||
"hyper 1.1.0",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@ -897,7 +962,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"memchr",
|
||||
@ -1187,10 +1252,10 @@ dependencies = [
|
||||
"cookie",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"http-body-util",
|
||||
"httpdate",
|
||||
"hyper",
|
||||
"hyper 1.1.0",
|
||||
"hyper-util",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
@ -1202,6 +1267,7 @@ dependencies = [
|
||||
"poem-derive",
|
||||
"quick-xml",
|
||||
"regex",
|
||||
"reqwest 0.11.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rfc7239",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1265,7 +1331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5d485fb9cc4ca9a8364beedd4ea81294b1f028d459c8fd7bb352e38f87f8ffa"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"indexmap",
|
||||
"mime",
|
||||
"proc-macro-crate",
|
||||
@ -1418,6 +1484,41 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "reqwest"
|
||||
version = "0.11.23"
|
||||
@ -1428,11 +1529,11 @@ dependencies = [
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"h2 0.4.1",
|
||||
"http 1.0.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper 1.1.0",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
@ -1472,7 +1573,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"hyper-util",
|
||||
"lazy_static",
|
||||
"mime",
|
||||
@ -1482,7 +1583,7 @@ dependencies = [
|
||||
"queryst",
|
||||
"rand",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest 0.11.23 (git+https://github.com/seanmonstar/reqwest.git?branch=hyper-v1)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
@ -2123,7 +2224,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
|
@ -13,7 +13,7 @@ hyper-util = { version = "0.1.2", features = ["full"] }
|
||||
lazy_static = "1.4.0"
|
||||
mime = "0.3.17"
|
||||
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"] }
|
||||
queryst = "3.0.0"
|
||||
rand = "0.8.5"
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::sync::RwLock;
|
||||
|
||||
use config::Config;
|
||||
use lazy_static::lazy_static;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::config::loader::load_settings;
|
||||
|
||||
|
33
src/main.rs
33
src/main.rs
@ -2,11 +2,28 @@ mod config;
|
||||
mod proxies;
|
||||
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 proxies::RoadInstance;
|
||||
use tokio::sync::Mutex;
|
||||
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]
|
||||
async fn main() -> Result<(), std::io::Error> {
|
||||
@ -19,19 +36,17 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
.init();
|
||||
|
||||
// Prepare all the stuff
|
||||
let mut instance = proxies::Instance::new();
|
||||
|
||||
info!("Loading proxy regions...");
|
||||
match proxies::loader::scan_regions(
|
||||
config::C
|
||||
.read()
|
||||
.unwrap()
|
||||
.await
|
||||
.get_string("regions")
|
||||
.unwrap_or("./regions".to_string()),
|
||||
) {
|
||||
Err(_) => error!("Loading proxy regions... failed"),
|
||||
Ok((regions, count)) => {
|
||||
instance.regions = regions;
|
||||
ROAD.lock().await.regions = regions;
|
||||
info!(count, "Loading proxy regions... done")
|
||||
}
|
||||
};
|
||||
@ -40,11 +55,11 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
let proxies_server = Server::new(TcpListener::bind(
|
||||
config::C
|
||||
.read()
|
||||
.unwrap()
|
||||
.await
|
||||
.get_string("listen.proxies")
|
||||
.unwrap_or("0.0.0.0:80".to_string()),
|
||||
))
|
||||
.run(route::handle.data(instance));
|
||||
.run(route::handle);
|
||||
|
||||
// Sideload
|
||||
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(
|
||||
config::C
|
||||
.read()
|
||||
.unwrap()
|
||||
.await
|
||||
.get_string("listen.sideload")
|
||||
.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 poem::http::{HeaderMap, Uri};
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wildmatch::WildMatch;
|
||||
|
||||
use self::config::{Location, Region};
|
||||
use self::{
|
||||
config::{Location, Region},
|
||||
metrics::RoadMetrics,
|
||||
};
|
||||
|
||||
pub mod browser;
|
||||
pub mod config;
|
||||
pub mod loader;
|
||||
pub mod metrics;
|
||||
pub mod responder;
|
||||
pub mod route;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Instance {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RoadInstance {
|
||||
pub regions: Vec<Region>,
|
||||
pub metrics: RoadMetrics,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new() -> Instance {
|
||||
Instance { regions: vec![] }
|
||||
}
|
||||
|
||||
pub fn filter(&self, uri: &Uri, method: Method, headers: &HeaderMap) -> Option<&Location> {
|
||||
impl RoadInstance {
|
||||
pub fn filter(
|
||||
&self,
|
||||
uri: &Uri,
|
||||
method: Method,
|
||||
headers: &HeaderMap,
|
||||
) -> Option<(&Region, &Location)> {
|
||||
self.regions.iter().find_map(|region| {
|
||||
region.locations.iter().find(|location| {
|
||||
let location = region.locations.iter().find(|location| {
|
||||
let mut hosts = location.hosts.iter();
|
||||
if !hosts.any(|item| {
|
||||
WildMatch::new(item.as_str()).matches(uri.host().unwrap_or("localhost"))
|
||||
@ -64,7 +69,9 @@ impl Instance {
|
||||
}
|
||||
|
||||
true
|
||||
})
|
||||
});
|
||||
|
||||
location.map(|location| (region, location))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,30 @@
|
||||
use http::Method;
|
||||
use poem::{
|
||||
handler,
|
||||
http::{HeaderMap, StatusCode, Uri},
|
||||
web::{websocket::WebSocket, Data},
|
||||
web::websocket::WebSocket,
|
||||
Body, Error, FromRequest, IntoResponse, Request, Response, Result,
|
||||
};
|
||||
use rand::seq::SliceRandom;
|
||||
use reqwest::Method;
|
||||
|
||||
use crate::proxies::{
|
||||
config::{Destination, DestinationType},
|
||||
responder,
|
||||
use crate::{
|
||||
proxies::{
|
||||
config::{Destination, DestinationType},
|
||||
responder,
|
||||
},
|
||||
ROAD,
|
||||
};
|
||||
|
||||
#[handler]
|
||||
pub async fn handle(
|
||||
app: Data<&super::Instance>,
|
||||
req: &Request,
|
||||
uri: &Uri,
|
||||
headers: &HeaderMap,
|
||||
method: Method,
|
||||
body: Body,
|
||||
) -> 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,
|
||||
None => {
|
||||
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;
|
||||
|
||||
#[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]
|
||||
impl SideloadApi {
|
||||
#[oai(path = "/hello", method = "get")]
|
||||
async fn index(&self, name: Query<Option<String>>) -> PlainText<String> {
|
||||
match name.0 {
|
||||
Some(name) => PlainText(format!("hello, {name}!")),
|
||||
None => PlainText("hello!".to_string()),
|
||||
}
|
||||
#[oai(path = "/", method = "get")]
|
||||
async fn index(&self) -> OverviewResponse {
|
||||
let locked_app = ROAD.lock().await;
|
||||
let regions = locked_app.regions.clone();
|
||||
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