Skip to content

Instantly share code, notes, and snippets.

@sfackler
Last active October 25, 2022 12:54
Show Gist options
  • Save sfackler/a7f3aaf2ce3f5ff4c99e1a3d67f828ed to your computer and use it in GitHub Desktop.
Save sfackler/a7f3aaf2ce3f5ff4c99e1a3d67f828ed to your computer and use it in GitHub Desktop.
use bytes::Bytes;
use futures_sink::Sink;
use futures_util::future::BoxFuture;
use http::{Request, Response};
use http_body::combinators::BoxBody;
use http_body::Body;
use hyper::server::conn::Connection;
use std::future::Future;
use std::io;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct Loggers {
pub audit_logger: SyncAppender<()>,
}
pub type SyncAppender<T> =
MetricsAppender<Pin<Box<dyn Sink<Bytes, Error = io::Error> + Sync + Send>>, T>;
pub struct MetricsAppender<S, T> {
inner: S,
_t: PhantomData<T>,
}
pub type RawBody = hyper::Body;
pub trait Service<R> {
type Response;
type Future: Future<Output = Self::Response>;
fn call(&self, req: R) -> Self::Future;
}
pub struct AuditLogService<S, T> {
logger: T,
inner: S,
}
impl<S, T> AuditLogService<S, T> {
pub fn new(logger: T, inner: S) -> Self {
AuditLogService { logger, inner }
}
}
impl<S, T, R, B> Service<R> for AuditLogService<S, T>
where
S: Service<R, Response = Response<B>>,
S::Future: 'static + Send,
T: 'static + Send,
B: Send,
{
type Response = Response<B>;
type Future = BoxFuture<'static, Self::Response>;
fn call(&self, _: R) -> Self::Future {
panic!()
}
}
pub struct HandlerService;
impl Service<Request<RawBody>> for HandlerService {
type Response = Response<BoxBody<Bytes, io::Error>>;
type Future = BoxFuture<'static, Self::Response>;
fn call(&self, _: Request<RawBody>) -> Self::Future {
panic!()
}
}
pub struct HyperService<S> {
request_service: S,
}
impl<S> HyperService<S> {
pub fn new(request_service: S) -> Self {
HyperService { request_service }
}
}
impl<S, R, B> Service<R> for HyperService<S>
where
S: Service<Request<hyper::Body>, Response = Response<B>>,
B: Body,
{
type Response = Result<(), io::Error>;
type Future = HyperFuture<S, R, B>;
fn call(&self, _: R) -> Self::Future {
panic!()
}
}
pub struct HyperFuture<S, R, B>
where
S: Service<Request<hyper::Body>, Response = Response<B>>,
B: Body,
{
inner: Connection<R, AdaptorService<S>>,
}
impl<S, R, B> Future for HyperFuture<S, R, B>
where
S: Service<Request<hyper::Body>, Response = Response<B>>,
B: Body,
{
type Output = Result<(), io::Error>;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
panic!()
}
}
struct AdaptorService<S> {
inner: S,
}
impl<S, R> hyper::service::Service<R> for AdaptorService<S>
where
S: Service<R>,
{
type Response = S::Response;
type Error = io::Error;
type Future = AdaptorFuture<S::Future>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: R) -> Self::Future {
AdaptorFuture {
inner: self.inner.call(req),
}
}
}
pub struct AdaptorFuture<F> {
inner: F,
}
impl<F, T> Future for AdaptorFuture<F>
where
F: Future<Output = T>,
{
type Output = Result<T, io::Error>;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
panic!()
}
}
fn handle(loggers: Loggers, stream: ()) {
let request_service = AuditLogService::new(loggers.audit_logger, HandlerService);
let handle_service = HyperService::new(request_service);
spawn(async move {
let _ = handle_service.call(stream).await;
});
}
fn spawn(_: impl Send) {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment