Add json-framed encoding, docs, refactor

This commit is contained in:
Dominik Werder
2024-04-28 18:41:06 +02:00
parent b0eab82c93
commit 1b1e0f5a72
52 changed files with 1539 additions and 454 deletions

View File

@@ -0,0 +1,39 @@
use crate::bodystream::response;
use crate::err::Error;
use crate::requests::accepts_json_or_all;
use http::Method;
use http::StatusCode;
use httpclient::body_empty;
use httpclient::body_string;
use httpclient::Requ;
use httpclient::StreamResponse;
use netpod::ProxyConfig;
use netpod::ReqCtx;
pub struct BackendListHandler {}
impl BackendListHandler {
pub fn handler(req: &Requ) -> Option<Self> {
if req.uri().path() == "/api/4/backend/list" {
Some(Self {})
} else {
None
}
}
pub async fn handle(&self, req: Requ, _ctx: &ReqCtx, _node_config: &ProxyConfig) -> Result<StreamResponse, Error> {
if req.method() == Method::GET {
if accepts_json_or_all(req.headers()) {
let res = serde_json::json!({
"backends_available": ["sf-databuffer"]
});
let body = serde_json::to_string(&res)?;
Ok(response(StatusCode::OK).body(body_string(body))?)
} else {
Ok(response(StatusCode::BAD_REQUEST).body(body_empty())?)
}
} else {
Ok(response(StatusCode::METHOD_NOT_ALLOWED).body(body_empty())?)
}
}
}

View File

@@ -1,8 +1,8 @@
use crate::bodystream::response;
use crate::bodystream::response_err_msg;
use crate::err::Error;
use crate::proxy::get_query_host_for_backend;
use crate::requests::accepts_cbor_frames;
use crate::requests::accepts_cbor_framed;
use crate::requests::accepts_json_framed;
use crate::requests::accepts_json_or_all;
use crate::ReqCtx;
use http::header;
@@ -22,7 +22,8 @@ use netpod::req_uri_to_url;
use netpod::FromUrl;
use netpod::HasBackend;
use netpod::ProxyConfig;
use netpod::APP_CBOR;
use netpod::APP_CBOR_FRAMED;
use netpod::APP_JSON_FRAMED;
use query::api4::events::PlainEventsQuery;
pub struct EventsHandler {}
@@ -44,14 +45,10 @@ impl EventsHandler {
if req.method() != Method::GET {
Ok(response(StatusCode::METHOD_NOT_ALLOWED).body(body_empty())?)
} else {
if accepts_cbor_frames(req.headers()) {
// self.handle_cbor(req, ctx, proxy_config).await
// Ok(crate::proxy::proxy_backend_query::<PlainEventsQuery>(req, ctx, proxy_config).await?)
warn!("TODO enabe cbor endpoint");
Ok(response_err_msg(
StatusCode::INTERNAL_SERVER_ERROR,
format!("cbor endpoint currently disabled"),
)?)
if accepts_cbor_framed(req.headers()) {
self.handle_framed(req, APP_CBOR_FRAMED, ctx, proxy_config).await
} else if accepts_json_framed(req.headers()) {
self.handle_framed(req, APP_JSON_FRAMED, ctx, proxy_config).await
} else if accepts_json_or_all(req.headers()) {
Ok(crate::proxy::proxy_backend_query::<PlainEventsQuery>(req, ctx, proxy_config).await?)
} else {
@@ -60,26 +57,33 @@ impl EventsHandler {
}
}
async fn handle_cbor(&self, req: Requ, ctx: &ReqCtx, proxy_config: &ProxyConfig) -> Result<StreamResponse, Error> {
async fn handle_framed(
&self,
req: Requ,
accept: &str,
ctx: &ReqCtx,
proxy_config: &ProxyConfig,
) -> Result<StreamResponse, Error> {
let (head, _body) = req.into_parts();
let url = req_uri_to_url(&head.uri)?;
let pairs = get_url_query_pairs(&url);
let evq = PlainEventsQuery::from_pairs(&pairs)?;
info!("{evq:?}");
// Ok(response(StatusCode::INTERNAL_SERVER_ERROR).body(body_empty())?)
// get_random_query_host_for_backend
debug!("{evq:?}");
let query_host = get_query_host_for_backend(evq.backend(), proxy_config)?;
// TODO this ignores the fragment
let url_str = format!("{}{}", query_host, head.uri.path_and_query().unwrap());
info!("try to contact {url_str}");
let url_str = format!(
"{}{}",
query_host,
head.uri
.path_and_query()
.ok_or_else(|| Error::with_msg_no_trace("uri contains no path"))?
);
debug!("try to contact {url_str}");
let uri: Uri = url_str.parse()?;
let host = uri.host().ok_or_else(|| Error::with_msg_no_trace("no host in url"))?;
let req = Request::builder()
.method(Method::GET)
.header(header::HOST, uri.host().unwrap())
.header(header::ACCEPT, APP_CBOR)
.header(header::HOST, host)
.header(header::ACCEPT, accept)
.header(ctx.header_name(), ctx.header_value())
.uri(&uri)
.body(body_empty())?;
@@ -87,10 +91,10 @@ impl EventsHandler {
let res = client.send_request(req).await?;
let (head, body) = res.into_parts();
if head.status != StatusCode::OK {
error!("backend returned error: {head:?}");
warn!("backend returned error: {head:?}");
Ok(response(StatusCode::INTERNAL_SERVER_ERROR).body(body_empty())?)
} else {
info!("backend returned OK");
debug!("backend returned OK");
Ok(response(StatusCode::OK).body(body_stream(StreamIncoming::new(body)))?)
}
}