V2 API Enabling (#33)

* node height return value and documentation

* rustfmt

* add parameter struct for initiate tx functions

* rustfmt

* change tx estimate to use InitTxArgs

* rustfmt

* transaction estimate

* rustfmt

* initiate tx args fixed

* add send args to init

* rustfmt

* last owner api documentation

* api 2 wiring

* rustfmt

* wiring in V2 JSON-RPC API

* rustfmt

* some documentation on endpoint

* shorten endpoints
This commit is contained in:
Yeastplume
2019-04-01 11:16:49 +01:00
committed by GitHub
parent 427f42c552
commit 4bbce85b75
5 changed files with 186 additions and 9 deletions
+176 -7
View File
@@ -15,8 +15,7 @@
//! Controller for wallet.. instantiates and handles listeners (or single-run
//! invocations) as needed.
//! Still experimental
use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig};
use crate::apiwallet::{Foreign, Owner};
use crate::api::{self, ApiServer, BasicAuthMiddleware, ResponseFuture, Router, TLSConfig};
use crate::core::core;
use crate::core::core::Transaction;
use crate::impls::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
@@ -42,6 +41,10 @@ use std::sync::Arc;
use url::form_urlencoded;
use uuid::Uuid;
use crate::apiwallet::{Foreign, ForeignRpc, Owner, OwnerRpc};
use easy_jsonrpc;
use easy_jsonrpc::Handler;
/// Instantiate wallet Owner API for a single-use (command line) call
/// Return a function containing a loaded API context to call
pub fn owner_single_use<F, T: ?Sized, C, K>(wallet: Arc<Mutex<T>>, f: F) -> Result<(), Error>
@@ -79,11 +82,12 @@ pub fn owner_listener<T: ?Sized, C, K>(
) -> Result<(), Error>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
OwnerAPIHandler<T, C, K>: Handler,
OwnerAPIHandler<T, C, K>: api::Handler,
C: NodeClient + 'static,
K: Keychain + 'static,
{
let api_handler = OwnerAPIHandler::new(wallet.clone());
let api_handler_v2 = OwnerAPIHandlerV2::new(wallet.clone());
let mut router = Router::new();
if api_secret.is_some() {
@@ -93,10 +97,15 @@ where
let basic_auth_middleware = Arc::new(BasicAuthMiddleware::new(api_basic_auth, basic_realm));
router.add_middleware(basic_auth_middleware);
}
router
.add_route("/v1/wallet/owner/**", Arc::new(api_handler))
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
router
.add_route("/v2/owner", Arc::new(api_handler_v2))
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
// If so configured, add the foreign API to the same port
if owner_api_include_foreign.unwrap_or(false) {
info!("Starting HTTP Foreign API on Owner server at {}.", addr);
@@ -104,6 +113,11 @@ where
router
.add_route("/v1/wallet/foreign/**", Arc::new(foreign_api_handler))
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
let foreign_api_handler_v2 = ForeignAPIHandlerV2::new(wallet.clone());
router
.add_route("/v2/foreign", Arc::new(foreign_api_handler_v2))
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
}
let mut apis = ApiServer::new();
@@ -131,13 +145,18 @@ where
C: NodeClient + 'static,
K: Keychain + 'static,
{
let api_handler = ForeignAPIHandler::new(wallet);
let api_handler = ForeignAPIHandler::new(wallet.clone());
let api_handler_v2 = ForeignAPIHandlerV2::new(wallet);
let mut router = Router::new();
router
.add_route("/v1/wallet/foreign/**", Arc::new(api_handler))
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
router
.add_route("/v2/foreign", Arc::new(api_handler_v2))
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
let mut apis = ApiServer::new();
warn!("Starting HTTP Foreign listener API server at {}.", addr);
let socket_addr: SocketAddr = addr.parse().expect("unable to parse socket address");
@@ -592,7 +611,7 @@ where
}
}
impl<T: ?Sized, C, K> Handler for OwnerAPIHandler<T, C, K>
impl<T: ?Sized, C, K> api::Handler for OwnerAPIHandler<T, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
@@ -624,8 +643,83 @@ where
}
}
/// API Handler/Wrapper for foreign functions
/// V2 API Handler/Wrapper for owner functions
pub struct OwnerAPIHandlerV2<T: ?Sized, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
K: Keychain + 'static,
{
/// Wallet instance
pub wallet: Arc<Mutex<T>>,
phantom: PhantomData<K>,
phantom_c: PhantomData<C>,
}
impl<T: ?Sized, C, K> OwnerAPIHandlerV2<T, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
K: Keychain + 'static,
{
/// Create a new owner API handler for GET methods
pub fn new(wallet: Arc<Mutex<T>>) -> OwnerAPIHandlerV2<T, C, K> {
OwnerAPIHandlerV2 {
wallet,
phantom: PhantomData,
phantom_c: PhantomData,
}
}
fn call_api(
&self,
req: Request<Body>,
api: Owner<T, C, K>,
) -> Box<dyn Future<Item = serde_json::Value, Error = Error> + Send> {
Box::new(parse_body(req).and_then(move |val: serde_json::Value| {
let owner_api = &api as &dyn OwnerRpc;
match owner_api.handle_request(val) {
Some(r) => ok(r),
None => {
error!("OwnerAPI: call_api: failed with error");
err(ErrorKind::GenericError(format!("OwnerAPI Call Failed")).into())
}
}
}))
}
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
let api = Owner::new(self.wallet.clone());
Box::new(
self.call_api(req, api)
.and_then(|resp| ok(json_response_pretty(&resp))),
)
}
}
impl<T: ?Sized, C, K> api::Handler for OwnerAPIHandlerV2<T, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
K: Keychain + 'static,
{
fn post(&self, req: Request<Body>) -> ResponseFuture {
Box::new(
self.handle_post_request(req)
.and_then(|r| ok(r))
.or_else(|e| {
error!("Request Error: {:?}", e);
ok(create_error_response(e))
}),
)
}
fn options(&self, _req: Request<Body>) -> ResponseFuture {
Box::new(ok(create_ok_response("{}")))
}
}
/// API Handler/Wrapper for foreign functions
pub struct ForeignAPIHandler<T: ?Sized, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
@@ -710,7 +804,7 @@ where
}
}
}
impl<T: ?Sized, C, K> Handler for ForeignAPIHandler<T, C, K>
impl<T: ?Sized, C, K> api::Handler for ForeignAPIHandler<T, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + Send + Sync + 'static,
@@ -728,6 +822,81 @@ where
}
}
/// V2 API Handler/Wrapper for foreign functions
pub struct ForeignAPIHandlerV2<T: ?Sized, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
K: Keychain + 'static,
{
/// Wallet instance
pub wallet: Arc<Mutex<T>>,
phantom: PhantomData<K>,
phantom_c: PhantomData<C>,
}
impl<T: ?Sized, C, K> ForeignAPIHandlerV2<T, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
K: Keychain + 'static,
{
/// Create a new foreign API handler for GET methods
pub fn new(wallet: Arc<Mutex<T>>) -> ForeignAPIHandlerV2<T, C, K> {
ForeignAPIHandlerV2 {
wallet,
phantom: PhantomData,
phantom_c: PhantomData,
}
}
fn call_api(
&self,
req: Request<Body>,
api: Foreign<T, C, K>,
) -> Box<dyn Future<Item = serde_json::Value, Error = Error> + Send> {
Box::new(parse_body(req).and_then(move |val: serde_json::Value| {
let foreign_api = &api as &dyn ForeignRpc;
match foreign_api.handle_request(val) {
Some(r) => ok(r),
None => {
error!("ForeignAPI: call_api: failed with error");
err(ErrorKind::GenericError(format!("ForeignAPI Call Failed")).into())
}
}
}))
}
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
let api = Foreign::new(self.wallet.clone());
Box::new(
self.call_api(req, api)
.and_then(|resp| ok(json_response_pretty(&resp))),
)
}
}
impl<T: ?Sized, C, K> api::Handler for ForeignAPIHandlerV2<T, C, K>
where
T: WalletBackend<C, K> + Send + Sync + 'static,
C: NodeClient + 'static,
K: Keychain + 'static,
{
fn post(&self, req: Request<Body>) -> ResponseFuture {
Box::new(
self.handle_post_request(req)
.and_then(|r| ok(r))
.or_else(|e| {
error!("Request Error: {:?}", e);
ok(create_error_response(e))
}),
)
}
fn options(&self, _req: Request<Body>) -> ResponseFuture {
Box::new(ok(create_ok_response("{}")))
}
}
// Utility to serialize a struct into JSON and produce a sensible Response
// out of it.
fn json_response<T>(s: &T) -> Response<Body>