♻️ 使用 Actix RS 重构 #8
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1277,6 +1277,7 @@ dependencies = [
|
|||||||
"actix-web-httpauth",
|
"actix-web-httpauth",
|
||||||
"awc",
|
"awc",
|
||||||
"config",
|
"config",
|
||||||
|
"derive_more",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"mime",
|
"mime",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
@ -31,3 +31,4 @@ toml = "0.8.8"
|
|||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
wildmatch = "2.3.0"
|
wildmatch = "2.3.0"
|
||||||
|
derive_more = "0.99.17"
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use actix_web::http::header::HeaderMap;
|
use actix_web::http::header::{ContentType, HeaderMap};
|
||||||
use actix_web::http::{Method, Uri};
|
use actix_web::http::{Method, StatusCode, Uri};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use wildmatch::WildMatch;
|
use wildmatch::WildMatch;
|
||||||
|
use actix_web::{error, HttpResponse};
|
||||||
|
use derive_more::{Display};
|
||||||
|
|
||||||
use crate::warden::WardenInstance;
|
use crate::warden::WardenInstance;
|
||||||
|
|
||||||
@ -16,6 +18,46 @@ pub mod metrics;
|
|||||||
pub mod responder;
|
pub mod responder;
|
||||||
pub mod route;
|
pub mod route;
|
||||||
|
|
||||||
|
#[derive(Debug, Display)]
|
||||||
|
pub enum ProxyError {
|
||||||
|
#[display(fmt = "Remote gateway issue")]
|
||||||
|
BadGateway,
|
||||||
|
|
||||||
|
#[display(fmt = "No configured able to process this request")]
|
||||||
|
NoGateway,
|
||||||
|
|
||||||
|
#[display(fmt = "Not found")]
|
||||||
|
NotFound,
|
||||||
|
|
||||||
|
#[display(fmt = "Only accepts method GET")]
|
||||||
|
MethodGetOnly,
|
||||||
|
|
||||||
|
#[display(fmt = "Invalid request path")]
|
||||||
|
InvalidRequestPath,
|
||||||
|
|
||||||
|
#[display(fmt = "Upstream does not support protocol you used")]
|
||||||
|
NotImplemented,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::ResponseError for ProxyError {
|
||||||
|
fn status_code(&self) -> StatusCode {
|
||||||
|
match *self {
|
||||||
|
ProxyError::BadGateway => StatusCode::BAD_GATEWAY,
|
||||||
|
ProxyError::NoGateway => StatusCode::NOT_FOUND,
|
||||||
|
ProxyError::NotFound => StatusCode::NOT_FOUND,
|
||||||
|
ProxyError::MethodGetOnly => StatusCode::METHOD_NOT_ALLOWED,
|
||||||
|
ProxyError::InvalidRequestPath => StatusCode::BAD_REQUEST,
|
||||||
|
ProxyError::NotImplemented => StatusCode::NOT_IMPLEMENTED,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_response(&self) -> HttpResponse {
|
||||||
|
HttpResponse::build(self.status_code())
|
||||||
|
.insert_header(ContentType::html())
|
||||||
|
.body(self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RoadInstance {
|
pub struct RoadInstance {
|
||||||
pub regions: Vec<Region>,
|
pub regions: Vec<Region>,
|
||||||
|
@ -7,12 +7,14 @@ use actix_proxy::IntoHttpResponse;
|
|||||||
use actix_web::{HttpRequest, HttpResponse, web};
|
use actix_web::{HttpRequest, HttpResponse, web};
|
||||||
use actix_web::http::Method;
|
use actix_web::http::Method;
|
||||||
use awc::Client;
|
use awc::Client;
|
||||||
|
use tracing::log::warn;
|
||||||
|
use crate::proxies::ProxyError;
|
||||||
|
|
||||||
pub async fn respond_hypertext(
|
pub async fn respond_hypertext(
|
||||||
uri: String,
|
uri: String,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
client: web::Data<Client>,
|
client: web::Data<Client>,
|
||||||
) -> Result<HttpResponse, HttpResponse> {
|
) -> Result<HttpResponse, ProxyError> {
|
||||||
let ip = req.peer_addr().unwrap().ip().to_string();
|
let ip = req.peer_addr().unwrap().ip().to_string();
|
||||||
let proto = req.uri().scheme_str().unwrap();
|
let proto = req.uri().scheme_str().unwrap();
|
||||||
let host = req.uri().host().unwrap();
|
let host = req.uri().host().unwrap();
|
||||||
@ -40,8 +42,8 @@ pub async fn respond_hypertext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
Err(HttpResponse::BadGateway()
|
warn!("Proxy got a upstream issue... {:?}", error);
|
||||||
.body(format!("Something went wrong... {:}", error)))
|
Err(ProxyError::BadGateway)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -59,10 +61,9 @@ pub struct StaticResponderConfig {
|
|||||||
pub async fn respond_static(
|
pub async fn respond_static(
|
||||||
cfg: StaticResponderConfig,
|
cfg: StaticResponderConfig,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> Result<HttpResponse, HttpResponse> {
|
) -> Result<HttpResponse, ProxyError> {
|
||||||
if req.method() != Method::GET {
|
if req.method() != Method::GET {
|
||||||
return Err(HttpResponse::MethodNotAllowed()
|
return Err(ProxyError::MethodGetOnly);
|
||||||
.body("This destination only support GET request."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = req
|
let path = req
|
||||||
@ -74,7 +75,7 @@ pub async fn respond_static(
|
|||||||
let path = match percent_encoding::percent_decode_str(path).decode_utf8() {
|
let path = match percent_encoding::percent_decode_str(path).decode_utf8() {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(HttpResponse::NotFound().body("Not found."));
|
return Err(ProxyError::NotFound);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,8 +92,7 @@ pub async fn respond_static(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !file_path.starts_with(cfg.uri) {
|
if !file_path.starts_with(cfg.uri) {
|
||||||
return Err(HttpResponse::Forbidden()
|
return Err(ProxyError::InvalidRequestPath);
|
||||||
.body("Unexpected path."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !file_path.exists() {
|
if !file_path.exists() {
|
||||||
@ -116,7 +116,7 @@ pub async fn respond_static(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(HttpResponse::NotFound().body("Not found."));
|
return Err(ProxyError::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
return if file_path.is_file() {
|
return if file_path.is_file() {
|
||||||
@ -129,6 +129,6 @@ pub async fn respond_static(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(HttpResponse::NotFound().body("Not found."))
|
return Err(ProxyError::NotFound);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use actix_web::{HttpRequest, HttpResponse, web};
|
use actix_web::{HttpRequest, HttpResponse, ResponseError, web};
|
||||||
use actix_web::http::header;
|
use actix_web::http::header;
|
||||||
use awc::Client;
|
use awc::Client;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
@ -10,14 +10,14 @@ use crate::{
|
|||||||
},
|
},
|
||||||
ROAD,
|
ROAD,
|
||||||
};
|
};
|
||||||
|
use crate::proxies::ProxyError;
|
||||||
|
|
||||||
pub async fn handle(req: HttpRequest, client: web::Data<Client>) -> HttpResponse {
|
pub async fn handle(req: HttpRequest, client: web::Data<Client>) -> HttpResponse {
|
||||||
let readable_app = ROAD.lock().await;
|
let readable_app = ROAD.lock().await;
|
||||||
let (region, location) = match readable_app.filter(req.uri(), req.method(), req.headers()) {
|
let (region, location) = match readable_app.filter(req.uri(), req.method(), req.headers()) {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None => {
|
None => {
|
||||||
return HttpResponse::NotFound()
|
return ProxyError::NoGateway.error_response();
|
||||||
.body("There are no region be able to respone this request.");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,29 +30,24 @@ pub async fn handle(req: HttpRequest, client: web::Data<Client>) -> HttpResponse
|
|||||||
end: &Destination,
|
end: &Destination,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
client: web::Data<Client>,
|
client: web::Data<Client>,
|
||||||
) -> Result<HttpResponse, HttpResponse> {
|
) -> Result<HttpResponse, ProxyError> {
|
||||||
// Handle normal web request
|
// Handle normal web request
|
||||||
match end.get_type() {
|
match end.get_type() {
|
||||||
DestinationType::Hypertext => {
|
DestinationType::Hypertext => {
|
||||||
let Ok(uri) = end.get_hypertext_uri() else {
|
let Ok(uri) = end.get_hypertext_uri() else {
|
||||||
return Err(HttpResponse::NotImplemented()
|
return Err(ProxyError::NotImplemented);
|
||||||
.body("This destination was not support web requests."));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
responder::respond_hypertext(uri, req, client).await
|
responder::respond_hypertext(uri, req, client).await
|
||||||
}
|
}
|
||||||
DestinationType::StaticFiles => {
|
DestinationType::StaticFiles => {
|
||||||
let Ok(cfg) = end.get_static_config() else {
|
let Ok(cfg) = end.get_static_config() else {
|
||||||
return Err(HttpResponse::NotImplemented()
|
return Err(ProxyError::NotImplemented);
|
||||||
.body("This destination was not support static files."));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
responder::respond_static(cfg, req).await
|
responder::respond_static(cfg, req).await
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Err(ProxyError::NotImplemented)
|
||||||
return Err(HttpResponse::NotImplemented()
|
|
||||||
.body("Unsupported destination protocol."));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,13 +73,14 @@ pub async fn handle(req: HttpRequest, client: web::Data<Client>) -> HttpResponse
|
|||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
Err(resp) => {
|
Err(resp) => {
|
||||||
|
let message = resp.to_string();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let writable_app = &mut ROAD.lock().await;
|
let writable_app = &mut ROAD.lock().await;
|
||||||
writable_app
|
writable_app
|
||||||
.metrics
|
.metrics
|
||||||
.add_failure_request(ip, ua, reg, loc, end, "TODO".to_owned());
|
.add_failure_request(ip, ua, reg, loc, end, message);
|
||||||
});
|
});
|
||||||
resp
|
resp.error_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user