refactor: move routes to lib, add tests
This commit is contained in:
parent
8b1abb3333
commit
d13fe11dee
@ -2,8 +2,6 @@ use std::num::NonZeroU16;
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use warp::query;
|
||||
|
||||
use ipfs::{Ipfs, IpfsOptions, IpfsTypes, UninitializedIpfs};
|
||||
use rust_ipfs_http::{config, v0};
|
||||
|
||||
@ -177,80 +175,15 @@ fn main() {
|
||||
fn serve<Types: IpfsTypes>(
|
||||
ipfs: &Ipfs<Types>,
|
||||
) -> (std::net::SocketAddr, impl std::future::Future<Output = ()>) {
|
||||
|
||||
use tokio::stream::StreamExt;
|
||||
use warp::Filter;
|
||||
|
||||
let (shutdown_tx, mut shutdown_rx) = tokio::sync::mpsc::channel::<()>(1);
|
||||
|
||||
// Set up routes
|
||||
// /api
|
||||
let api = warp::path("api");
|
||||
|
||||
// /api/v0
|
||||
let v0 = api.and(warp::path("v0"));
|
||||
|
||||
// /api/v0/shutdown
|
||||
let shutdown = warp::post()
|
||||
.and(warp::path!("shutdown"))
|
||||
.and(warp::any().map(move || shutdown_tx.clone()))
|
||||
.and_then(shutdown);
|
||||
|
||||
// the http libraries seem to prefer POST method
|
||||
let api = shutdown
|
||||
.or(v0::id::identity(ipfs))
|
||||
// Placeholder paths
|
||||
// https://docs.rs/warp/0.2.2/warp/macro.path.html#path-prefixes
|
||||
.or(warp::path!("add").and_then(not_implemented))
|
||||
.or(warp::path!("bitswap" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("block" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("bootstrap" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("config" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("dag" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("dht" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("get").and_then(not_implemented))
|
||||
.or(warp::path!("key" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("name" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("object" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("pin" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("ping" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("pubsub" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("refs" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("repo" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("stats" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("swarm" / "connect")
|
||||
.and(query::<v0::swarm::ConnectQuery>())
|
||||
.and_then(v0::swarm::connect))
|
||||
.or(warp::path!("swarm" / "peers")
|
||||
.and(query::<v0::swarm::PeersQuery>())
|
||||
.and_then(v0::swarm::peers))
|
||||
.or(warp::path!("swarm" / "addrs").and_then(v0::swarm::addrs))
|
||||
.or(warp::path!("swarm" / "addrs" / "local")
|
||||
.and(query::<v0::swarm::AddrsLocalQuery>())
|
||||
.and_then(v0::swarm::addrs_local))
|
||||
.or(warp::path!("swarm" / "disconnect")
|
||||
.and(query::<v0::swarm::DisconnectQuery>())
|
||||
.and_then(v0::swarm::disconnect))
|
||||
.or(warp::path!("version")
|
||||
.and(query::<v0::version::Query>())
|
||||
.and_then(v0::version::version));
|
||||
|
||||
let routes = v0.and(api.recover(v0::recover_as_message_response));
|
||||
let routes = v0::routes(ipfs, shutdown_tx);
|
||||
let routes = routes.with(warp::log("rust-ipfs-http-v0"));
|
||||
|
||||
warp::serve(routes).bind_with_graceful_shutdown(([127, 0, 0, 1], 0), async move {
|
||||
shutdown_rx.next().await;
|
||||
})
|
||||
}
|
||||
|
||||
async fn shutdown(
|
||||
mut tx: tokio::sync::mpsc::Sender<()>,
|
||||
) -> Result<impl warp::Reply, std::convert::Infallible> {
|
||||
Ok(match tx.send(()).await {
|
||||
Ok(_) => warp::http::StatusCode::OK,
|
||||
Err(_) => warp::http::StatusCode::NOT_IMPLEMENTED,
|
||||
})
|
||||
}
|
||||
|
||||
async fn not_implemented() -> Result<impl warp::Reply, std::convert::Infallible> {
|
||||
Ok(warp::http::StatusCode::NOT_IMPLEMENTED)
|
||||
}
|
||||
|
125
http/src/v0.rs
125
http/src/v0.rs
@ -1,7 +1,130 @@
|
||||
use ipfs::{Ipfs, IpfsTypes};
|
||||
use std::convert::Infallible;
|
||||
|
||||
pub mod id;
|
||||
pub mod swarm;
|
||||
pub mod version;
|
||||
|
||||
pub mod support;
|
||||
pub(crate) use support::{with_ipfs, NotImplemented, InvalidPeerId, StringError};
|
||||
pub use support::recover_as_message_response;
|
||||
pub(crate) use support::{with_ipfs, InvalidPeerId, NotImplemented, StringError};
|
||||
|
||||
pub fn routes<T>(
|
||||
ipfs: &Ipfs<T>,
|
||||
shutdown_tx: tokio::sync::mpsc::Sender<()>,
|
||||
) -> impl warp::Filter<Extract = impl warp::Reply, Error = Infallible> + Clone
|
||||
where
|
||||
T: IpfsTypes,
|
||||
{
|
||||
use warp::{query, Filter};
|
||||
// /api/v0/shutdown
|
||||
let shutdown = warp::post()
|
||||
.and(warp::path!("shutdown"))
|
||||
.and(warp::any().map(move || shutdown_tx.clone()))
|
||||
.and_then(handle_shutdown);
|
||||
|
||||
let mount = warp::path("api").and(warp::path("v0"));
|
||||
|
||||
let api = mount.and(
|
||||
shutdown
|
||||
.or(id::identity(ipfs))
|
||||
// Placeholder paths
|
||||
// https://docs.rs/warp/0.2.2/warp/macro.path.html#path-prefixes
|
||||
.or(warp::path!("add").and_then(not_implemented))
|
||||
.or(warp::path!("bitswap" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("block" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("bootstrap" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("config" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("dag" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("dht" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("get").and_then(not_implemented))
|
||||
.or(warp::path!("key" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("name" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("object" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("pin" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("ping" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("pubsub" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("refs" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("repo" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("stats" / ..).and_then(not_implemented))
|
||||
.or(warp::path!("swarm" / "connect")
|
||||
.and(query::<swarm::ConnectQuery>())
|
||||
.and_then(swarm::connect))
|
||||
.or(warp::path!("swarm" / "peers")
|
||||
.and(query::<swarm::PeersQuery>())
|
||||
.and_then(swarm::peers))
|
||||
.or(warp::path!("swarm" / "addrs").and_then(swarm::addrs))
|
||||
.or(warp::path!("swarm" / "addrs" / "local")
|
||||
.and(query::<swarm::AddrsLocalQuery>())
|
||||
.and_then(swarm::addrs_local))
|
||||
.or(warp::path!("swarm" / "disconnect")
|
||||
.and(query::<swarm::DisconnectQuery>())
|
||||
.and_then(swarm::disconnect))
|
||||
.or(warp::path!("version")
|
||||
.and(query::<version::Query>())
|
||||
.and_then(version::version))
|
||||
);
|
||||
|
||||
let routes = api.recover(recover_as_message_response);
|
||||
|
||||
routes
|
||||
}
|
||||
|
||||
pub async fn handle_shutdown(
|
||||
mut tx: tokio::sync::mpsc::Sender<()>,
|
||||
) -> Result<impl warp::Reply, std::convert::Infallible> {
|
||||
Ok(match tx.send(()).await {
|
||||
Ok(_) => warp::http::StatusCode::OK,
|
||||
Err(_) => warp::http::StatusCode::NOT_IMPLEMENTED,
|
||||
})
|
||||
}
|
||||
|
||||
async fn not_implemented() -> Result<impl warp::Reply, std::convert::Infallible> {
|
||||
Ok(warp::http::StatusCode::NOT_IMPLEMENTED)
|
||||
}
|
||||
|
||||
/// Creates routes for tests, the ipfs will not work as no background task is being spawned.
|
||||
#[cfg(test)]
|
||||
async fn non_functioning_routes() -> impl warp::Filter<Extract = impl warp::Reply, Error = Infallible> + Clone {
|
||||
use ipfs::{IpfsOptions, TestTypes, UninitializedIpfs};
|
||||
let options = IpfsOptions::<TestTypes>::default();
|
||||
|
||||
let (ipfs, fut) = UninitializedIpfs::new(options).await.start().await.unwrap();
|
||||
drop(fut);
|
||||
let (shutdown_tx, shutdown_rx) = tokio::sync::mpsc::channel::<()>(1);
|
||||
drop(shutdown_rx);
|
||||
|
||||
routes(&ipfs, shutdown_tx)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn not_found() {
|
||||
let routes = non_functioning_routes().await;
|
||||
let resp = warp::test::request()
|
||||
.method("GET")
|
||||
.path("/api/v0/id_foobar")
|
||||
.reply(&routes)
|
||||
.await;
|
||||
|
||||
assert_eq!(resp.status(), 404);
|
||||
// from go-ipfs
|
||||
assert_eq!(resp.body(), "404 page not found");
|
||||
|
||||
println!("{:?}", resp);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_peer_id() {
|
||||
let routes = non_functioning_routes().await;
|
||||
let resp = warp::test::request()
|
||||
.method("GET")
|
||||
.path("/api/v0/id?arg=foobar")
|
||||
.reply(&routes)
|
||||
.await;
|
||||
|
||||
assert_eq!(resp.status(), 400);
|
||||
// from go-ipfs
|
||||
assert_eq!(resp.body(), r#"{"Message":"invalid peer id","Code":0,"Type":"error"}"#);
|
||||
|
||||
println!("{:?}", resp);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user