implement ApiHandler::Async

This commit is contained in:
Dietmar Maurer 2019-12-16 09:53:25 +01:00
parent d9897316b8
commit 7dadea06dd
4 changed files with 65 additions and 6 deletions

@ -18,6 +18,7 @@ serde_json = "1.0"
textwrap = "0.11"
url = "2.1"
tokio = { version = "0.2", features = [], optional = true }
hyper = { version = "0.13", optional = true }
[dev-dependencies]
@ -25,5 +26,5 @@ lazy_static = "1.3"
[features]
default = [ "router", "cli" ]
router = [ "hyper" ]
cli = [ "router", "hyper" ]
router = [ "hyper", "tokio" ]
cli = [ "router", "hyper", "tokio" ]

@ -58,6 +58,22 @@ fn handle_simple_command(
return Err(err);
}
},
ApiHandler::Async(handler) => {
let future = (handler)(params, &cli_cmd.info, &mut rpcenv);
let mut rt = tokio::runtime::Runtime::new().unwrap();
match rt.block_on(future) {
Ok(value) => {
if value != Value::Null {
println!("Result: {}", serde_json::to_string_pretty(&value).unwrap());
}
}
Err(err) => {
eprintln!("Error: {}", err);
return Err(err);
}
}
}
ApiHandler::AsyncHttp(_) => {
let err_msg = "CliHandler does not support ApiHandler::AsyncHttp - internal error";
print_simple_usage_error(prefix, cli_cmd, err_msg);

@ -29,7 +29,9 @@ pub mod router;
#[cfg(feature = "router")]
#[doc(inline)]
pub use router::{ApiFuture, ApiHandler, ApiMethod, Router, SubRoute, SubdirMap};
pub use router::{
ApiFuture, ApiHandler, ApiMethod, ApiResponseFuture, Router, SubRoute, SubdirMap,
};
#[cfg(feature = "cli")]
pub mod cli;

@ -38,6 +38,38 @@ pub type ApiHandlerFn = &'static (dyn Fn(Value, &ApiMethod, &mut dyn RpcEnvironm
+ Sync
+ 'static);
/// Asynchronous API handlers
///
/// Returns a future Value.
/// ```
/// # use failure::*;
/// # use serde_json::{json, Value};
/// # use proxmox_api::{*, schema::*};
/// #
/// use futures::*;
///
/// fn hello_future<'a>(
/// param: Value,
/// info: &ApiMethod,
/// rpcenv: &'a mut dyn RpcEnvironment,
/// ) -> ApiFuture<'a> {
/// async move {
/// let data = json!("hello world!");
/// Ok(data)
/// }.boxed()
/// }
///
/// const API_METHOD_HELLO_FUTURE: ApiMethod = ApiMethod::new(
/// &ApiHandler::Async(&hello_future),
/// &ObjectSchema::new("Hello World Example (async)", &[])
/// );
/// ```
pub type ApiAsyncHandlerFn = &'static (dyn for<'a> Fn(Value, &'static ApiMethod, &'a mut dyn RpcEnvironment) -> ApiFuture<'a>
+ Send
+ Sync);
pub type ApiFuture<'a> = Pin<Box<dyn Future<Output = Result<Value, failure::Error>> + Send + 'a>>;
/// Asynchronous HTTP API handlers
///
/// They get low level access to request and response data. Use this
@ -56,7 +88,7 @@ pub type ApiHandlerFn = &'static (dyn Fn(Value, &ApiMethod, &mut dyn RpcEnvironm
/// param: Value,
/// info: &ApiMethod,
/// rpcenv: Box<dyn RpcEnvironment>,
/// ) -> ApiFuture {
/// ) -> ApiResponseFuture {
/// async move {
/// let response = http::Response::builder()
/// .status(200)
@ -70,17 +102,25 @@ pub type ApiHandlerFn = &'static (dyn Fn(Value, &ApiMethod, &mut dyn RpcEnvironm
/// &ObjectSchema::new("Hello World Example (low level)", &[])
/// );
/// ```
pub type ApiAsyncHttpHandlerFn = &'static (dyn Fn(Parts, Body, Value, &'static ApiMethod, Box<dyn RpcEnvironment>) -> ApiFuture
pub type ApiAsyncHttpHandlerFn = &'static (dyn Fn(
Parts,
Body,
Value,
&'static ApiMethod,
Box<dyn RpcEnvironment>,
) -> ApiResponseFuture
+ Send
+ Sync
+ 'static);
/// The output of an asynchronous API handler is a futrue yielding a `Response`.
pub type ApiFuture = Pin<Box<dyn Future<Output = Result<Response<Body>, failure::Error>> + Send>>;
pub type ApiResponseFuture =
Pin<Box<dyn Future<Output = Result<Response<Body>, failure::Error>> + Send>>;
/// Enum for different types of API handler functions.
pub enum ApiHandler {
Sync(ApiHandlerFn),
Async(ApiAsyncHandlerFn),
AsyncHttp(ApiAsyncHttpHandlerFn),
}