use std::convert::Infallible; use eyre::Result; use warp::{hyper::StatusCode, Filter}; use atuin_common::api::SyncHistoryRequest; use super::{ database::{Database, Postgres}, handlers, }; use crate::{models::User, settings::Settings}; fn with_settings( settings: Settings, ) -> impl Filter + Clone { warp::any().map(move || settings.clone()) } fn with_db( db: impl Database + Clone + Send + Sync, ) -> impl Filter + Clone { warp::any().map(move || db.clone()) } fn with_user( postgres: Postgres, ) -> impl Filter + Clone { warp::header::("authorization").and_then(move |header: String| { // async closures are still buggy :( let postgres = postgres.clone(); async move { let header: Vec<&str> = header.split(' ').collect(); let token = if header.len() == 2 { if header[0] != "Token" { return Err(warp::reject()); } header[1] } else { return Err(warp::reject()); }; let user = postgres .get_session_user(token) .await .map_err(|_| warp::reject())?; Ok(user) } }) } pub async fn router( settings: &Settings, ) -> Result + Clone> { let postgres = Postgres::new(settings.db_uri.as_str()).await?; let index = warp::get().and(warp::path::end()).map(handlers::index); let count = warp::get() .and(warp::path("sync")) .and(warp::path("count")) .and(warp::path::end()) .and(with_user(postgres.clone())) .and(with_db(postgres.clone())) .and_then(handlers::history::count) .boxed(); let sync = warp::get() .and(warp::path("sync")) .and(warp::path("history")) .and(warp::query::()) .and(warp::path::end()) .and(with_user(postgres.clone())) .and(with_db(postgres.clone())) .and_then(handlers::history::list) .boxed(); let add_history = warp::post() .and(warp::path("history")) .and(warp::path::end()) .and(warp::body::json()) .and(with_user(postgres.clone())) .and(with_db(postgres.clone())) .and_then(handlers::history::add) .boxed(); let user = warp::get() .and(warp::path("user")) .and(warp::path::param::()) .and(warp::path::end()) .and(with_db(postgres.clone())) .and_then(handlers::user::get) .boxed(); let register = warp::post() .and(warp::path("register")) .and(warp::path::end()) .and(warp::body::json()) .and(with_settings(settings.clone())) .and(with_db(postgres.clone())) .and_then(handlers::user::register) .boxed(); let login = warp::post() .and(warp::path("login")) .and(warp::path::end()) .and(warp::body::json()) .and(with_db(postgres)) .and_then(handlers::user::login) .boxed(); let r = warp::any() .and( index .or(count) .or(sync) .or(add_history) .or(user) .or(register) .or(login) .or(warp::any().map(|| warp::reply::with_status("☕", StatusCode::IM_A_TEAPOT))), ) .with(warp::filters::log::log("atuin::api")); Ok(r) }