diff --git a/api-test/src/bin/api-test.rs b/api-test/src/bin/api-test.rs
index 522c4d21..8d3a6119 100644
--- a/api-test/src/bin/api-test.rs
+++ b/api-test/src/bin/api-test.rs
@@ -13,76 +13,9 @@ use tokio::io::AsyncReadExt;
use proxmox::api::{api, router};
-async fn run_request(request: Request
) -> Result, hyper::Error> {
- match route_request(request).await {
- Ok(r) => Ok(r),
- Err(err) => Ok(Response::builder()
- .status(400)
- .body(Body::from(format!("ERROR: {}", err)))
- .expect("building an error response...")),
- }
-}
-
-async fn route_request(request: Request) -> Result, Error> {
- let path = request.uri().path();
-
- let (target, params) = ROUTER
- .lookup(path)
- .ok_or_else(|| format_err!("missing path: {}", path))?;
-
- target
- .get
- .as_ref()
- .ok_or_else(|| format_err!("no GET method for: {}", path))?
- .call(params.unwrap_or(Value::Null))
- .await
-}
-
-async fn main_do(www_dir: String) {
- // Construct our SocketAddr to listen on...
- let addr = ([0, 0, 0, 0], 3000).into();
-
- // And a MakeService to handle each connection...
- let service = make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(run_request)) });
-
- // Then bind and serve...
- let server = Server::bind(&addr).serve(service);
-
- println!("Serving {} under http://localhost:3000/www/", www_dir);
-
- if let Err(e) = server.await {
- eprintln!("server error: {}", e);
- }
-}
-
-fn main() {
- // We expect a path, where to find our files we expose via the www/ dir:
- let mut args = std::env::args();
-
- // real code should have better error handling
- let _program_name = args.next();
- let www_dir = args.next().expect("expected a www/ subdirectory");
- set_www_dir(www_dir.to_string());
-
- // show our api info:
- println!(
- "{}",
- serde_json::to_string_pretty(&ROUTER.api_dump()).unwrap()
- );
-
- let rt = tokio::runtime::Runtime::new().unwrap();
- rt.block_on(main_do(www_dir));
-}
-
-#[api({
- description: "Hello API call",
-})]
-async fn hello() -> Result, Error> {
- Ok(http::Response::builder()
- .status(200)
- .header("content-type", "text/html")
- .body(Body::from("Hello"))?)
-}
+//
+// Configuration:
+//
static mut WWW_DIR: Option = None;
@@ -103,6 +36,30 @@ pub fn set_www_dir(dir: String) {
}
}
+//
+// API methods
+//
+
+router! {
+ pub static ROUTER: Router = {
+ GET: hello,
+ /www/{path}*: { GET: get_www },
+ /api/1: {
+ // fill with more stuff
+ }
+ };
+}
+
+#[api({
+ description: "Hello API call",
+})]
+async fn hello() -> Result, Error> {
+ Ok(http::Response::builder()
+ .status(200)
+ .header("content-type", "text/html")
+ .body(Body::from("Hello"))?)
+}
+
#[api({
description: "Get a file from the www/ subdirectory.",
parameters: {
@@ -114,6 +71,7 @@ async fn get_www(path: String) -> Result, Error> {
bail!("illegal path");
}
+ // FIXME: Add support for an ApiError type for 404s etc. to reduce error handling code size:
let mut file = match tokio::fs::File::open(format!("{}/{}", www_dir(), path)).await {
Ok(file) => file,
Err(ref err) if err.kind() == io::ErrorKind::NotFound => {
@@ -145,11 +103,77 @@ async fn get_www(path: String) -> Result, Error> {
Ok(response.body(Body::from(data))?)
}
-router! {
- pub static ROUTER: Router = {
- GET: hello,
- /www/{path}*: { GET: get_www },
- /api/1: {
- }
+//
+// Hyper glue
+//
+
+async fn route_request(request: Request) -> Result, Error> {
+ let path = request.uri().path();
+
+ let (target, params) = ROUTER
+ .lookup(path)
+ .ok_or_else(|| format_err!("missing path: {}", path))?;
+
+ use hyper::Method;
+ let method = match *request.method() {
+ Method::GET => target.get.as_ref(),
+ Method::PUT => target.put.as_ref(),
+ Method::POST => target.post.as_ref(),
+ Method::DELETE => target.delete.as_ref(),
+ _ => bail!("unexpected method type"),
};
+
+ method
+ .ok_or_else(|| format_err!("no GET method for: {}", path))?
+ .call(params.unwrap_or(Value::Null))
+ .await
+}
+
+async fn service_func(request: Request) -> Result, hyper::Error> {
+ match route_request(request).await {
+ Ok(r) => Ok(r),
+ Err(err) => Ok(Response::builder()
+ .status(400)
+ .body(Body::from(format!("ERROR: {}", err)))
+ .expect("building an error response...")),
+ }
+}
+
+//
+// Main entry point
+//
+async fn main_do(www_dir: String) {
+ // Construct our SocketAddr to listen on...
+ let addr = ([0, 0, 0, 0], 3000).into();
+
+ // And a MakeService to handle each connection...
+ let service = make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(service_func)) });
+
+ // Then bind and serve...
+ let server = Server::bind(&addr).serve(service);
+
+ println!("Serving {} under http://localhost:3000/www/", www_dir);
+
+ if let Err(e) = server.await {
+ eprintln!("server error: {}", e);
+ }
+}
+
+fn main() {
+ // We expect a path, where to find our files we expose via the www/ dir:
+ let mut args = std::env::args();
+
+ // real code should have better error handling
+ let _program_name = args.next();
+ let www_dir = args.next().expect("expected a www/ subdirectory");
+ set_www_dir(www_dir.to_string());
+
+ // show our api info:
+ println!(
+ "{}",
+ serde_json::to_string_pretty(&ROUTER.api_dump()).unwrap()
+ );
+
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ rt.block_on(main_do(www_dir));
}