move http body guts out to signal-gateway-bin
this is a cleaner separation of concerns
This commit is contained in:
@@ -25,6 +25,9 @@ async-trait = { workspace = true }
|
||||
conf = { workspace = true }
|
||||
conf-extra = { workspace = true }
|
||||
dotenvy = { workspace = true }
|
||||
http = { workspace = true }
|
||||
http-body = { workspace = true }
|
||||
http-body-util = { workspace = true }
|
||||
hyper = { workspace = true }
|
||||
hyper-util = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
|
||||
@@ -3,14 +3,19 @@
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use conf::Conf;
|
||||
use http::{Method, Request, Response, StatusCode};
|
||||
use http_body::Body;
|
||||
use http_body_util::BodyExt;
|
||||
use hyper::service::service_fn;
|
||||
use hyper_util::{rt::TokioIo, server::conn::auto};
|
||||
use signal_gateway::{CommandRouter, Gateway, GatewayConfig, Handling};
|
||||
use signal_gateway::{CommandRouter, Gateway, GatewayConfig, Handling, alertmanager::AlertPost};
|
||||
use signal_gateway_app_code::AppCodeTools;
|
||||
use signal_gateway_assistant_claude::{ClaudeAssistant, ClaudeConfig};
|
||||
use std::{env, fs, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
convert::Infallible, env, fs, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration,
|
||||
};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tokio_util::{bytes::Buf, sync::CancellationToken};
|
||||
use tracing::{error, info, warn};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
@@ -222,10 +227,7 @@ fn start_http_task(listener: TcpListener, gateway: Arc<Gateway>) -> tokio::task:
|
||||
if let Err(err) = auto::Builder::new(hyper_util::rt::TokioExecutor::new())
|
||||
.serve_connection(
|
||||
io,
|
||||
service_fn(|req| {
|
||||
let thread_gateway = thread_gateway.clone();
|
||||
async move { thread_gateway.handle_http_request(req).await }
|
||||
}),
|
||||
service_fn(|req| handle_http_request(thread_gateway.clone(), req)),
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -236,6 +238,96 @@ fn start_http_task(listener: TcpListener, gateway: Arc<Gateway>) -> tokio::task:
|
||||
})
|
||||
}
|
||||
|
||||
async fn handle_http_request(
|
||||
gateway: Arc<Gateway>,
|
||||
req: Request<hyper::body::Incoming>,
|
||||
) -> Result<Response<String>, Infallible> {
|
||||
match handle_http_request_impl(gateway, req).await {
|
||||
Ok(resp) => Ok(resp),
|
||||
Err(resp) => Ok(resp),
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_http_request_impl<B>(
|
||||
gateway: Arc<Gateway>,
|
||||
req: Request<B>,
|
||||
) -> Result<Response<String>, Response<String>>
|
||||
where
|
||||
B: Body + Send,
|
||||
B::Data: Buf + Send,
|
||||
B::Error: std::fmt::Display,
|
||||
{
|
||||
info!(
|
||||
"Received http request: {} {} (version: {:?})",
|
||||
req.method(),
|
||||
req.uri().path(),
|
||||
req.version()
|
||||
);
|
||||
|
||||
fn ok_resp() -> Response<String> {
|
||||
Response::new("OK".into())
|
||||
}
|
||||
fn err_resp(code: StatusCode, text: impl Into<String>) -> Response<String> {
|
||||
let mut resp = Response::new(text.into());
|
||||
*resp.status_mut() = code;
|
||||
resp
|
||||
}
|
||||
|
||||
match req.uri().path() {
|
||||
"/" | "/health" | "/ready" => {
|
||||
if !matches!(req.method(), &Method::GET | &Method::HEAD) {
|
||||
Ok(err_resp(
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
"Use GET or HEAD with this route",
|
||||
))
|
||||
} else {
|
||||
Ok(ok_resp())
|
||||
}
|
||||
}
|
||||
"/alert" => {
|
||||
if !matches!(req.method(), &Method::POST) {
|
||||
return Ok(err_resp(
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
"Use POST with this route",
|
||||
));
|
||||
}
|
||||
let body_bytes = req
|
||||
.into_body()
|
||||
.collect()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
err_resp(
|
||||
StatusCode::BAD_REQUEST,
|
||||
format!("When reading body bytes: {err}"),
|
||||
)
|
||||
})?
|
||||
.to_bytes()
|
||||
.to_vec();
|
||||
|
||||
let body_text = str::from_utf8(&body_bytes).map_err(|err| {
|
||||
warn!("When reading body bytes: {err}");
|
||||
err_resp(StatusCode::BAD_REQUEST, "Request body was not utf-8")
|
||||
})?;
|
||||
|
||||
let alert_msg: AlertPost = serde_json::from_str(body_text).map_err(|err| {
|
||||
error!("Could not parse json: {err}:\n{body_text}");
|
||||
err_resp(StatusCode::BAD_REQUEST, "Invalid Json")
|
||||
})?;
|
||||
|
||||
if let Err(msg) = gateway.handle_alertmanager_post(alert_msg).await {
|
||||
error!("gateway (handle_alertmanager_post): {msg}");
|
||||
Ok(err_resp(StatusCode::INTERNAL_SERVER_ERROR, msg))
|
||||
} else {
|
||||
Ok(ok_resp())
|
||||
}
|
||||
}
|
||||
_ => Ok(err_resp(
|
||||
StatusCode::NOT_FOUND,
|
||||
format!("Not found '{} {}'", req.method(), req.uri().path()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user