use std::{convert::Infallible, pin::Pin, sync::Arc};
use bytes::Bytes;
use futures_util::TryStreamExt;
use http_body_util::{BodyExt, Empty, StreamBody, combinators::BoxBody};
use hyper::{Request, Response, StatusCode, body::Incoming, service::Service};
use redis::aio::ConnectionManager;
use tiny_google_oidc::config::Config;
use tokio::fs::File;
use tokio_util::io::ReaderStream;
use crate::{login_service::LoginService, protected::ProtectedService};
#[derive(Clone)]
pub struct Router {
config: Arc<Config>,
redis_conn: ConnectionManager,
}
impl Router {
pub fn new(config: Arc<Config>, redis_conn: ConnectionManager) -> Self {
Self {
config: config,
redis_conn,
}
}
pub fn config(&self) -> Arc<Config> {
Arc::clone(&self.config)
}
pub fn redis_conn(&self) -> ConnectionManager {
self.redis_conn.clone()
}
}
impl Service<Request<Incoming>> for Router {
type Response = Response<BoxBody<Bytes, std::io::Error>>;
type Error = Infallible;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn call(&self, req: Request<Incoming>) -> Self::Future {
let redis_conn = self.redis_conn();
let config = self.config();
Box::pin(async move {
let default = Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Empty::new().map_err(|e| match e {}).boxed())
.unwrap();
match req.uri().path().to_string().as_ref() {
"/" => {
let file = File::open("./examples/hyper/index.html").await.unwrap();
let reader_stream = ReaderStream::new(file);
let a = StreamBody::new(reader_stream.map_ok(hyper::body::Frame::data));
let box_body = BodyExt::boxed(a);
let res = Response::builder()
.status(StatusCode::OK)
.body(box_body)
.unwrap();
Ok(res)
}
"/auth" => {
let res = LoginService::new(config, redis_conn)
.entry()
.await
.unwrap_or(default);
Ok(res)
}
"/auth/callback" => {
let res = LoginService::new(config, redis_conn)
.callback(req)
.await
.unwrap_or(default);
Ok(res)
}
"/protected" => {
let res = ProtectedService::new(redis_conn)
.serve(req)
.await
.unwrap_or(default);
Ok(res)
}
_ => {
let res = Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Empty::new().map_err(|e| match e {}).boxed())
.unwrap();
Ok(res)
}
}
})
}
}