api_schema: allow generic api handler functions
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
135
src/api_schema/api_handler.rs
Normal file
135
src/api_schema/api_handler.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use failure::Error;
|
||||
use serde_json::Value;
|
||||
|
||||
use super::router::{ApiMethod, RpcEnvironment};
|
||||
|
||||
pub type ApiHandlerFn = Box<
|
||||
dyn Fn(Value, &ApiMethod, &mut dyn RpcEnvironment) -> Result<Value, Error>
|
||||
+ Send + Sync + 'static
|
||||
>;
|
||||
|
||||
pub trait WrapApiHandler<Args, R, MetaArgs> {
|
||||
fn wrap(self) -> ApiHandlerFn;
|
||||
}
|
||||
|
||||
// fn()
|
||||
impl<F, R> WrapApiHandler<(), R, ()> for F
|
||||
where
|
||||
F: Fn() -> Result<R, Error> + Send + Sync + 'static,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |_value, _method, _rpc_env| {
|
||||
Ok(serde_json::to_value((self)()?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn(Arg)
|
||||
impl<F, A, R> WrapApiHandler<(A,), R, ()> for F
|
||||
where
|
||||
F: Fn(A) -> Result<R, Error> + Send + Sync + 'static,
|
||||
A: serde::de::DeserializeOwned,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |value, _method, _rpc_env| {
|
||||
Ok(serde_json::to_value((self)(serde_json::from_value(value)?)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn(&ApiMethod)
|
||||
impl<F, R> WrapApiHandler<(), R, (ApiMethod,)> for F
|
||||
where
|
||||
F: Fn(&ApiMethod) -> Result<R, Error> + Send + Sync + 'static,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |_value, method, _rpc_env| {
|
||||
Ok(serde_json::to_value((self)(method)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn(Arg, &ApiMethod)
|
||||
impl<F, A, R> WrapApiHandler<(A,), R, (ApiMethod,)> for F
|
||||
where
|
||||
F: Fn(A, &ApiMethod) -> Result<R, Error> + Send + Sync + 'static,
|
||||
A: serde::de::DeserializeOwned,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |value, method, _rpc_env| {
|
||||
Ok(serde_json::to_value((self)(
|
||||
serde_json::from_value(value)?,
|
||||
method,
|
||||
)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// RpcEnvironment is a trait, so use a "marker" type for it instead:
|
||||
pub struct RpcEnvArg();
|
||||
|
||||
// fn(&mut dyn RpcEnvironment)
|
||||
impl<F, R> WrapApiHandler<(), R, (RpcEnvArg,)> for F
|
||||
where
|
||||
F: Fn(&mut dyn RpcEnvironment) -> Result<R, Error> + Send + Sync + 'static,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |_value, _method, rpc_env| {
|
||||
Ok(serde_json::to_value((self)(rpc_env)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn(Arg, &mut dyn RpcEnvironment)
|
||||
impl<F, A, R> WrapApiHandler<(A,), R, (RpcEnvArg,)> for F
|
||||
where
|
||||
F: Fn(A, &mut dyn RpcEnvironment) -> Result<R, Error> + Send + Sync + 'static,
|
||||
A: serde::de::DeserializeOwned,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |value, _method, rpc_env| {
|
||||
Ok(serde_json::to_value((self)(
|
||||
serde_json::from_value(value)?,
|
||||
rpc_env,
|
||||
)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn(&ApiMethod, &mut dyn RpcEnvironment)
|
||||
impl<F, R> WrapApiHandler<(), R, (ApiMethod, RpcEnvArg,)> for F
|
||||
where
|
||||
F: Fn(&ApiMethod, &mut dyn RpcEnvironment) -> Result<R, Error> + Send + Sync + 'static,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |_value, method, rpc_env| {
|
||||
Ok(serde_json::to_value((self)(method, rpc_env)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fn(Arg, &ApiMethod, &mut dyn RpcEnvironment)
|
||||
impl<F, A, R> WrapApiHandler<(A,), R, (ApiMethod, RpcEnvArg,)> for F
|
||||
where
|
||||
F: Fn(A, &ApiMethod, &mut dyn RpcEnvironment) -> Result<R, Error> + Send + Sync + 'static,
|
||||
A: serde::de::DeserializeOwned,
|
||||
R: serde::Serialize,
|
||||
{
|
||||
fn wrap(self) -> ApiHandlerFn {
|
||||
Box::new(move |value, method, rpc_env| {
|
||||
Ok(serde_json::to_value((self)(
|
||||
serde_json::from_value(value)?,
|
||||
method,
|
||||
rpc_env,
|
||||
)?)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ use hyper::{Body, Response, StatusCode};
|
||||
use hyper::rt::Future;
|
||||
use hyper::http::request::Parts;
|
||||
|
||||
use super::api_handler::*;
|
||||
|
||||
pub type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
|
||||
|
||||
/// Abstract Interface for API methods to interact with the environment
|
||||
@ -72,9 +74,10 @@ macro_rules! http_err {
|
||||
}}
|
||||
}
|
||||
|
||||
type ApiHandlerFn = fn(Value, &ApiMethod, &mut dyn RpcEnvironment) -> Result<Value, Error>;
|
||||
|
||||
type ApiAsyncHandlerFn = fn(Parts, Body, Value, &ApiAsyncMethod, &mut dyn RpcEnvironment) -> Result<BoxFut, Error>;
|
||||
type ApiAsyncHandlerFn = Box<
|
||||
dyn Fn(Parts, Body, Value, &ApiAsyncMethod, &mut dyn RpcEnvironment) -> Result<BoxFut, Error>
|
||||
+ Send + Sync + 'static
|
||||
>;
|
||||
|
||||
/// This struct defines synchronous API call which returns the restulkt as json `Value`
|
||||
pub struct ApiMethod {
|
||||
@ -89,15 +92,28 @@ pub struct ApiMethod {
|
||||
/// Return type Schema
|
||||
pub returns: Arc<Schema>,
|
||||
/// Handler function
|
||||
pub handler: ApiHandlerFn,
|
||||
pub handler: Option<ApiHandlerFn>,
|
||||
}
|
||||
|
||||
impl ApiMethod {
|
||||
|
||||
pub fn new(handler: ApiHandlerFn, parameters: ObjectSchema) -> Self {
|
||||
pub fn new<F, Args, R, MetaArgs>(func: F, parameters: ObjectSchema) -> Self
|
||||
where
|
||||
F: WrapApiHandler<Args, R, MetaArgs>,
|
||||
{
|
||||
Self {
|
||||
parameters,
|
||||
handler,
|
||||
handler: Some(func.wrap()),
|
||||
returns: Arc::new(Schema::Null),
|
||||
protected: false,
|
||||
reload_timezone: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_dummy(parameters: ObjectSchema) -> Self {
|
||||
Self {
|
||||
parameters,
|
||||
handler: None,
|
||||
returns: Arc::new(Schema::Null),
|
||||
protected: false,
|
||||
reload_timezone: false,
|
||||
@ -134,10 +150,14 @@ pub struct ApiAsyncMethod {
|
||||
|
||||
impl ApiAsyncMethod {
|
||||
|
||||
pub fn new(handler: ApiAsyncHandlerFn, parameters: ObjectSchema) -> Self {
|
||||
pub fn new<F>(handler: F, parameters: ObjectSchema) -> Self
|
||||
where
|
||||
F: Fn(Parts, Body, Value, &ApiAsyncMethod, &mut dyn RpcEnvironment) -> Result<BoxFut, Error>
|
||||
+ Send + Sync + 'static,
|
||||
{
|
||||
Self {
|
||||
parameters,
|
||||
handler,
|
||||
handler: Box::new(handler),
|
||||
returns: Arc::new(Schema::Null),
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user