feat: new matcher system instead of manually 'match'ing in servcie

This commit is contained in:
hexlocation 2025-08-02 20:40:44 +02:00
parent f305cb5a85
commit 638b0376d8
15 changed files with 646 additions and 225 deletions

157
src/routes/api.rs Normal file
View file

@ -0,0 +1,157 @@
use async_trait::async_trait;
use base64::{Engine, prelude::BASE64_STANDARD};
use http::request::Parts;
use http_body_util::BodyExt;
use hyper::{Method, StatusCode};
use log::{debug, error, warn};
use crate::{
config::Client,
db::Endpoint,
matchers::api::ApiMatcher,
server::{custom_resp, json_to_vec},
services::matcher::Route,
};
pub struct AddHost {}
#[async_trait]
impl Route<ApiMatcher> for AddHost {
fn matcher(&self, _: &ApiMatcher, req: &hyper::Request<hyper::body::Incoming>) -> bool {
req.uri().path().starts_with("/endpoint/") && req.method() == Method::POST
}
async fn call(
&self,
m: &ApiMatcher,
parts: Parts,
) -> Result<crate::server::GeneralResponse, hyper::Error> {
let database = m.database.clone();
let address = m._address.unwrap();
let body = m.body.clone().unwrap();
let endpoint_id: u32 = parts.uri.path().replace("/endpoint/", "").parse().unwrap();
if !body["hosts"].is_array() {
error!("Hosts parameter is not an array.",);
return Ok(custom_resp(
StatusCode::BAD_REQUEST,
"Hosts parameter is not an array.".to_string(),
)
.await);
}
let endpoint = match Endpoint::get_by_id(*database.lock().await, endpoint_id)
.await
.unwrap()
{
Some(x) => x,
None => {
error!("No endpoint found by id {endpoint_id} from {address}",);
return Ok(custom_resp(
StatusCode::NOT_FOUND,
"No endpoint by that ID.".to_string(),
)
.await);
}
};
let hosts = json_to_vec(body["hosts"].clone()).await.unwrap();
endpoint.host(*database.lock().await, hosts).await.unwrap();
Ok(custom_resp(StatusCode::OK, "Success".to_string()).await)
}
}
pub struct RegisterEndpoint {}
#[async_trait]
impl Route<ApiMatcher> for RegisterEndpoint {
fn matcher(&self, _: &ApiMatcher, req: &hyper::Request<hyper::body::Incoming>) -> bool {
req.uri().path() == "/register" && req.method() == Method::POST
}
async fn call(
&self,
m: &ApiMatcher,
_: Parts,
) -> Result<crate::server::GeneralResponse, hyper::Error> {
let address = m._address.unwrap();
let database = m.database.clone();
let body = m.body.clone().unwrap();
let mut endpoint = Endpoint::new(
None,
address,
body["port"].as_u16().unwrap_or(8080),
body["callback"].as_str().unwrap_or("/").to_string(),
)
.await;
if !body["hosts"].is_array() {
error!("Hosts parameter is not an array.",);
return Ok(custom_resp(
StatusCode::BAD_REQUEST,
"Hosts parameter is not an array.".to_string(),
)
.await);
};
let hosts = json_to_vec(body["hosts"].clone()).await.unwrap();
endpoint
.register(*database.lock().await, hosts)
.await
.unwrap();
let endpoint_id = endpoint.id.unwrap().to_string();
let response = custom_resp(StatusCode::OK, endpoint_id).await;
Ok(response)
}
}
pub struct RemoveHost {}
#[async_trait]
impl Route<ApiMatcher> for RemoveHost {
fn matcher(&self, _: &ApiMatcher, req: &hyper::Request<hyper::body::Incoming>) -> bool {
req.uri().path().starts_with("/endpoint/") && req.method() == Method::DELETE
}
async fn call(
&self,
m: &ApiMatcher,
parts: Parts,
) -> Result<crate::server::GeneralResponse, hyper::Error> {
let database = m.database.clone();
let address = m._address.unwrap();
let endpoint_id: u32 = parts.uri.path().replace("/endpoint/", "").parse().unwrap();
let endpoint = match Endpoint::get_by_id(*database.lock().await, endpoint_id)
.await
.unwrap()
{
Some(x) => x,
None => {
error!("No endpoint found by id {endpoint_id} from {address}",);
return Ok(custom_resp(
StatusCode::NOT_FOUND,
"No endpoint by that ID.".to_string(),
)
.await);
}
};
endpoint.delete(*database.lock().await).await.unwrap();
Ok(custom_resp(StatusCode::OK, "Success".to_string()).await)
}
}