forked from loafle/openapi-generator-original
[Rust Server] Hyper 0.13 + Async/Await support (#6244)
* [Rust Server] Hyper 0.13 + Async/Await support Upgrade dependencies to Hyper 0.13 and use async/await. * [Rust Server] Add missing hyper-tls dependency * [Rust Server] Add missing models import * Update samples
This commit is contained in:
committed by
GitHub
parent
c3ac84cec2
commit
82410ae90b
@@ -27,7 +27,7 @@ client = [
|
||||
"serde_ignored", "regex", "percent-encoding", "lazy_static",
|
||||
{{/hasCallbacks}}
|
||||
{{! Anything added to the list below, should probably be added to the callbacks list below }}
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
{{#apiUsesMultipart}}
|
||||
@@ -40,7 +40,7 @@ server = [
|
||||
"hyper_0_10", "mime_multipart",
|
||||
{{/apiUsesMultipartRelated}}
|
||||
{{#hasCallbacks}}
|
||||
"native-tls", "hyper-openssl", "openssl",
|
||||
"native-tls", "hyper-openssl", "hyper-tls", "openssl",
|
||||
{{/hasCallbacks}}
|
||||
{{! Anything added to the list below, should probably be added to the callbacks list above }}
|
||||
"serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static"
|
||||
@@ -49,20 +49,22 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
@@ -78,27 +80,27 @@ mime_0_2 = { package = "mime", version = "0.2.6", optional = true }
|
||||
multipart = { version = "0.16", default-features = false, optional = true }
|
||||
{{/apiUsesMultipartFormData}}
|
||||
{{#apiUsesUuid}}
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
uuid = {version = "0.8", features = ["serde", "v4"]}
|
||||
{{/apiUsesUuid}}
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
{{#apiUsesMultipartRelated}}
|
||||
mime_multipart = {version = "0.5", optional = true}
|
||||
hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true}
|
||||
{{/apiUsesMultipartRelated}}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
{{#usesUrlEncodedForm}}
|
||||
serde_urlencoded = {version = "0.5.1", optional = true}
|
||||
serde_urlencoded = {version = "0.6.1", optional = true}
|
||||
{{/usesUrlEncodedForm}}
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -109,15 +111,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
{{^apiUsesUuid}}
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
{{/apiUsesUuid}}
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
use futures;
|
||||
use futures::{Future, Stream, future, stream};
|
||||
use hyper;
|
||||
use hyper::client::HttpConnector;
|
||||
use async_trait::async_trait;
|
||||
use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use hyper::{Body, Uri, Response};
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use hyper_openssl::HttpsConnector;
|
||||
use serde_json;
|
||||
use hyper::{Body, Request, Response, service::Service, Uri};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Read, Error, ErrorKind};
|
||||
use std::error;
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use swagger;
|
||||
use swagger::{ApiError, Connector, client::Service, XSpanIdString, Has, AuthData};
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, AuthData, BodyExt, Connector, Has, XSpanIdString};
|
||||
use url::form_urlencoded;
|
||||
use url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET};
|
||||
|
||||
{{#apiUsesMultipartFormData}}
|
||||
use mime::Mime;
|
||||
use std::io::Cursor;
|
||||
@@ -30,20 +27,18 @@ use multipart::client::lazy::Multipart;
|
||||
use hyper_0_10::header::{Headers, ContentType};
|
||||
use mime_multipart::{Node, Part, generate_boundary, write_multipart};
|
||||
{{/apiUsesMultipartRelated}}
|
||||
{{#apiUsesUuid}}
|
||||
use uuid;
|
||||
{{/apiUsesUuid}}
|
||||
{{#usesXml}}
|
||||
use serde_xml_rs;
|
||||
{{/usesXml}}
|
||||
|
||||
use crate::models;
|
||||
use crate::header;
|
||||
|
||||
url::define_encode_set! {
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
pub ID_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'|'}
|
||||
}
|
||||
/// https://url.spec.whatwg.org/#fragment-percent-encode-set
|
||||
#[allow(dead_code)]
|
||||
const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
|
||||
.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
|
||||
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
#[allow(dead_code)]
|
||||
const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');
|
||||
|
||||
@@ -8,11 +8,11 @@ pub mod callbacks;
|
||||
|
||||
{{/hasCallbacks}}
|
||||
/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.
|
||||
fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
fn into_base_path(input: impl TryInto<Uri, Error=hyper::http::uri::InvalidUri>, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
// First convert to Uri, since a base path is a subset of Uri.
|
||||
let uri = Uri::from_str(input)?;
|
||||
let uri = input.try_into()?;
|
||||
|
||||
let scheme = uri.scheme_part().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
|
||||
// Check the scheme if necessary
|
||||
if let Some(correct_scheme) = correct_scheme {
|
||||
@@ -22,38 +22,54 @@ fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<S
|
||||
}
|
||||
|
||||
let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?;
|
||||
let port = uri.port_part().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/')))
|
||||
}
|
||||
|
||||
/// A client that implements the API by making HTTP calls out to a server.
|
||||
pub struct Client<F>
|
||||
pub struct Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
/// Inner service
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
|
||||
/// Base path of the API
|
||||
base_path: String,
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for Client<F>
|
||||
impl<S> fmt::Debug for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Client {{ base_path: {} }}", self.base_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Clone for Client<F>
|
||||
impl<S> Clone for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Client {
|
||||
Self {
|
||||
client_service: self.client_service.clone(),
|
||||
base_path: self.base_path.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::ResponseFuture>
|
||||
impl<C> Client<hyper::client::Client<C, Body>> where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create a client with a custom implementation of hyper::client::Connect.
|
||||
///
|
||||
@@ -66,30 +82,93 @@ impl Client<hyper::client::ResponseFuture>
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
/// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")`
|
||||
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
|
||||
pub fn try_new_with_connector<C>(
|
||||
pub fn try_new_with_connector(
|
||||
base_path: &str,
|
||||
protocol: Option<&'static str>,
|
||||
connector: C,
|
||||
) -> Result<Self, ClientInitError> where
|
||||
C: hyper::client::connect::Connect + 'static,
|
||||
C::Transport: 'static,
|
||||
C::Future: 'static,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let client_service = Box::new(hyper::client::Client::builder().build(connector));
|
||||
let client_service = hyper::client::Client::builder().build(connector);
|
||||
|
||||
Ok(Client {
|
||||
client_service: Arc::new(client_service),
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, protocol)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HyperClient {
|
||||
Http(hyper::client::Client<hyper::client::HttpConnector, Body>),
|
||||
Https(hyper::client::Client<HttpsConnector, Body>),
|
||||
}
|
||||
|
||||
impl Service<Request<Body>> for HyperClient {
|
||||
type Response = Response<Body>;
|
||||
type Error = hyper::Error;
|
||||
type Future = hyper::client::ResponseFuture;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.poll_ready(cx),
|
||||
HyperClient::Https(client) => client.poll_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.call(req),
|
||||
HyperClient::Https(client) => client.call(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<HyperClient> {
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
let uri = Uri::from_str(base_path)?;
|
||||
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = scheme.to_ascii_lowercase();
|
||||
|
||||
let connector = Connector::builder();
|
||||
|
||||
let client_service = match scheme.as_str() {
|
||||
"http" => {
|
||||
HyperClient::Http(hyper::client::Client::builder().build(connector.build()))
|
||||
},
|
||||
"https" => {
|
||||
let connector = connector.https()
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
HyperClient::Https(hyper::client::Client::builder().build(connector))
|
||||
},
|
||||
_ => {
|
||||
return Err(ClientInitError::InvalidScheme);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::Client<hyper::client::HttpConnector, Body>>
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new_http(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
@@ -97,11 +176,20 @@ impl Client<hyper::client::ResponseFuture>
|
||||
|
||||
Self::try_new_with_connector(base_path, Some("http"), http_connector)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
impl Client<hyper::client::Client<HttpsConnector, Body>>
|
||||
{
|
||||
/// Create a client with a TLS connection to the server
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
pub fn try_new_https(base_path: &str) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let https_connector = Connector::builder()
|
||||
@@ -114,7 +202,7 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// Create a client with a TLS connection to the server using a pinned certificate
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
pub fn try_new_https_pinned<CA>(
|
||||
@@ -135,7 +223,7 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// Create a client with a mutually authenticated TLS connection to the server.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
/// * `client_key` - Path to the client private key
|
||||
/// * `client_certificate` - Path to the client's public certificate associated with the private key
|
||||
@@ -161,17 +249,24 @@ impl Client<hyper::client::ResponseFuture>
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Client<F>
|
||||
impl<S> Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `swagger::Service`
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `hyper::service::Service` /
|
||||
/// `tower::Service`
|
||||
///
|
||||
/// This allows adding custom wrappers around the underlying transport, for example for logging.
|
||||
pub fn try_new_with_client_service(
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
Ok(Client {
|
||||
client_service: client_service,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
})
|
||||
}
|
||||
@@ -211,16 +306,29 @@ impl fmt::Display for ClientInitError {
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ClientInitError {
|
||||
impl Error for ClientInitError {
|
||||
fn description(&self) -> &str {
|
||||
"Failed to produce a hyper client."
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, F> Api<C> for Client<F> where
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}},
|
||||
F: Future<Item=Response<Body>, Error=hyper::Error> + Send + 'static
|
||||
#[async_trait]
|
||||
impl<C, S> Api<C> for Client<S> where
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}} + Clone + Send + Sync + 'static,
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
|
||||
match self.client_service.clone().poll_ready(cx) {
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
|
||||
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
@@ -8,8 +8,9 @@
|
||||
{{#allParams}}
|
||||
param_{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>
|
||||
context: &C) -> Result<{{{operationId}}}Response, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
{{#isCallbackRequest}}
|
||||
"{{vendorExtensions.x-path-format-string}}"
|
||||
@@ -29,105 +30,113 @@
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
{{#queryParams}}
|
||||
{{^required}}
|
||||
if let Some(param_{{{paramName}}}) = param_{{{paramName}}} {
|
||||
if let Some(param_{{{paramName}}}) = param_{{{paramName}}} {
|
||||
{{/required}}
|
||||
query_string.append_pair("{{{baseName}}}", ¶m_{{{paramName}}}{{#isListContainer}}.iter().map(ToString::to_string).collect::<Vec<String>>().join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
|
||||
query_string.append_pair("{{{baseName}}}", ¶m_{{{paramName}}}{{#isListContainer}}.iter().map(ToString::to_string).collect::<Vec<String>>().join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
|
||||
{{^required}}
|
||||
}
|
||||
}
|
||||
{{/required}}
|
||||
{{/queryParams}}
|
||||
{{#authMethods}}
|
||||
{{#isApiKey}}
|
||||
{{#isKeyInQuery}}
|
||||
if let Some(auth_data) = (context as &dyn Has<Option<AuthData>>).get().as_ref() {
|
||||
if let AuthData::ApiKey(ref api_key) = *auth_data {
|
||||
query_string.append_pair("{{keyParamName}}", api_key);
|
||||
if let Some(auth_data) = (context as &dyn Has<Option<AuthData>>).get().as_ref() {
|
||||
if let AuthData::ApiKey(ref api_key) = *auth_data {
|
||||
query_string.append_pair("{{keyParamName}}", api_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/isKeyInQuery}}
|
||||
{{/isApiKey}}
|
||||
{{/authMethods}}
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("{{{vendorExtensions.HttpMethod}}}")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
{{#vendorExtensions}}
|
||||
{{#consumesMultipart}}
|
||||
let mut multipart = Multipart::new();
|
||||
let (body_string, multipart_header) = {
|
||||
let mut multipart = Multipart::new();
|
||||
|
||||
{{#vendorExtensions}}
|
||||
{{#formParams}}
|
||||
{{#-first}}
|
||||
// For each parameter, encode as appropriate and add to the multipart body as a stream.
|
||||
// For each parameter, encode as appropriate and add to the multipart body as a stream.
|
||||
{{/-first}}
|
||||
|
||||
{{^isByteArray}}
|
||||
{{#jsonSchema}}
|
||||
let {{{paramName}}}_str = match serde_json::to_string(¶m_{{{paramName}}}) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to parse {{{paramName}}} to string: {}", e)))),
|
||||
};
|
||||
let {{{paramName}}}_str = match serde_json::to_string(¶m_{{{paramName}}}) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Err(ApiError(format!("Unable to parse {{{paramName}}} to string: {}", e))),
|
||||
};
|
||||
|
||||
let {{{paramName}}}_vec = {{{paramName}}}_str.as_bytes().to_vec();
|
||||
let {{{paramName}}}_vec = {{{paramName}}}_str.as_bytes().to_vec();
|
||||
let {{{paramName}}}_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec);
|
||||
|
||||
let {{{paramName}}}_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
|
||||
let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec);
|
||||
|
||||
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime));
|
||||
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime));
|
||||
{{/jsonSchema}}
|
||||
{{/isByteArray}}
|
||||
|
||||
{{#isByteArray}}
|
||||
let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec();
|
||||
let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec();
|
||||
|
||||
let {{{paramName}}}_mime = match mime_0_2::Mime::from_str("application/octet-stream") {
|
||||
Ok(mime) => mime,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to get mime type: {:?}", err)))),
|
||||
};
|
||||
let {{{paramName}}}_mime = match mime_0_2::Mime::from_str("application/octet-stream") {
|
||||
Ok(mime) => mime,
|
||||
Err(err) => return Err(ApiError(format!("Unable to get mime type: {:?}", err))),
|
||||
};
|
||||
|
||||
let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec);
|
||||
let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec);
|
||||
|
||||
let filename = None as Option<&str> ;
|
||||
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, filename, Some({{{paramName}}}_mime));
|
||||
let filename = None as Option<&str> ;
|
||||
multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, filename, Some({{{paramName}}}_mime));
|
||||
{{/isByteArray}}
|
||||
{{/formParams}}
|
||||
{{/vendorExtensions}}
|
||||
let mut fields = match multipart.prepare() {
|
||||
Ok(fields) => fields,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build request: {}", err)))),
|
||||
|
||||
let mut fields = match multipart.prepare() {
|
||||
Ok(fields) => fields,
|
||||
Err(err) => return Err(ApiError(format!("Unable to build request: {}", err))),
|
||||
};
|
||||
|
||||
let mut body_string = String::new();
|
||||
|
||||
match fields.read_to_string(&mut body_string) {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build body: {}", err))),
|
||||
}
|
||||
|
||||
let boundary = fields.boundary();
|
||||
|
||||
let multipart_header = format!("multipart/form-data;boundary={}", boundary);
|
||||
|
||||
(body_string, multipart_header)
|
||||
};
|
||||
|
||||
let mut body_string = String::new();
|
||||
match fields.read_to_string(&mut body_string) {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build body: {}", err)))),
|
||||
}
|
||||
let boundary = fields.boundary();
|
||||
|
||||
let multipart_header = format!("multipart/form-data;boundary={}", boundary);
|
||||
|
||||
*request.body_mut() = Body::from(body_string);
|
||||
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e)))
|
||||
});
|
||||
|
||||
{{/consumesMultipart}}
|
||||
@@ -146,7 +155,7 @@
|
||||
let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}";
|
||||
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
*request.body_mut() = Body::from(body.into_bytes());
|
||||
{{/-last}}
|
||||
@@ -209,7 +218,7 @@
|
||||
&[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat()
|
||||
) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
|
||||
{{/-last}}
|
||||
@@ -264,7 +273,7 @@
|
||||
let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}";
|
||||
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
{{#-last}}
|
||||
|
||||
@@ -272,14 +281,14 @@
|
||||
{{/bodyParam}}
|
||||
{{/consumesMultipart}}
|
||||
{{/vendorExtensions}}
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
{{#hasAuthMethods}}
|
||||
if let Some(auth_data) = (context as &dyn Has<Option<AuthData>>).get().as_ref() {
|
||||
if let Some(auth_data) = Has::<Option<AuthData>>::get(context).as_ref() {
|
||||
// Currently only authentication with Basic and Bearer are supported
|
||||
match auth_data {
|
||||
{{#authMethods}}
|
||||
@@ -288,7 +297,7 @@
|
||||
let auth = swagger::auth::Header(basic_header.clone());
|
||||
let header = match HeaderValue::from_str(&format!("{}", auth)) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create Authorization header: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e)))
|
||||
};
|
||||
request.headers_mut().insert(
|
||||
hyper::header::AUTHORIZATION,
|
||||
@@ -300,7 +309,7 @@
|
||||
let auth = swagger::auth::Header(bearer_header.clone());
|
||||
let header = match HeaderValue::from_str(&format!("{}", auth)) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create Authorization header: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e)))
|
||||
};
|
||||
request.headers_mut().insert(
|
||||
hyper::header::AUTHORIZATION,
|
||||
@@ -313,7 +322,7 @@
|
||||
let auth = swagger::auth::Header(bearer_header.clone());
|
||||
let header = match HeaderValue::from_str(&format!("{}", auth)) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create Authorization header: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e)))
|
||||
};
|
||||
request.headers_mut().insert(
|
||||
hyper::header::AUTHORIZATION,
|
||||
@@ -341,8 +350,8 @@
|
||||
match header::IntoHeaderValue(param_{{{paramName}}}.clone()).try_into() {
|
||||
Ok(header) => header,
|
||||
Err(e) => {
|
||||
return Box::new(future::err(ApiError(format!(
|
||||
"Invalid header {{{paramName}}} - {}", e)))) as Box<dyn Future<Item=_, Error=_> + Send>;
|
||||
return Err(ApiError(format!(
|
||||
"Invalid header {{{paramName}}} - {}", e)));
|
||||
},
|
||||
});
|
||||
{{^required}}
|
||||
@@ -356,111 +365,102 @@
|
||||
{{/isMapContainer}}
|
||||
|
||||
{{/headerParams}}
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
{{#responses}}
|
||||
{{{code}}} => {
|
||||
{{{code}}} => {
|
||||
{{#headers}}
|
||||
let response_{{{name}}} = match response.headers().get(HeaderName::from_static("{{{nameInLowerCase}}}")) {
|
||||
Some(response_{{{name}}}) => response_{{{name}}}.clone(),
|
||||
None => return Box::new(future::err(ApiError(String::from("Required response header {{{baseName}}} for response {{{code}}} was not found.")))) as Box<dyn Future<Item=_, Error=_> + Send>,
|
||||
};
|
||||
let response_{{{name}}} = match TryInto::<header::IntoHeaderValue<{{{dataType}}}>>::try_into(response_{{{name}}}) {
|
||||
Ok(value) => value,
|
||||
Err(e) => {
|
||||
return Box::new(future::err(ApiError(format!("Invalid response header {{baseName}} for response {{code}} - {}", e)))) as Box<dyn Future<Item=_, Error=_> + Send>;
|
||||
},
|
||||
};
|
||||
let response_{{{name}}} = response_{{{name}}}.0;
|
||||
let response_{{{name}}} = match response.headers().get(HeaderName::from_static("{{{nameInLowerCase}}}")) {
|
||||
Some(response_{{{name}}}) => response_{{{name}}}.clone(),
|
||||
None => {
|
||||
return Err(ApiError(String::from("Required response header {{{baseName}}} for response {{{code}}} was not found.")));
|
||||
}
|
||||
};
|
||||
let response_{{{name}}} = match TryInto::<header::IntoHeaderValue<{{{dataType}}}>>::try_into(response_{{{name}}}) {
|
||||
Ok(value) => value,
|
||||
Err(e) => {
|
||||
return Err(ApiError(format!("Invalid response header {{baseName}} for response {{code}} - {}", e)));
|
||||
},
|
||||
};
|
||||
let response_{{{name}}} = response_{{{name}}}.0;
|
||||
|
||||
{{/headers}}
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
let body = response.into_body();
|
||||
{{#dataType}}
|
||||
body
|
||||
.concat2()
|
||||
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
|
||||
.and_then(|body|
|
||||
let body = body
|
||||
.to_raw()
|
||||
.map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
|
||||
{{#vendorExtensions}}
|
||||
{{#producesBytes}}
|
||||
Ok(swagger::ByteArray(body.to_vec()))
|
||||
let body = swagger::ByteArray(body.to_vec());
|
||||
{{/producesBytes}}
|
||||
{{^producesBytes}}
|
||||
str::from_utf8(&body)
|
||||
.map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))
|
||||
.and_then(|body|
|
||||
let body = str::from_utf8(&body)
|
||||
.map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
|
||||
{{#producesXml}}
|
||||
// ToDo: this will move to swagger-rs and become a standard From conversion trait
|
||||
// once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
|
||||
serde_xml_rs::from_str::<{{{dataType}}}>(body)
|
||||
.map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))
|
||||
// ToDo: this will move to swagger-rs and become a standard From conversion trait
|
||||
// once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
|
||||
let body = serde_xml_rs::from_str::<{{{dataType}}}>(body)
|
||||
.map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
|
||||
{{/producesXml}}
|
||||
{{#producesJson}}
|
||||
serde_json::from_str::<{{{dataType}}}>(body)
|
||||
.map_err(|e| e.into())
|
||||
let body = serde_json::from_str::<{{{dataType}}}>(body)?;
|
||||
{{/producesJson}}
|
||||
{{#producesPlainText}}
|
||||
Ok(body.to_string())
|
||||
let body = body.to_string();
|
||||
{{/producesPlainText}}
|
||||
)
|
||||
{{/producesBytes}}
|
||||
{{/vendorExtensions}}
|
||||
)
|
||||
.map(move |body| {
|
||||
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}
|
||||
Ok({{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}
|
||||
{{^headers}}
|
||||
(body)
|
||||
(body)
|
||||
{{/headers}}
|
||||
{{#headers}}
|
||||
{{#-first}}
|
||||
{
|
||||
body: body,
|
||||
{
|
||||
body: body,
|
||||
{{/-first}}
|
||||
{{{name}}}: response_{{name}},
|
||||
{{{name}}}: response_{{name}},
|
||||
{{#-last}}
|
||||
}
|
||||
}
|
||||
{{/-last}}
|
||||
{{/headers}}
|
||||
})
|
||||
)
|
||||
{{/dataType}}
|
||||
{{^dataType}}
|
||||
future::ok(
|
||||
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}
|
||||
Ok(
|
||||
{{{operationId}}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}
|
||||
{{#headers}}
|
||||
{{#-first}}
|
||||
{
|
||||
{
|
||||
{{/-first}}
|
||||
{{{name}}}: response_{{name}},
|
||||
{{{name}}}: response_{{name}},
|
||||
{{#-last}}
|
||||
}
|
||||
}
|
||||
{{/-last}}
|
||||
{{/headers}}
|
||||
)
|
||||
)
|
||||
{{/dataType}}
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
{{/responses}}
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
}
|
||||
}))
|
||||
{{/responses}}
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,24 +83,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
{{#authMethods}}
|
||||
{{#isBasic}}
|
||||
@@ -119,12 +114,7 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{{/isBasic}}
|
||||
@@ -137,12 +127,7 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{{/isOAuth}}
|
||||
@@ -156,18 +141,13 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{{/isKeyInHeader}}
|
||||
{{#isKeyInQuery}}
|
||||
{
|
||||
let key = form_urlencoded::parse(head.uri.query().unwrap_or_default().as_bytes())
|
||||
let key = form_urlencoded::parse(request.uri().query().unwrap_or_default().as_bytes())
|
||||
.filter(|e| e.0 == "api_key_query")
|
||||
.map(|e| e.1.clone().into_owned())
|
||||
.nth(0);
|
||||
@@ -176,11 +156,7 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{{/isKeyInQuery}}
|
||||
@@ -189,11 +165,7 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,18 @@ mod server;
|
||||
{{/hasCallbacks}}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use {{{externCrateName}}}::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}},
|
||||
{{{operationId}}}Response{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{{operationId}}}Response,
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -18,7 +25,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -66,21 +75,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
{{#hasCallbacks}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{>example-server-common}}
|
||||
use {{{externCrateName}}}::{CallbackApi, ApiError};
|
||||
use {{{externCrateName}}}::CallbackApi;
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -16,8 +16,12 @@ use {{{externCrateName}}}::{{{operationId}}}Response;
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
use {{{externCrateName}}}::client::callbacks::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> CallbackApi<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
#[async_trait]
|
||||
impl<C> CallbackApi<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use {{{externCrateName}}}::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
{{{externCrateName}}}::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:{{{serverPort}}}";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
@@ -11,9 +11,9 @@
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>
|
||||
context: &C) -> Result<{{{operationId}}}Response, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{{paramName}}}{{/allParams}}, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
use {{{externCrateName}}}::{
|
||||
Api,
|
||||
ApiError,
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -14,8 +13,12 @@ use {{{externCrateName}}}::{
|
||||
{{/apiInfo}}
|
||||
};
|
||||
use {{{externCrateName}}}::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use std::io::Error;
|
||||
use std::error::Error;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::{ApiError, ContextWrapper};
|
||||
|
||||
#[deprecated(note = "Import swagger-rs directly")]
|
||||
pub use swagger::{ApiError, ContextWrapper};
|
||||
#[deprecated(note = "Import futures directly")]
|
||||
pub use futures::Future;
|
||||
type ServiceError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub const BASE_PATH: &'static str = "{{{basePathWithoutHost}}}";
|
||||
{{#appVersion}}
|
||||
@@ -23,7 +23,12 @@ pub const API_VERSION: &'static str = "{{{appVersion}}}";
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
#[async_trait]
|
||||
pub trait Api<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -31,12 +36,12 @@ pub trait Api<C> {
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<{{{operationId}}}Response, ApiError>;
|
||||
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
@@ -44,8 +49,14 @@ pub trait Api<C> {
|
||||
{{/apiInfo}}
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
pub trait ApiNoContext {
|
||||
/// API where `Context` isn't passed on every API call
|
||||
#[async_trait]
|
||||
pub trait ApiNoContext<C: Send + Sync> {
|
||||
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -53,12 +64,12 @@ pub trait ApiNoContext {
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>;
|
||||
) -> Result<{{{operationId}}}Response, ApiError>;
|
||||
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
@@ -67,18 +78,28 @@ pub trait ApiNoContext {
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait ContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
#[async_trait]
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -86,14 +107,15 @@ impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>
|
||||
) -> Result<{{{operationId}}}Response, ApiError>
|
||||
{
|
||||
self.api().{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{{paramName}}}, {{/allParams}}&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}({{#allParams}}{{{paramName}}}, {{/allParams}}&context).await
|
||||
}
|
||||
|
||||
{{/operation}}
|
||||
@@ -101,6 +123,7 @@ impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
}
|
||||
|
||||
{{#hasCallbacks}}
|
||||
|
||||
{{#apiInfo}}
|
||||
@@ -120,7 +143,12 @@ impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
{{/apiInfo}}
|
||||
|
||||
/// Callback API
|
||||
pub trait CallbackApi<C> {
|
||||
#[async_trait]
|
||||
pub trait CallbackApi<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -131,7 +159,7 @@ pub trait CallbackApi<C> {
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
@@ -141,7 +169,7 @@ pub trait CallbackApi<C> {
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
context: &C) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<{{{operationId}}}Response, ApiError>;
|
||||
|
||||
{{/requests}}
|
||||
{{/urls}}
|
||||
@@ -153,7 +181,12 @@ pub trait CallbackApi<C> {
|
||||
}
|
||||
|
||||
/// Callback API without a `Context`
|
||||
pub trait CallbackApiNoContext {
|
||||
#[async_trait]
|
||||
pub trait CallbackApiNoContext<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -164,7 +197,7 @@ pub trait CallbackApiNoContext {
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
@@ -174,7 +207,7 @@ pub trait CallbackApiNoContext {
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>;
|
||||
) -> Result<{{{operationId}}}Response, ApiError>;
|
||||
|
||||
{{/requests}}
|
||||
{{/urls}}
|
||||
@@ -185,19 +218,28 @@ pub trait CallbackApiNoContext {
|
||||
{{/apiInfo}}
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait CallbackContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait CallbackContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: CallbackApi<C> + Sized, C> CallbackContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: CallbackApi<C> + Send + Sync, C: Clone + Send + Sync> CallbackContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: CallbackApi<C>, C> CallbackApiNoContext for ContextWrapper<'a, T, C> {
|
||||
#[async_trait]
|
||||
impl<T: CallbackApi<C> + Send + Sync, C: Clone + Send + Sync> CallbackApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
@@ -208,7 +250,7 @@ impl<'a, T: CallbackApi<C>, C> CallbackApiNoContext for ContextWrapper<'a, T, C>
|
||||
{{#summary}}
|
||||
/// {{{summary}}}
|
||||
{{/summary}}
|
||||
fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
async fn {{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
&self,
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
@@ -218,8 +260,9 @@ impl<'a, T: CallbackApi<C>, C> CallbackApiNoContext for ContextWrapper<'a, T, C>
|
||||
{{#allParams}}
|
||||
{{{paramName}}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}},
|
||||
{{/allParams}}
|
||||
) -> Box<dyn Future<Item={{{operationId}}}Response, Error=ApiError> + Send>
|
||||
) -> Result<{{{operationId}}}Response, ApiError>
|
||||
{
|
||||
let context = self.context().clone();
|
||||
self.api().{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
@@ -229,7 +272,7 @@ impl<'a, T: CallbackApi<C>, C> CallbackApiNoContext for ContextWrapper<'a, T, C>
|
||||
{{#allParams}}
|
||||
{{{paramName}}},
|
||||
{{/allParams}}
|
||||
&self.context())
|
||||
&context).await
|
||||
}
|
||||
|
||||
{{/requests}}
|
||||
|
||||
@@ -17,29 +17,45 @@ use crate::{{{operationId}}}Response;
|
||||
{{/apiInfo}}
|
||||
|
||||
/// A client that implements the API by making HTTP calls out to a server.
|
||||
pub struct Client<F>
|
||||
pub struct Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
/// Inner service
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for Client<F>
|
||||
impl<S> fmt::Debug for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Client")
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Clone for Client<F>
|
||||
impl<S> Clone for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Client {
|
||||
Self {
|
||||
client_service: self.client_service.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::ResponseFuture>
|
||||
impl<C> Client<hyper::client::Client<C, Body>> where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create a client with a custom implementation of hyper::client::Connect.
|
||||
///
|
||||
@@ -53,26 +69,33 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
|
||||
pub fn new_with_connector<C>(
|
||||
connector: C,
|
||||
) -> Self where
|
||||
C: hyper::client::connect::Connect + 'static,
|
||||
C::Transport: 'static,
|
||||
C::Future: 'static,
|
||||
pub fn new_with_connector(connector: C) -> Self
|
||||
{
|
||||
let client_service = Box::new(hyper::client::Client::builder().build(connector));
|
||||
let client_service = hyper::client::Client::builder().build(connector);
|
||||
|
||||
Client {
|
||||
client_service: Arc::new(client_service),
|
||||
Self {
|
||||
client_service,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::Client<hyper::client::HttpConnector, Body>>
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
pub fn new_http() -> Self {
|
||||
let http_connector = Connector::builder().build();
|
||||
Self::new_with_connector(http_connector)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
type HttpConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
impl Client<hyper::client::Client<HttpsConnector, Body>>
|
||||
{
|
||||
/// Create a client with a TLS connection to the server.
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
pub fn new_https() -> Result<Self, native_tls::Error>
|
||||
@@ -132,24 +155,43 @@ impl Client<hyper::client::ResponseFuture>
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Client<F>
|
||||
impl<S> Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `swagger::Service`
|
||||
///
|
||||
/// This allows adding custom wrappers around the underlying transport, for example for logging.
|
||||
pub fn new_with_client_service(
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
) -> Self {
|
||||
Client {
|
||||
client_service: client_service,
|
||||
client_service,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, F> CallbackApi<C> for Client<F> where
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}},
|
||||
F: Future<Item=Response<Body>, Error=hyper::Error> + Send + 'static
|
||||
#[async_trait]
|
||||
impl<C, S> CallbackApi<C> for Client<S> where
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}} + Send + Sync,
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
|
||||
match self.client_service.clone().poll_ready(cx) {
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(Box::new(e))),
|
||||
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
|
||||
@@ -1,38 +1,31 @@
|
||||
use std::marker::PhantomData;
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use hyper;
|
||||
use hyper::{Request, Response, Error, StatusCode, Body, HeaderMap};
|
||||
use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt};
|
||||
use hyper::{Request, Response, StatusCode, Body, HeaderMap};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use log::warn;
|
||||
use serde_json;
|
||||
#[allow(unused_imports)]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io;
|
||||
use url::form_urlencoded;
|
||||
#[allow(unused_imports)]
|
||||
use swagger;
|
||||
use swagger::{ApiError, XSpanIdString, Has, RequestParser};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString};
|
||||
pub use swagger::auth::Authorization;
|
||||
use swagger::auth::Scopes;
|
||||
use swagger::context::ContextualPayload;
|
||||
use url::form_urlencoded;
|
||||
{{#apiUsesMultipartRelated}}
|
||||
use hyper_0_10::header::{Headers, ContentType};
|
||||
use mime_0_2::{TopLevel, SubLevel, Mime as Mime2};
|
||||
use mime_multipart::{read_multipart_body, Node, Part};
|
||||
{{/apiUsesMultipartRelated}}
|
||||
{{#apiUsesUuid}}
|
||||
use uuid;
|
||||
{{/apiUsesUuid}}
|
||||
{{#apiUsesMultipartFormData}}
|
||||
use multipart::server::Multipart;
|
||||
use multipart::server::save::SaveResult;
|
||||
{{/apiUsesMultipartFormData}}
|
||||
{{#usesXml}}
|
||||
use serde_xml_rs;
|
||||
{{/usesXml}}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
||||
use crate::header;
|
||||
|
||||
pub use crate::context;
|
||||
|
||||
type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
pub struct MakeService<T, RC> {
|
||||
pub struct MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static
|
||||
impl<T, C> MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
MakeService {
|
||||
@@ -16,21 +18,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, SC, RC> hyper::service::MakeService<&'a SC> for MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static + Send
|
||||
impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, RC>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
type Service = Service<T, RC>;
|
||||
type Future = future::FutureResult<Self::Service, Self::MakeError>;
|
||||
type MakeError = Error;
|
||||
type Response = Service<T, C>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, _ctx: &'a SC) -> Self::Future {
|
||||
future::FutureResult::from(Ok(Service::new(
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
futures::future::ok(Service::new(
|
||||
self.api_impl.clone(),
|
||||
)))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
{
|
||||
let authorization = match (&context as &dyn Has<Option<Authorization>>).get() {
|
||||
&Some(ref authorization) => authorization,
|
||||
&None => return Box::new(future::ok(Response::builder()
|
||||
&None => return Ok(Response::builder()
|
||||
.status(StatusCode::FORBIDDEN)
|
||||
.body(Body::from("Unauthenticated"))
|
||||
.expect("Unable to create Authentication Forbidden response"))),
|
||||
.expect("Unable to create Authentication Forbidden response")),
|
||||
};
|
||||
{{#authMethods}}
|
||||
{{#isOAuth}}
|
||||
@@ -22,14 +22,14 @@
|
||||
|
||||
if !required_scopes.is_subset(scopes) {
|
||||
let missing_scopes = required_scopes.difference(scopes);
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::FORBIDDEN)
|
||||
.body(Body::from(missing_scopes.fold(
|
||||
"Insufficient authorization, missing scopes".to_string(),
|
||||
|s, scope| format!("{} {}", s, scope))
|
||||
))
|
||||
.expect("Unable to create Authentication Insufficient response")
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
{{/isOAuth}}
|
||||
@@ -41,10 +41,10 @@
|
||||
{{#consumesMultipart}}
|
||||
let boundary = match swagger::multipart::boundary(&headers) {
|
||||
Some(boundary) => boundary.to_string(),
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Couldn't find valid multipart body".to_string()))
|
||||
.expect("Unable to create Bad Request response for incorrect boundary"))),
|
||||
.expect("Unable to create Bad Request response for incorrect boundary")),
|
||||
};
|
||||
|
||||
{{/consumesMultipart}}
|
||||
@@ -64,15 +64,15 @@
|
||||
let param_{{{paramName}}} = match percent_encoding::percent_decode(path_params["{{{baseName}}}"].as_bytes()).decode_utf8() {
|
||||
Ok(param_{{{paramName}}}) => match param_{{{paramName}}}.parse::<{{{dataType}}}>() {
|
||||
Ok(param_{{{paramName}}}) => param_{{{paramName}}},
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse path parameter {{{baseName}}}: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid path parameter"))),
|
||||
.expect("Unable to create Bad Request response for invalid path parameter")),
|
||||
},
|
||||
Err(_) => return Box::new(future::ok(Response::builder()
|
||||
Err(_) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["{{{baseName}}}"])))
|
||||
.expect("Unable to create Bad Request response for invalid percent decode")))
|
||||
.expect("Unable to create Bad Request response for invalid percent decode"))
|
||||
};
|
||||
|
||||
{{/pathParams}}
|
||||
@@ -97,19 +97,19 @@
|
||||
Some(result.0),
|
||||
{{/required}}
|
||||
Err(err) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Invalid header {{{baseName}}} - {}", err)))
|
||||
.expect("Unable to create Bad Request response for invalid header {{{baseName}}}")));
|
||||
.expect("Unable to create Bad Request response for invalid header {{{baseName}}}"));
|
||||
|
||||
},
|
||||
},
|
||||
None => {
|
||||
{{#required}}
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required header {{{baseName}}}"))
|
||||
.expect("Unable to create Bad Request response for missing required header {{{baseName}}}")));
|
||||
.expect("Unable to create Bad Request response for missing required header {{{baseName}}}"));
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
None
|
||||
@@ -143,15 +143,15 @@
|
||||
let param_{{{paramName}}} = match param_{{{paramName}}} {
|
||||
Some(param_{{{paramName}}}) => match param_{{{paramName}}}.parse::<{{{dataType}}}>() {
|
||||
Ok(param_{{{paramName}}}) => param_{{{paramName}}},
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse query parameter {{{baseName}}} - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid query parameter {{{baseName}}}"))),
|
||||
.expect("Unable to create Bad Request response for invalid query parameter {{{baseName}}}")),
|
||||
},
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required query parameter {{{baseName}}}"))
|
||||
.expect("Unable to create Bad Request response for missing qeury parameter {{{baseName}}}"))),
|
||||
.expect("Unable to create Bad Request response for missing qeury parameter {{{baseName}}}")),
|
||||
};
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
@@ -169,9 +169,8 @@
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw().await;
|
||||
match result {
|
||||
Ok(body) => {
|
||||
{{#vendorExtensions}}
|
||||
{{^consumesPlainText}}
|
||||
@@ -191,10 +190,10 @@
|
||||
}) {
|
||||
Ok(param_{{{paramName}}}) => param_{{{paramName}}},
|
||||
{{#required}}
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter {{{baseName}}} - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to schema"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to schema")),
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
Err(_) => None,
|
||||
@@ -208,10 +207,10 @@
|
||||
{{#isString}}
|
||||
match String::from_utf8(body.to_vec()) {
|
||||
Ok(param_{{{paramName}}}) => Some(param_{{{paramName}}}),
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter {{{baseName}}} - not valid UTF-8: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to UTF-8"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to UTF-8")),
|
||||
}
|
||||
{{/isString}}
|
||||
{{/consumesPlainText}}
|
||||
@@ -222,10 +221,10 @@
|
||||
{{#required}}
|
||||
let param_{{{paramName}}} = match param_{{{paramName}}} {
|
||||
Some(param_{{{paramName}}}) => param_{{{paramName}}},
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required body parameter {{{baseName}}}"))
|
||||
.expect("Unable to create Bad Request response for missing body parameter {{{baseName}}}"))),
|
||||
.expect("Unable to create Bad Request response for missing body parameter {{{baseName}}}")),
|
||||
};
|
||||
{{/required}}
|
||||
{{/-first}}
|
||||
@@ -240,9 +239,8 @@
|
||||
// Form Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw();
|
||||
match result.await {
|
||||
Ok(body) => {
|
||||
use std::io::Read;
|
||||
|
||||
@@ -252,10 +250,10 @@
|
||||
entries
|
||||
},
|
||||
_ => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Unable to process all message parts")))
|
||||
.expect("Unable to create Bad Request response due to failure to process all message")))
|
||||
.expect("Unable to create Bad Request response due to failure to process all message"))
|
||||
},
|
||||
};
|
||||
{{#formParams}}
|
||||
@@ -278,11 +276,11 @@
|
||||
let {{{paramName}}}_model: {{{dataType}}} = match serde_json::from_str(&data) {
|
||||
Ok(model) => model,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("{{{paramName}}} data does not match API definition : {}", e)))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}"))
|
||||
}
|
||||
};
|
||||
{{{paramName}}}_model
|
||||
@@ -294,11 +292,11 @@
|
||||
},
|
||||
None => {
|
||||
{{#required}}
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Missing required form parameter {{{paramName}}}")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}"))
|
||||
{{/required}}
|
||||
{{^required}}
|
||||
None
|
||||
@@ -313,8 +311,6 @@
|
||||
{{^consumesMultipart}}
|
||||
{{^bodyParams}}
|
||||
{{#vendorExtensions}}
|
||||
Box::new({
|
||||
{{
|
||||
{{#formParams}}
|
||||
{{#-first}}
|
||||
// Form parameters
|
||||
@@ -332,9 +328,8 @@
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw();
|
||||
match result.await {
|
||||
Ok(body) => {
|
||||
let mut unused_elements: Vec<String> = vec![];
|
||||
|
||||
@@ -354,10 +349,10 @@
|
||||
multi_part_headers.set(ContentType(content_type_mime));
|
||||
},
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(e))
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for {{operationId}}")));
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for {{operationId}}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,10 +361,10 @@
|
||||
let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) {
|
||||
Ok(nodes) => nodes,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Could not read multipart body for {{operationId}}: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for {{operationId}}")));
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for {{operationId}}"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -391,10 +386,10 @@
|
||||
unused_elements.push(path.to_string());
|
||||
}) {
|
||||
Ok(json_data) => json_data,
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter {{dataType}} - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter {{dataType}} due to schema")))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter {{dataType}} due to schema"))
|
||||
};
|
||||
// Push JSON part to return object.
|
||||
param_{{{paramName}}}.get_or_insert(json_data);
|
||||
@@ -427,10 +422,10 @@
|
||||
{{#required}}
|
||||
let param_{{{paramName}}} = match param_required_binary_field {
|
||||
Some(x) => x,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Missing required multipart/related parameter {{{paramName}}}")))
|
||||
.expect("Unable to create Bad Request response for missing multipart/related parameter {{{paramName}}} due to schema")))
|
||||
.expect("Unable to create Bad Request response for missing multipart/related parameter {{{paramName}}} due to schema"))
|
||||
};
|
||||
{{/required}}
|
||||
{{#-last}}
|
||||
@@ -439,8 +434,7 @@
|
||||
{{/formParams}}
|
||||
{{/consumesMultipartRelated}}
|
||||
{{/vendorExtensions}}
|
||||
Box::new(
|
||||
api_impl.{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
let result = api_impl.{{#vendorExtensions}}{{{operation_id}}}{{/vendorExtensions}}(
|
||||
{{#vendorExtensions}}
|
||||
{{#callbackParams}}
|
||||
callback_{{.}},
|
||||
@@ -450,9 +444,9 @@
|
||||
param_{{{paramName}}}{{#isListContainer}}.as_ref(){{/isListContainer}},
|
||||
{{/allParams}}
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -505,7 +499,7 @@
|
||||
let {{{name}}} = match header::IntoHeaderValue({{{name}}}).try_into() {
|
||||
Ok(val) => val,
|
||||
Err(e) => {
|
||||
return future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(Body::from(format!("An internal server error occurred handling {{name}} header - {}", e)))
|
||||
.expect("Unable to create Internal Server Error for invalid response header"))
|
||||
@@ -569,26 +563,18 @@
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
{{#vendorExtensions}}
|
||||
{{^consumesMultipart}}
|
||||
{{^bodyParams}}
|
||||
{{#vendorExtensions}}
|
||||
{{#consumesMultipartRelated}}
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter {{{baseName}}}: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
{{/consumesMultipartRelated}}
|
||||
{{^consumesMultipartRelated}}
|
||||
}}
|
||||
}) as Self::Future
|
||||
{{/consumesMultipartRelated}}
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParams}}
|
||||
@@ -597,28 +583,23 @@
|
||||
{{#bodyParams}}
|
||||
{{#-first}}
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter {{{baseName}}}: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
{{/-first}}
|
||||
{{/bodyParams}}
|
||||
{{#vendorExtensions}}
|
||||
{{#consumesMultipart}}
|
||||
{{^bodyParams}}
|
||||
{{#vendorExtensions}}
|
||||
as Self::Future
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read multipart body")))
|
||||
.expect("Unable to create Bad Request response due to unable read multipart body"))),
|
||||
.expect("Unable to create Bad Request response due to unable read multipart body")),
|
||||
}
|
||||
})
|
||||
)
|
||||
{{/vendorExtensions}}
|
||||
{{/bodyParams}}
|
||||
{{/consumesMultipart}}
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
_ => Box::new(future::ok(
|
||||
Response::builder().status(StatusCode::NOT_FOUND)
|
||||
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Not Found response")
|
||||
)) as Self::Future
|
||||
.expect("Unable to create Not Found response"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> Clone for Service<T, C> where T: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
} Box::pin(run(self.api_impl.clone(), req)) }
|
||||
}
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
type ServiceFuture = Box<dyn Future<Item = Response<Body>, Error = Error> + Send>;
|
||||
|
||||
fn method_not_allowed() -> ServiceFuture {
|
||||
Box::new(future::ok(
|
||||
fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
|
||||
Ok(
|
||||
Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Method Not Allowed response")
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Service<T, RC> {
|
||||
pub struct Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> Service<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static {
|
||||
impl<T, C> Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
Service {
|
||||
api_impl: api_impl,
|
||||
@@ -25,23 +26,38 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service for Service<T, C>
|
||||
where
|
||||
impl<T, C> Clone for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + 'static + Send
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, C>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + Sync + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
type Response = Response<Body>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = ServiceFuture;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let api_impl = self.api_impl.clone();
|
||||
let (parts, body) = req.into_parts();
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.api_impl.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
|
||||
{
|
||||
let (request, context) = req;
|
||||
let (parts, body) = request.into_parts();
|
||||
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
|
||||
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
|
||||
let mut context = body.context;
|
||||
let body = body.inner;
|
||||
|
||||
{{!
|
||||
This match statement is duplicated below in `parse_operation_id()`.
|
||||
|
||||
@@ -12,7 +12,7 @@ client = [
|
||||
"mime_0_2",
|
||||
"multipart", "multipart/client", "swagger/multipart",
|
||||
"hyper_0_10", "mime_multipart",
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
"mime_0_2",
|
||||
@@ -24,20 +24,22 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
@@ -45,18 +47,18 @@ mime_0_2 = { package = "mime", version = "0.2.6", optional = true }
|
||||
multipart = { version = "0.16", default-features = false, optional = true }
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
mime_multipart = {version = "0.5", optional = true}
|
||||
hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -67,13 +69,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use multipart_v3::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse
|
||||
MultipleIdenticalMimeTypesPostResponse,
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -17,7 +16,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -55,21 +56,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:8080";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use multipart_v3::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
multipart_v3::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,48 +96,51 @@ impl<C> Server<C> {
|
||||
|
||||
use multipart_v3::{
|
||||
Api,
|
||||
ApiError,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse,
|
||||
};
|
||||
use multipart_v3::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
fn multipart_related_request_post(
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
async fn multipart_related_request_post(
|
||||
&self,
|
||||
required_binary_field: swagger::ByteArray,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
optional_binary_field: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRelatedRequestPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipartRelatedRequestPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("multipart_related_request_post({:?}, {:?}, {:?}) - X-Span-ID: {:?}", required_binary_field, object_field, optional_binary_field, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn multipart_request_post(
|
||||
async fn multipart_request_post(
|
||||
&self,
|
||||
string_field: String,
|
||||
binary_field: swagger::ByteArray,
|
||||
optional_string_field: Option<String>,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipartRequestPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("multipart_request_post(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", string_field, binary_field, optional_string_field, object_field, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
async fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipleIdenticalMimeTypesPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("multiple_identical_mime_types_post({:?}, {:?}) - X-Span-ID: {:?}", binary1, binary2, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
use futures;
|
||||
use futures::{Future, Stream, future, stream};
|
||||
use hyper;
|
||||
use hyper::client::HttpConnector;
|
||||
use async_trait::async_trait;
|
||||
use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use hyper::{Body, Uri, Response};
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use hyper_openssl::HttpsConnector;
|
||||
use serde_json;
|
||||
use hyper::{Body, Request, Response, service::Service, Uri};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Read, Error, ErrorKind};
|
||||
use std::error;
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use swagger;
|
||||
use swagger::{ApiError, Connector, client::Service, XSpanIdString, Has, AuthData};
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, AuthData, BodyExt, Connector, Has, XSpanIdString};
|
||||
use url::form_urlencoded;
|
||||
use url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET};
|
||||
|
||||
use mime::Mime;
|
||||
use std::io::Cursor;
|
||||
use multipart::client::lazy::Multipart;
|
||||
@@ -30,13 +27,17 @@ use mime_multipart::{Node, Part, generate_boundary, write_multipart};
|
||||
use crate::models;
|
||||
use crate::header;
|
||||
|
||||
url::define_encode_set! {
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
pub ID_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'|'}
|
||||
}
|
||||
/// https://url.spec.whatwg.org/#fragment-percent-encode-set
|
||||
#[allow(dead_code)]
|
||||
const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
|
||||
.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
|
||||
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
#[allow(dead_code)]
|
||||
const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');
|
||||
|
||||
use crate::{Api,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
@@ -45,11 +46,11 @@ use crate::{Api,
|
||||
};
|
||||
|
||||
/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.
|
||||
fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
fn into_base_path(input: impl TryInto<Uri, Error=hyper::http::uri::InvalidUri>, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
// First convert to Uri, since a base path is a subset of Uri.
|
||||
let uri = Uri::from_str(input)?;
|
||||
let uri = input.try_into()?;
|
||||
|
||||
let scheme = uri.scheme_part().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
|
||||
// Check the scheme if necessary
|
||||
if let Some(correct_scheme) = correct_scheme {
|
||||
@@ -59,38 +60,54 @@ fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<S
|
||||
}
|
||||
|
||||
let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?;
|
||||
let port = uri.port_part().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/')))
|
||||
}
|
||||
|
||||
/// A client that implements the API by making HTTP calls out to a server.
|
||||
pub struct Client<F>
|
||||
pub struct Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
/// Inner service
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
|
||||
/// Base path of the API
|
||||
base_path: String,
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for Client<F>
|
||||
impl<S> fmt::Debug for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Client {{ base_path: {} }}", self.base_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Clone for Client<F>
|
||||
impl<S> Clone for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Client {
|
||||
Self {
|
||||
client_service: self.client_service.clone(),
|
||||
base_path: self.base_path.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::ResponseFuture>
|
||||
impl<C> Client<hyper::client::Client<C, Body>> where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create a client with a custom implementation of hyper::client::Connect.
|
||||
///
|
||||
@@ -103,30 +120,93 @@ impl Client<hyper::client::ResponseFuture>
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
/// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")`
|
||||
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
|
||||
pub fn try_new_with_connector<C>(
|
||||
pub fn try_new_with_connector(
|
||||
base_path: &str,
|
||||
protocol: Option<&'static str>,
|
||||
connector: C,
|
||||
) -> Result<Self, ClientInitError> where
|
||||
C: hyper::client::connect::Connect + 'static,
|
||||
C::Transport: 'static,
|
||||
C::Future: 'static,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let client_service = Box::new(hyper::client::Client::builder().build(connector));
|
||||
let client_service = hyper::client::Client::builder().build(connector);
|
||||
|
||||
Ok(Client {
|
||||
client_service: Arc::new(client_service),
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, protocol)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HyperClient {
|
||||
Http(hyper::client::Client<hyper::client::HttpConnector, Body>),
|
||||
Https(hyper::client::Client<HttpsConnector, Body>),
|
||||
}
|
||||
|
||||
impl Service<Request<Body>> for HyperClient {
|
||||
type Response = Response<Body>;
|
||||
type Error = hyper::Error;
|
||||
type Future = hyper::client::ResponseFuture;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.poll_ready(cx),
|
||||
HyperClient::Https(client) => client.poll_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.call(req),
|
||||
HyperClient::Https(client) => client.call(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<HyperClient> {
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
let uri = Uri::from_str(base_path)?;
|
||||
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = scheme.to_ascii_lowercase();
|
||||
|
||||
let connector = Connector::builder();
|
||||
|
||||
let client_service = match scheme.as_str() {
|
||||
"http" => {
|
||||
HyperClient::Http(hyper::client::Client::builder().build(connector.build()))
|
||||
},
|
||||
"https" => {
|
||||
let connector = connector.https()
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
HyperClient::Https(hyper::client::Client::builder().build(connector))
|
||||
},
|
||||
_ => {
|
||||
return Err(ClientInitError::InvalidScheme);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::Client<hyper::client::HttpConnector, Body>>
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new_http(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
@@ -134,11 +214,20 @@ impl Client<hyper::client::ResponseFuture>
|
||||
|
||||
Self::try_new_with_connector(base_path, Some("http"), http_connector)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
impl Client<hyper::client::Client<HttpsConnector, Body>>
|
||||
{
|
||||
/// Create a client with a TLS connection to the server
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
pub fn try_new_https(base_path: &str) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let https_connector = Connector::builder()
|
||||
@@ -151,7 +240,7 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// Create a client with a TLS connection to the server using a pinned certificate
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
pub fn try_new_https_pinned<CA>(
|
||||
@@ -172,7 +261,7 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// Create a client with a mutually authenticated TLS connection to the server.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
/// * `client_key` - Path to the client private key
|
||||
/// * `client_certificate` - Path to the client's public certificate associated with the private key
|
||||
@@ -198,17 +287,24 @@ impl Client<hyper::client::ResponseFuture>
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Client<F>
|
||||
impl<S> Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `swagger::Service`
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `hyper::service::Service` /
|
||||
/// `tower::Service`
|
||||
///
|
||||
/// This allows adding custom wrappers around the underlying transport, for example for logging.
|
||||
pub fn try_new_with_client_service(
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
Ok(Client {
|
||||
client_service: client_service,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
})
|
||||
}
|
||||
@@ -248,47 +344,63 @@ impl fmt::Display for ClientInitError {
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ClientInitError {
|
||||
impl Error for ClientInitError {
|
||||
fn description(&self) -> &str {
|
||||
"Failed to produce a hyper client."
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, F> Api<C> for Client<F> where
|
||||
C: Has<XSpanIdString> ,
|
||||
F: Future<Item=Response<Body>, Error=hyper::Error> + Send + 'static
|
||||
#[async_trait]
|
||||
impl<C, S> Api<C> for Client<S> where
|
||||
C: Has<XSpanIdString> + Clone + Send + Sync + 'static,
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn multipart_related_request_post(
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
|
||||
match self.client_service.clone().poll_ready(cx) {
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
|
||||
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
async fn multipart_related_request_post(
|
||||
&self,
|
||||
param_required_binary_field: swagger::ByteArray,
|
||||
param_object_field: Option<models::MultipartRequestObjectField>,
|
||||
param_optional_binary_field: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRelatedRequestPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipartRelatedRequestPostResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{}/multipart_related_request",
|
||||
self.base_path
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
// Construct the Body for a multipart/related request. The mime 0.2.6 library
|
||||
@@ -359,229 +471,230 @@ impl<C, F> Api<C> for Client<F> where
|
||||
&[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat()
|
||||
) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
201 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
MultipartRelatedRequestPostResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
201 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
MultipartRelatedRequestPostResponse::OK
|
||||
)
|
||||
}
|
||||
}))
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn multipart_request_post(
|
||||
async fn multipart_request_post(
|
||||
&self,
|
||||
param_string_field: String,
|
||||
param_binary_field: swagger::ByteArray,
|
||||
param_optional_string_field: Option<String>,
|
||||
param_object_field: Option<models::MultipartRequestObjectField>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipartRequestPostResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{}/multipart_request",
|
||||
self.base_path
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
let mut multipart = Multipart::new();
|
||||
let (body_string, multipart_header) = {
|
||||
let mut multipart = Multipart::new();
|
||||
|
||||
// For each parameter, encode as appropriate and add to the multipart body as a stream.
|
||||
// For each parameter, encode as appropriate and add to the multipart body as a stream.
|
||||
|
||||
let string_field_str = match serde_json::to_string(¶m_string_field) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to parse string_field to string: {}", e)))),
|
||||
let string_field_str = match serde_json::to_string(¶m_string_field) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Err(ApiError(format!("Unable to parse string_field to string: {}", e))),
|
||||
};
|
||||
|
||||
let string_field_vec = string_field_str.as_bytes().to_vec();
|
||||
let string_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
let string_field_cursor = Cursor::new(string_field_vec);
|
||||
|
||||
multipart.add_stream("string_field", string_field_cursor, None as Option<&str>, Some(string_field_mime));
|
||||
|
||||
|
||||
let optional_string_field_str = match serde_json::to_string(¶m_optional_string_field) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Err(ApiError(format!("Unable to parse optional_string_field to string: {}", e))),
|
||||
};
|
||||
|
||||
let optional_string_field_vec = optional_string_field_str.as_bytes().to_vec();
|
||||
let optional_string_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
let optional_string_field_cursor = Cursor::new(optional_string_field_vec);
|
||||
|
||||
multipart.add_stream("optional_string_field", optional_string_field_cursor, None as Option<&str>, Some(optional_string_field_mime));
|
||||
|
||||
|
||||
let object_field_str = match serde_json::to_string(¶m_object_field) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Err(ApiError(format!("Unable to parse object_field to string: {}", e))),
|
||||
};
|
||||
|
||||
let object_field_vec = object_field_str.as_bytes().to_vec();
|
||||
let object_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
let object_field_cursor = Cursor::new(object_field_vec);
|
||||
|
||||
multipart.add_stream("object_field", object_field_cursor, None as Option<&str>, Some(object_field_mime));
|
||||
|
||||
|
||||
|
||||
let binary_field_vec = param_binary_field.to_vec();
|
||||
|
||||
let binary_field_mime = match mime_0_2::Mime::from_str("application/octet-stream") {
|
||||
Ok(mime) => mime,
|
||||
Err(err) => return Err(ApiError(format!("Unable to get mime type: {:?}", err))),
|
||||
};
|
||||
|
||||
let binary_field_cursor = Cursor::new(binary_field_vec);
|
||||
|
||||
let filename = None as Option<&str> ;
|
||||
multipart.add_stream("binary_field", binary_field_cursor, filename, Some(binary_field_mime));
|
||||
|
||||
let mut fields = match multipart.prepare() {
|
||||
Ok(fields) => fields,
|
||||
Err(err) => return Err(ApiError(format!("Unable to build request: {}", err))),
|
||||
};
|
||||
|
||||
let mut body_string = String::new();
|
||||
|
||||
match fields.read_to_string(&mut body_string) {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build body: {}", err))),
|
||||
}
|
||||
|
||||
let boundary = fields.boundary();
|
||||
|
||||
let multipart_header = format!("multipart/form-data;boundary={}", boundary);
|
||||
|
||||
(body_string, multipart_header)
|
||||
};
|
||||
|
||||
let string_field_vec = string_field_str.as_bytes().to_vec();
|
||||
|
||||
let string_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
|
||||
let string_field_cursor = Cursor::new(string_field_vec);
|
||||
|
||||
multipart.add_stream("string_field", string_field_cursor, None as Option<&str>, Some(string_field_mime));
|
||||
|
||||
let optional_string_field_str = match serde_json::to_string(¶m_optional_string_field) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to parse optional_string_field to string: {}", e)))),
|
||||
};
|
||||
|
||||
let optional_string_field_vec = optional_string_field_str.as_bytes().to_vec();
|
||||
|
||||
let optional_string_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
|
||||
let optional_string_field_cursor = Cursor::new(optional_string_field_vec);
|
||||
|
||||
multipart.add_stream("optional_string_field", optional_string_field_cursor, None as Option<&str>, Some(optional_string_field_mime));
|
||||
|
||||
let object_field_str = match serde_json::to_string(¶m_object_field) {
|
||||
Ok(str) => str,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to parse object_field to string: {}", e)))),
|
||||
};
|
||||
|
||||
let object_field_vec = object_field_str.as_bytes().to_vec();
|
||||
|
||||
let object_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse");
|
||||
|
||||
let object_field_cursor = Cursor::new(object_field_vec);
|
||||
|
||||
multipart.add_stream("object_field", object_field_cursor, None as Option<&str>, Some(object_field_mime));
|
||||
|
||||
let binary_field_vec = param_binary_field.to_vec();
|
||||
|
||||
let binary_field_mime = match mime_0_2::Mime::from_str("application/octet-stream") {
|
||||
Ok(mime) => mime,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to get mime type: {:?}", err)))),
|
||||
};
|
||||
|
||||
let binary_field_cursor = Cursor::new(binary_field_vec);
|
||||
|
||||
let filename = None as Option<&str> ;
|
||||
multipart.add_stream("binary_field", binary_field_cursor, filename, Some(binary_field_mime));
|
||||
let mut fields = match multipart.prepare() {
|
||||
Ok(fields) => fields,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build request: {}", err)))),
|
||||
};
|
||||
|
||||
let mut body_string = String::new();
|
||||
match fields.read_to_string(&mut body_string) {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build body: {}", err)))),
|
||||
}
|
||||
let boundary = fields.boundary();
|
||||
|
||||
let multipart_header = format!("multipart/form-data;boundary={}", boundary);
|
||||
|
||||
*request.body_mut() = Body::from(body_string);
|
||||
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e)))
|
||||
});
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
201 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
MultipartRequestPostResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
201 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
MultipartRequestPostResponse::OK
|
||||
)
|
||||
}
|
||||
}))
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
async fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
param_binary1: Option<swagger::ByteArray>,
|
||||
param_binary2: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipleIdenticalMimeTypesPostResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{}/multiple-identical-mime-types",
|
||||
self.base_path
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
// Construct the Body for a multipart/related request. The mime 0.2.6 library
|
||||
@@ -637,48 +750,43 @@ impl<C, F> Api<C> for Client<F> where
|
||||
&[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat()
|
||||
) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
200 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
MultipleIdenticalMimeTypesPostResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
200 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
MultipleIdenticalMimeTypesPostResponse::OK
|
||||
)
|
||||
}
|
||||
}))
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,33 +83,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use std::io::Error;
|
||||
use std::error::Error;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::{ApiError, ContextWrapper};
|
||||
|
||||
#[deprecated(note = "Import swagger-rs directly")]
|
||||
pub use swagger::{ApiError, ContextWrapper};
|
||||
#[deprecated(note = "Import futures directly")]
|
||||
pub use futures::Future;
|
||||
type ServiceError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub const BASE_PATH: &'static str = "";
|
||||
pub const API_VERSION: &'static str = "1.0.7";
|
||||
@@ -30,100 +30,125 @@ pub enum MultipleIdenticalMimeTypesPostResponse {
|
||||
}
|
||||
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
fn multipart_related_request_post(
|
||||
#[async_trait]
|
||||
pub trait Api<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
async fn multipart_related_request_post(
|
||||
&self,
|
||||
required_binary_field: swagger::ByteArray,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
optional_binary_field: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRelatedRequestPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MultipartRelatedRequestPostResponse, ApiError>;
|
||||
|
||||
fn multipart_request_post(
|
||||
async fn multipart_request_post(
|
||||
&self,
|
||||
string_field: String,
|
||||
binary_field: swagger::ByteArray,
|
||||
optional_string_field: Option<String>,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MultipartRequestPostResponse, ApiError>;
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
async fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MultipleIdenticalMimeTypesPostResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
pub trait ApiNoContext {
|
||||
fn multipart_related_request_post(
|
||||
/// API where `Context` isn't passed on every API call
|
||||
#[async_trait]
|
||||
pub trait ApiNoContext<C: Send + Sync> {
|
||||
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
async fn multipart_related_request_post(
|
||||
&self,
|
||||
required_binary_field: swagger::ByteArray,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
optional_binary_field: Option<swagger::ByteArray>,
|
||||
) -> Box<dyn Future<Item=MultipartRelatedRequestPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MultipartRelatedRequestPostResponse, ApiError>;
|
||||
|
||||
fn multipart_request_post(
|
||||
async fn multipart_request_post(
|
||||
&self,
|
||||
string_field: String,
|
||||
binary_field: swagger::ByteArray,
|
||||
optional_string_field: Option<String>,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MultipartRequestPostResponse, ApiError>;
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
async fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MultipleIdenticalMimeTypesPostResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait ContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
fn multipart_related_request_post(
|
||||
#[async_trait]
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
async fn multipart_related_request_post(
|
||||
&self,
|
||||
required_binary_field: swagger::ByteArray,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
optional_binary_field: Option<swagger::ByteArray>,
|
||||
) -> Box<dyn Future<Item=MultipartRelatedRequestPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<MultipartRelatedRequestPostResponse, ApiError>
|
||||
{
|
||||
self.api().multipart_related_request_post(required_binary_field, object_field, optional_binary_field, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().multipart_related_request_post(required_binary_field, object_field, optional_binary_field, &context).await
|
||||
}
|
||||
|
||||
fn multipart_request_post(
|
||||
async fn multipart_request_post(
|
||||
&self,
|
||||
string_field: String,
|
||||
binary_field: swagger::ByteArray,
|
||||
optional_string_field: Option<String>,
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<MultipartRequestPostResponse, ApiError>
|
||||
{
|
||||
self.api().multipart_request_post(string_field, binary_field, optional_string_field, object_field, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().multipart_request_post(string_field, binary_field, optional_string_field, object_field, &context).await
|
||||
}
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
async fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<MultipleIdenticalMimeTypesPostResponse, ApiError>
|
||||
{
|
||||
self.api().multiple_identical_mime_types_post(binary1, binary2, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().multiple_identical_mime_types_post(binary1, binary2, &context).await
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub mod client;
|
||||
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
use std::marker::PhantomData;
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use hyper;
|
||||
use hyper::{Request, Response, Error, StatusCode, Body, HeaderMap};
|
||||
use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt};
|
||||
use hyper::{Request, Response, StatusCode, Body, HeaderMap};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use log::warn;
|
||||
use serde_json;
|
||||
#[allow(unused_imports)]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io;
|
||||
use url::form_urlencoded;
|
||||
#[allow(unused_imports)]
|
||||
use swagger;
|
||||
use swagger::{ApiError, XSpanIdString, Has, RequestParser};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString};
|
||||
pub use swagger::auth::Authorization;
|
||||
use swagger::auth::Scopes;
|
||||
use swagger::context::ContextualPayload;
|
||||
use url::form_urlencoded;
|
||||
use hyper_0_10::header::{Headers, ContentType};
|
||||
use mime_0_2::{TopLevel, SubLevel, Mime as Mime2};
|
||||
use mime_multipart::{read_multipart_body, Node, Part};
|
||||
@@ -27,6 +24,8 @@ use crate::header;
|
||||
|
||||
pub use crate::context;
|
||||
|
||||
type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
|
||||
|
||||
use crate::{Api,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse,
|
||||
@@ -49,15 +48,17 @@ mod paths {
|
||||
pub(crate) static ID_MULTIPLE_IDENTICAL_MIME_TYPES: usize = 2;
|
||||
}
|
||||
|
||||
pub struct MakeService<T, RC> {
|
||||
pub struct MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static
|
||||
impl<T, C> MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
MakeService {
|
||||
@@ -67,44 +68,45 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, SC, RC> hyper::service::MakeService<&'a SC> for MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static + Send
|
||||
impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, RC>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
type Service = Service<T, RC>;
|
||||
type Future = future::FutureResult<Self::Service, Self::MakeError>;
|
||||
type MakeError = Error;
|
||||
type Response = Service<T, C>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, _ctx: &'a SC) -> Self::Future {
|
||||
future::FutureResult::from(Ok(Service::new(
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
futures::future::ok(Service::new(
|
||||
self.api_impl.clone(),
|
||||
)))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
type ServiceFuture = Box<dyn Future<Item = Response<Body>, Error = Error> + Send>;
|
||||
|
||||
fn method_not_allowed() -> ServiceFuture {
|
||||
Box::new(future::ok(
|
||||
fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
|
||||
Ok(
|
||||
Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Method Not Allowed response")
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Service<T, RC> {
|
||||
pub struct Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> Service<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static {
|
||||
impl<T, C> Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
Service {
|
||||
api_impl: api_impl,
|
||||
@@ -113,23 +115,38 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service for Service<T, C>
|
||||
where
|
||||
impl<T, C> Clone for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + 'static + Send
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, C>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + Sync + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type Response = Response<Body>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = ServiceFuture;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let api_impl = self.api_impl.clone();
|
||||
let (parts, body) = req.into_parts();
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.api_impl.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
let (request, context) = req;
|
||||
let (parts, body) = request.into_parts();
|
||||
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
|
||||
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
|
||||
let mut context = body.context;
|
||||
let body = body.inner;
|
||||
|
||||
match &method {
|
||||
|
||||
@@ -138,9 +155,8 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw();
|
||||
match result.await {
|
||||
Ok(body) => {
|
||||
let mut unused_elements: Vec<String> = vec![];
|
||||
|
||||
@@ -160,10 +176,10 @@ where
|
||||
multi_part_headers.set(ContentType(content_type_mime));
|
||||
},
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(e))
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for MultipartRelatedRequestPost")));
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for MultipartRelatedRequestPost"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,10 +188,10 @@ where
|
||||
let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) {
|
||||
Ok(nodes) => nodes,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Could not read multipart body for MultipartRelatedRequestPost: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for MultipartRelatedRequestPost")));
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for MultipartRelatedRequestPost"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -195,10 +211,10 @@ where
|
||||
unused_elements.push(path.to_string());
|
||||
}) {
|
||||
Ok(json_data) => json_data,
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter models::MultipartRequestObjectField - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter models::MultipartRequestObjectField due to schema")))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter models::MultipartRequestObjectField due to schema"))
|
||||
};
|
||||
// Push JSON part to return object.
|
||||
param_object_field.get_or_insert(json_data);
|
||||
@@ -226,21 +242,20 @@ where
|
||||
// Check that the required multipart chunks are present.
|
||||
let param_required_binary_field = match param_required_binary_field {
|
||||
Some(x) => x,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Missing required multipart/related parameter required_binary_field")))
|
||||
.expect("Unable to create Bad Request response for missing multipart/related parameter required_binary_field due to schema")))
|
||||
.expect("Unable to create Bad Request response for missing multipart/related parameter required_binary_field due to schema"))
|
||||
};
|
||||
|
||||
Box::new(
|
||||
api_impl.multipart_related_request_post(
|
||||
let result = api_impl.multipart_related_request_post(
|
||||
param_required_binary_field,
|
||||
param_object_field,
|
||||
param_optional_binary_field,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -260,35 +275,30 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter Default: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter Default"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter Default")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
// MultipartRequestPost - POST /multipart_request
|
||||
&hyper::Method::POST if path.matched(paths::ID_MULTIPART_REQUEST) => {
|
||||
let boundary = match swagger::multipart::boundary(&headers) {
|
||||
Some(boundary) => boundary.to_string(),
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Couldn't find valid multipart body".to_string()))
|
||||
.expect("Unable to create Bad Request response for incorrect boundary"))),
|
||||
.expect("Unable to create Bad Request response for incorrect boundary")),
|
||||
};
|
||||
|
||||
// Form Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw();
|
||||
match result.await {
|
||||
Ok(body) => {
|
||||
use std::io::Read;
|
||||
|
||||
@@ -298,10 +308,10 @@ where
|
||||
entries
|
||||
},
|
||||
_ => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Unable to process all message parts")))
|
||||
.expect("Unable to create Bad Request response due to failure to process all message")))
|
||||
.expect("Unable to create Bad Request response due to failure to process all message"))
|
||||
},
|
||||
};
|
||||
let field_string_field = entries.fields.remove("string_field");
|
||||
@@ -313,21 +323,21 @@ where
|
||||
let string_field_model: String = match serde_json::from_str(&data) {
|
||||
Ok(model) => model,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("string_field data does not match API definition : {}", e)))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter string_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter string_field"))
|
||||
}
|
||||
};
|
||||
string_field_model
|
||||
},
|
||||
None => {
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Missing required form parameter string_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter string_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter string_field"))
|
||||
}
|
||||
};
|
||||
let field_optional_string_field = entries.fields.remove("optional_string_field");
|
||||
@@ -340,11 +350,11 @@ where
|
||||
let optional_string_field_model: String = match serde_json::from_str(&data) {
|
||||
Ok(model) => model,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("optional_string_field data does not match API definition : {}", e)))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter optional_string_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter optional_string_field"))
|
||||
}
|
||||
};
|
||||
optional_string_field_model
|
||||
@@ -364,11 +374,11 @@ where
|
||||
let object_field_model: models::MultipartRequestObjectField = match serde_json::from_str(&data) {
|
||||
Ok(model) => model,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("object_field data does not match API definition : {}", e)))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter object_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter object_field"))
|
||||
}
|
||||
};
|
||||
object_field_model
|
||||
@@ -387,23 +397,22 @@ where
|
||||
swagger::ByteArray(data)
|
||||
},
|
||||
None => {
|
||||
return Box::new(future::ok(
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Missing required form parameter binary_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter binary_field")))
|
||||
.expect("Unable to create Bad Request due to missing required form parameter binary_field"))
|
||||
}
|
||||
};
|
||||
Box::new(
|
||||
api_impl.multipart_request_post(
|
||||
let result = api_impl.multipart_request_post(
|
||||
param_string_field,
|
||||
param_binary_field,
|
||||
param_optional_string_field,
|
||||
param_object_field,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -423,18 +432,13 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read multipart body")))
|
||||
.expect("Unable to create Bad Request response due to unable read multipart body"))),
|
||||
.expect("Unable to create Bad Request response due to unable read multipart body")),
|
||||
}
|
||||
})
|
||||
)
|
||||
},
|
||||
|
||||
// MultipleIdenticalMimeTypesPost - POST /multiple-identical-mime-types
|
||||
@@ -442,9 +446,8 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw();
|
||||
match result.await {
|
||||
Ok(body) => {
|
||||
let mut unused_elements: Vec<String> = vec![];
|
||||
|
||||
@@ -464,10 +467,10 @@ where
|
||||
multi_part_headers.set(ContentType(content_type_mime));
|
||||
},
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(e))
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for MultipleIdenticalMimeTypesPost")));
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for MultipleIdenticalMimeTypesPost"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,10 +479,10 @@ where
|
||||
let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) {
|
||||
Ok(nodes) => nodes,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Could not read multipart body for MultipleIdenticalMimeTypesPost: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for MultipleIdenticalMimeTypesPost")));
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for MultipleIdenticalMimeTypesPost"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -512,14 +515,13 @@ where
|
||||
|
||||
// Check that the required multipart chunks are present.
|
||||
|
||||
Box::new(
|
||||
api_impl.multiple_identical_mime_types_post(
|
||||
let result = api_impl.multiple_identical_mime_types_post(
|
||||
param_binary1,
|
||||
param_binary2,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -539,39 +541,23 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter Default: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter Default"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter Default")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
_ if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_MULTIPART_REQUEST) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_MULTIPLE_IDENTICAL_MIME_TYPES) => method_not_allowed(),
|
||||
_ => Box::new(future::ok(
|
||||
Response::builder().status(StatusCode::NOT_FOUND)
|
||||
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Not Found response")
|
||||
)) as Self::Future
|
||||
.expect("Unable to create Not Found response"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> Clone for Service<T, C> where T: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
} Box::pin(run(self.api_impl.clone(), req)) }
|
||||
}
|
||||
|
||||
/// Request parser for `Api`.
|
||||
|
||||
@@ -9,7 +9,7 @@ edition = "2018"
|
||||
[features]
|
||||
default = ["client", "server"]
|
||||
client = [
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
"serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static"
|
||||
@@ -18,35 +18,37 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -57,13 +59,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use no_example_v3::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError,
|
||||
OpGetResponse
|
||||
OpGetResponse,
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -15,7 +14,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -50,21 +51,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:8080";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use no_example_v3::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
no_example_v3::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,20 +96,23 @@ impl<C> Server<C> {
|
||||
|
||||
use no_example_v3::{
|
||||
Api,
|
||||
ApiError,
|
||||
OpGetResponse,
|
||||
};
|
||||
use no_example_v3::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
fn op_get(
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
async fn op_get(
|
||||
&self,
|
||||
inline_object: models::InlineObject,
|
||||
context: &C) -> Box<dyn Future<Item=OpGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<OpGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op_get({:?}) - X-Span-ID: {:?}", inline_object, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
use futures;
|
||||
use futures::{Future, Stream, future, stream};
|
||||
use hyper;
|
||||
use hyper::client::HttpConnector;
|
||||
use async_trait::async_trait;
|
||||
use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use hyper::{Body, Uri, Response};
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use hyper_openssl::HttpsConnector;
|
||||
use serde_json;
|
||||
use hyper::{Body, Request, Response, service::Service, Uri};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Read, Error, ErrorKind};
|
||||
use std::error;
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use swagger;
|
||||
use swagger::{ApiError, Connector, client::Service, XSpanIdString, Has, AuthData};
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, AuthData, BodyExt, Connector, Has, XSpanIdString};
|
||||
use url::form_urlencoded;
|
||||
use url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET};
|
||||
|
||||
|
||||
use crate::models;
|
||||
use crate::header;
|
||||
|
||||
url::define_encode_set! {
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
pub ID_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'|'}
|
||||
}
|
||||
/// https://url.spec.whatwg.org/#fragment-percent-encode-set
|
||||
#[allow(dead_code)]
|
||||
const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
|
||||
.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
|
||||
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
#[allow(dead_code)]
|
||||
const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');
|
||||
|
||||
use crate::{Api,
|
||||
OpGetResponse
|
||||
};
|
||||
|
||||
/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.
|
||||
fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
fn into_base_path(input: impl TryInto<Uri, Error=hyper::http::uri::InvalidUri>, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
|
||||
// First convert to Uri, since a base path is a subset of Uri.
|
||||
let uri = Uri::from_str(input)?;
|
||||
let uri = input.try_into()?;
|
||||
|
||||
let scheme = uri.scheme_part().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
|
||||
// Check the scheme if necessary
|
||||
if let Some(correct_scheme) = correct_scheme {
|
||||
@@ -52,38 +53,54 @@ fn into_base_path(input: &str, correct_scheme: Option<&'static str>) -> Result<S
|
||||
}
|
||||
|
||||
let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?;
|
||||
let port = uri.port_part().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default();
|
||||
Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/')))
|
||||
}
|
||||
|
||||
/// A client that implements the API by making HTTP calls out to a server.
|
||||
pub struct Client<F>
|
||||
pub struct Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
/// Inner service
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
|
||||
/// Base path of the API
|
||||
base_path: String,
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for Client<F>
|
||||
impl<S> fmt::Debug for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Client {{ base_path: {} }}", self.base_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Clone for Client<F>
|
||||
impl<S> Clone for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Client {
|
||||
Self {
|
||||
client_service: self.client_service.clone(),
|
||||
base_path: self.base_path.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::ResponseFuture>
|
||||
impl<C> Client<hyper::client::Client<C, Body>> where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create a client with a custom implementation of hyper::client::Connect.
|
||||
///
|
||||
@@ -96,30 +113,93 @@ impl Client<hyper::client::ResponseFuture>
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
/// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")`
|
||||
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
|
||||
pub fn try_new_with_connector<C>(
|
||||
pub fn try_new_with_connector(
|
||||
base_path: &str,
|
||||
protocol: Option<&'static str>,
|
||||
connector: C,
|
||||
) -> Result<Self, ClientInitError> where
|
||||
C: hyper::client::connect::Connect + 'static,
|
||||
C::Transport: 'static,
|
||||
C::Future: 'static,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let client_service = Box::new(hyper::client::Client::builder().build(connector));
|
||||
let client_service = hyper::client::Client::builder().build(connector);
|
||||
|
||||
Ok(Client {
|
||||
client_service: Arc::new(client_service),
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, protocol)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HyperClient {
|
||||
Http(hyper::client::Client<hyper::client::HttpConnector, Body>),
|
||||
Https(hyper::client::Client<HttpsConnector, Body>),
|
||||
}
|
||||
|
||||
impl Service<Request<Body>> for HyperClient {
|
||||
type Response = Response<Body>;
|
||||
type Error = hyper::Error;
|
||||
type Future = hyper::client::ResponseFuture;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.poll_ready(cx),
|
||||
HyperClient::Https(client) => client.poll_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
||||
match self {
|
||||
HyperClient::Http(client) => client.call(req),
|
||||
HyperClient::Https(client) => client.call(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<HyperClient> {
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
let uri = Uri::from_str(base_path)?;
|
||||
|
||||
let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
|
||||
let scheme = scheme.to_ascii_lowercase();
|
||||
|
||||
let connector = Connector::builder();
|
||||
|
||||
let client_service = match scheme.as_str() {
|
||||
"http" => {
|
||||
HyperClient::Http(hyper::client::Client::builder().build(connector.build()))
|
||||
},
|
||||
"https" => {
|
||||
let connector = connector.https()
|
||||
.build()
|
||||
.map_err(|e| ClientInitError::SslError(e))?;
|
||||
HyperClient::Https(hyper::client::Client::builder().build(connector))
|
||||
},
|
||||
_ => {
|
||||
return Err(ClientInitError::InvalidScheme);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::Client<hyper::client::HttpConnector, Body>>
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com"
|
||||
pub fn try_new_http(
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
@@ -127,11 +207,20 @@ impl Client<hyper::client::ResponseFuture>
|
||||
|
||||
Self::try_new_with_connector(base_path, Some("http"), http_connector)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
impl Client<hyper::client::Client<HttpsConnector, Body>>
|
||||
{
|
||||
/// Create a client with a TLS connection to the server
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
pub fn try_new_https(base_path: &str) -> Result<Self, ClientInitError>
|
||||
{
|
||||
let https_connector = Connector::builder()
|
||||
@@ -144,7 +233,7 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// Create a client with a TLS connection to the server using a pinned certificate
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
pub fn try_new_https_pinned<CA>(
|
||||
@@ -165,7 +254,7 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// Create a client with a mutually authenticated TLS connection to the server.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
|
||||
/// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com"
|
||||
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
|
||||
/// * `client_key` - Path to the client private key
|
||||
/// * `client_certificate` - Path to the client's public certificate associated with the private key
|
||||
@@ -191,17 +280,24 @@ impl Client<hyper::client::ResponseFuture>
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Client<F>
|
||||
impl<S> Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `swagger::Service`
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `hyper::service::Service` /
|
||||
/// `tower::Service`
|
||||
///
|
||||
/// This allows adding custom wrappers around the underlying transport, for example for logging.
|
||||
pub fn try_new_with_client_service(
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
base_path: &str,
|
||||
) -> Result<Self, ClientInitError> {
|
||||
Ok(Client {
|
||||
client_service: client_service,
|
||||
) -> Result<Self, ClientInitError>
|
||||
{
|
||||
Ok(Self {
|
||||
client_service,
|
||||
base_path: into_base_path(base_path, None)?,
|
||||
})
|
||||
}
|
||||
@@ -241,45 +337,61 @@ impl fmt::Display for ClientInitError {
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ClientInitError {
|
||||
impl Error for ClientInitError {
|
||||
fn description(&self) -> &str {
|
||||
"Failed to produce a hyper client."
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, F> Api<C> for Client<F> where
|
||||
C: Has<XSpanIdString> ,
|
||||
F: Future<Item=Response<Body>, Error=hyper::Error> + Send + 'static
|
||||
#[async_trait]
|
||||
impl<C, S> Api<C> for Client<S> where
|
||||
C: Has<XSpanIdString> + Clone + Send + Sync + 'static,
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>> + Clone + Sync + Send + 'static,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn op_get(
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
|
||||
match self.client_service.clone().poll_ready(cx) {
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
|
||||
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
async fn op_get(
|
||||
&self,
|
||||
param_inline_object: models::InlineObject,
|
||||
context: &C) -> Box<dyn Future<Item=OpGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<OpGetResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{}/op",
|
||||
self.base_path
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("GET")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
// Body parameter
|
||||
@@ -290,48 +402,43 @@ impl<C, F> Api<C> for Client<F> where
|
||||
let header = "application/json";
|
||||
request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
|
||||
});
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
200 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
OpGetResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
200 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
OpGetResponse::OK
|
||||
)
|
||||
}
|
||||
}))
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,33 +83,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use std::io::Error;
|
||||
use std::error::Error;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::{ApiError, ContextWrapper};
|
||||
|
||||
#[deprecated(note = "Import swagger-rs directly")]
|
||||
pub use swagger::{ApiError, ContextWrapper};
|
||||
#[deprecated(note = "Import futures directly")]
|
||||
pub use futures::Future;
|
||||
type ServiceError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub const BASE_PATH: &'static str = "";
|
||||
pub const API_VERSION: &'static str = "0.0.1";
|
||||
@@ -18,46 +18,69 @@ pub enum OpGetResponse {
|
||||
}
|
||||
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
fn op_get(
|
||||
#[async_trait]
|
||||
pub trait Api<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
async fn op_get(
|
||||
&self,
|
||||
inline_object: models::InlineObject,
|
||||
context: &C) -> Box<dyn Future<Item=OpGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<OpGetResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
pub trait ApiNoContext {
|
||||
fn op_get(
|
||||
/// API where `Context` isn't passed on every API call
|
||||
#[async_trait]
|
||||
pub trait ApiNoContext<C: Send + Sync> {
|
||||
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
async fn op_get(
|
||||
&self,
|
||||
inline_object: models::InlineObject,
|
||||
) -> Box<dyn Future<Item=OpGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<OpGetResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait ContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
fn op_get(
|
||||
#[async_trait]
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
async fn op_get(
|
||||
&self,
|
||||
inline_object: models::InlineObject,
|
||||
) -> Box<dyn Future<Item=OpGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<OpGetResponse, ApiError>
|
||||
{
|
||||
self.api().op_get(inline_object, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op_get(inline_object, &context).await
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub mod client;
|
||||
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
use std::marker::PhantomData;
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use hyper;
|
||||
use hyper::{Request, Response, Error, StatusCode, Body, HeaderMap};
|
||||
use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt};
|
||||
use hyper::{Request, Response, StatusCode, Body, HeaderMap};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use log::warn;
|
||||
use serde_json;
|
||||
#[allow(unused_imports)]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io;
|
||||
use url::form_urlencoded;
|
||||
#[allow(unused_imports)]
|
||||
use swagger;
|
||||
use swagger::{ApiError, XSpanIdString, Has, RequestParser};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString};
|
||||
pub use swagger::auth::Authorization;
|
||||
use swagger::auth::Scopes;
|
||||
use swagger::context::ContextualPayload;
|
||||
use url::form_urlencoded;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
||||
@@ -22,6 +19,8 @@ use crate::header;
|
||||
|
||||
pub use crate::context;
|
||||
|
||||
type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
|
||||
|
||||
use crate::{Api,
|
||||
OpGetResponse
|
||||
};
|
||||
@@ -38,15 +37,17 @@ mod paths {
|
||||
pub(crate) static ID_OP: usize = 0;
|
||||
}
|
||||
|
||||
pub struct MakeService<T, RC> {
|
||||
pub struct MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static
|
||||
impl<T, C> MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
MakeService {
|
||||
@@ -56,44 +57,45 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, SC, RC> hyper::service::MakeService<&'a SC> for MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static + Send
|
||||
impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, RC>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
type Service = Service<T, RC>;
|
||||
type Future = future::FutureResult<Self::Service, Self::MakeError>;
|
||||
type MakeError = Error;
|
||||
type Response = Service<T, C>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, _ctx: &'a SC) -> Self::Future {
|
||||
future::FutureResult::from(Ok(Service::new(
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
futures::future::ok(Service::new(
|
||||
self.api_impl.clone(),
|
||||
)))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
type ServiceFuture = Box<dyn Future<Item = Response<Body>, Error = Error> + Send>;
|
||||
|
||||
fn method_not_allowed() -> ServiceFuture {
|
||||
Box::new(future::ok(
|
||||
fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
|
||||
Ok(
|
||||
Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Method Not Allowed response")
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Service<T, RC> {
|
||||
pub struct Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> Service<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static {
|
||||
impl<T, C> Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
Service {
|
||||
api_impl: api_impl,
|
||||
@@ -102,23 +104,38 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service for Service<T, C>
|
||||
where
|
||||
impl<T, C> Clone for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + 'static + Send
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, C>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + Sync + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type Response = Response<Body>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = ServiceFuture;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let api_impl = self.api_impl.clone();
|
||||
let (parts, body) = req.into_parts();
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.api_impl.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
let (request, context) = req;
|
||||
let (parts, body) = request.into_parts();
|
||||
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
|
||||
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
|
||||
let mut context = body.context;
|
||||
let body = body.inner;
|
||||
|
||||
match &method {
|
||||
|
||||
@@ -127,9 +144,8 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw().await;
|
||||
match result {
|
||||
Ok(body) => {
|
||||
let mut unused_elements = Vec::new();
|
||||
let param_inline_object: Option<models::InlineObject> = if !body.is_empty() {
|
||||
@@ -139,29 +155,28 @@ where
|
||||
unused_elements.push(path.to_string());
|
||||
}) {
|
||||
Ok(param_inline_object) => param_inline_object,
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter InlineObject - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter InlineObject due to schema"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter InlineObject due to schema")),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let param_inline_object = match param_inline_object {
|
||||
Some(param_inline_object) => param_inline_object,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required body parameter InlineObject"))
|
||||
.expect("Unable to create Bad Request response for missing body parameter InlineObject"))),
|
||||
.expect("Unable to create Bad Request response for missing body parameter InlineObject")),
|
||||
};
|
||||
|
||||
Box::new(
|
||||
api_impl.op_get(
|
||||
let result = api_impl.op_get(
|
||||
param_inline_object,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -188,37 +203,21 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter InlineObject: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter InlineObject"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter InlineObject")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
_ if path.matched(paths::ID_OP) => method_not_allowed(),
|
||||
_ => Box::new(future::ok(
|
||||
Response::builder().status(StatusCode::NOT_FOUND)
|
||||
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Not Found response")
|
||||
)) as Self::Future
|
||||
.expect("Unable to create Not Found response"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> Clone for Service<T, C> where T: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
} Box::pin(run(self.api_impl.clone(), req)) }
|
||||
}
|
||||
|
||||
/// Request parser for `Api`.
|
||||
|
||||
@@ -10,49 +10,51 @@ edition = "2018"
|
||||
default = ["client", "server"]
|
||||
client = [
|
||||
"serde_ignored", "regex", "percent-encoding", "lazy_static",
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
"native-tls", "hyper-openssl", "openssl",
|
||||
"native-tls", "hyper-openssl", "hyper-tls", "openssl",
|
||||
"serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static"
|
||||
]
|
||||
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
# TODO: this should be updated to point at the official crate once
|
||||
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
|
||||
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"}
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
uuid = {version = "0.8", features = ["serde", "v4"]}
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -63,12 +65,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
mod server;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use openapi_v3::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError,
|
||||
CallbackWithHeaderPostResponse,
|
||||
ComplexQueryParamGetResponse,
|
||||
EnumInPathPathParamGetResponse,
|
||||
@@ -29,7 +28,7 @@ use openapi_v3::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
XmlPostResponse,
|
||||
XmlPutResponse,
|
||||
CreateRepoResponse,
|
||||
GetRepoInfoResponse
|
||||
GetRepoInfoResponse,
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -38,7 +37,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -95,21 +96,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
use uuid;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use openapi_v3::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
openapi_v3::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,31 +93,35 @@ impl<C> Server<C> {
|
||||
}
|
||||
}
|
||||
|
||||
use openapi_v3::{CallbackApi, ApiError};
|
||||
use openapi_v3::CallbackApi;
|
||||
use openapi_v3::CallbackCallbackWithHeaderPostResponse;
|
||||
use openapi_v3::CallbackCallbackPostResponse;
|
||||
use openapi_v3::client::callbacks::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> CallbackApi<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
fn callback_callback_with_header_post(
|
||||
#[async_trait]
|
||||
impl<C> CallbackApi<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
async fn callback_callback_with_header_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
information: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackCallbackWithHeaderPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CallbackCallbackWithHeaderPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("callback_callback_with_header_post({:?}) - X-Span-ID: {:?}", information, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn callback_callback_post(
|
||||
async fn callback_callback_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackCallbackPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CallbackCallbackPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("callback_callback_post() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:8080";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
use uuid;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use openapi_v3::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
openapi_v3::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +96,6 @@ impl<C> Server<C> {
|
||||
|
||||
use openapi_v3::{
|
||||
Api,
|
||||
ApiError,
|
||||
CallbackWithHeaderPostResponse,
|
||||
ComplexQueryParamGetResponse,
|
||||
EnumInPathPathParamGetResponse,
|
||||
@@ -131,233 +121,237 @@ use openapi_v3::{
|
||||
GetRepoInfoResponse,
|
||||
};
|
||||
use openapi_v3::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
fn callback_with_header_post(
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
async fn callback_with_header_post(
|
||||
&self,
|
||||
url: String,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackWithHeaderPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CallbackWithHeaderPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("callback_with_header_post(\"{}\") - X-Span-ID: {:?}", url, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn complex_query_param_get(
|
||||
async fn complex_query_param_get(
|
||||
&self,
|
||||
list_of_strings: Option<&Vec<models::StringObject>>,
|
||||
context: &C) -> Box<dyn Future<Item=ComplexQueryParamGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<ComplexQueryParamGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("complex_query_param_get({:?}) - X-Span-ID: {:?}", list_of_strings, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn enum_in_path_path_param_get(
|
||||
async fn enum_in_path_path_param_get(
|
||||
&self,
|
||||
path_param: models::StringEnum,
|
||||
context: &C) -> Box<dyn Future<Item=EnumInPathPathParamGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<EnumInPathPathParamGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("enum_in_path_path_param_get({:?}) - X-Span-ID: {:?}", path_param, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn mandatory_request_header_get(
|
||||
async fn mandatory_request_header_get(
|
||||
&self,
|
||||
x_header: String,
|
||||
context: &C) -> Box<dyn Future<Item=MandatoryRequestHeaderGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MandatoryRequestHeaderGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("mandatory_request_header_get(\"{}\") - X-Span-ID: {:?}", x_header, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn merge_patch_json_get(
|
||||
async fn merge_patch_json_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=MergePatchJsonGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MergePatchJsonGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("merge_patch_json_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Get some stuff.
|
||||
fn multiget_get(
|
||||
async fn multiget_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=MultigetGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultigetGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("multiget_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn multiple_auth_scheme_get(
|
||||
async fn multiple_auth_scheme_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleAuthSchemeGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<MultipleAuthSchemeGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("multiple_auth_scheme_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn override_server_get(
|
||||
async fn override_server_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=OverrideServerGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<OverrideServerGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("override_server_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Get some stuff with parameters.
|
||||
fn paramget_get(
|
||||
async fn paramget_get(
|
||||
&self,
|
||||
uuid: Option<uuid::Uuid>,
|
||||
some_object: Option<models::ObjectParam>,
|
||||
some_list: Option<models::MyIdList>,
|
||||
context: &C) -> Box<dyn Future<Item=ParamgetGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<ParamgetGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("paramget_get({:?}, {:?}, {:?}) - X-Span-ID: {:?}", uuid, some_object, some_list, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn readonly_auth_scheme_get(
|
||||
async fn readonly_auth_scheme_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=ReadonlyAuthSchemeGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<ReadonlyAuthSchemeGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("readonly_auth_scheme_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn register_callback_post(
|
||||
async fn register_callback_post(
|
||||
&self,
|
||||
url: String,
|
||||
context: &C) -> Box<dyn Future<Item=RegisterCallbackPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<RegisterCallbackPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("register_callback_post(\"{}\") - X-Span-ID: {:?}", url, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn required_octet_stream_put(
|
||||
async fn required_octet_stream_put(
|
||||
&self,
|
||||
body: swagger::ByteArray,
|
||||
context: &C) -> Box<dyn Future<Item=RequiredOctetStreamPutResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<RequiredOctetStreamPutResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("required_octet_stream_put({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn responses_with_headers_get(
|
||||
async fn responses_with_headers_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=ResponsesWithHeadersGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<ResponsesWithHeadersGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("responses_with_headers_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn rfc7807_get(
|
||||
async fn rfc7807_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Rfc7807GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Rfc7807GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("rfc7807_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn untyped_property_get(
|
||||
async fn untyped_property_get(
|
||||
&self,
|
||||
object_untyped_props: Option<models::ObjectUntypedProps>,
|
||||
context: &C) -> Box<dyn Future<Item=UntypedPropertyGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<UntypedPropertyGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("untyped_property_get({:?}) - X-Span-ID: {:?}", object_untyped_props, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn uuid_get(
|
||||
async fn uuid_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=UuidGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<UuidGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("uuid_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn xml_extra_post(
|
||||
async fn xml_extra_post(
|
||||
&self,
|
||||
duplicate_xml_object: Option<models::DuplicateXmlObject>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlExtraPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<XmlExtraPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("xml_extra_post({:?}) - X-Span-ID: {:?}", duplicate_xml_object, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn xml_other_post(
|
||||
async fn xml_other_post(
|
||||
&self,
|
||||
another_xml_object: Option<models::AnotherXmlObject>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlOtherPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<XmlOtherPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("xml_other_post({:?}) - X-Span-ID: {:?}", another_xml_object, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn xml_other_put(
|
||||
async fn xml_other_put(
|
||||
&self,
|
||||
another_xml_array: Option<models::AnotherXmlArray>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlOtherPutResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<XmlOtherPutResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("xml_other_put({:?}) - X-Span-ID: {:?}", another_xml_array, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Post an array
|
||||
fn xml_post(
|
||||
async fn xml_post(
|
||||
&self,
|
||||
xml_array: Option<models::XmlArray>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<XmlPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("xml_post({:?}) - X-Span-ID: {:?}", xml_array, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn xml_put(
|
||||
async fn xml_put(
|
||||
&self,
|
||||
xml_object: Option<models::XmlObject>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlPutResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<XmlPutResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("xml_put({:?}) - X-Span-ID: {:?}", xml_object, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn create_repo(
|
||||
async fn create_repo(
|
||||
&self,
|
||||
object_param: models::ObjectParam,
|
||||
context: &C) -> Box<dyn Future<Item=CreateRepoResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CreateRepoResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("create_repo({:?}) - X-Span-ID: {:?}", object_param, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn get_repo_info(
|
||||
async fn get_repo_info(
|
||||
&self,
|
||||
repo_id: String,
|
||||
context: &C) -> Box<dyn Future<Item=GetRepoInfoResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<GetRepoInfoResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("get_repo_info(\"{}\") - X-Span-ID: {:?}", repo_id, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
use std::marker::PhantomData;
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use hyper;
|
||||
use hyper::{Request, Response, Error, StatusCode, Body, HeaderMap};
|
||||
use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt};
|
||||
use hyper::{Request, Response, StatusCode, Body, HeaderMap};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use log::warn;
|
||||
use serde_json;
|
||||
#[allow(unused_imports)]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io;
|
||||
use url::form_urlencoded;
|
||||
#[allow(unused_imports)]
|
||||
use swagger;
|
||||
use swagger::{ApiError, XSpanIdString, Has, RequestParser};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString};
|
||||
pub use swagger::auth::Authorization;
|
||||
use swagger::auth::Scopes;
|
||||
use swagger::context::ContextualPayload;
|
||||
use uuid;
|
||||
use serde_xml_rs;
|
||||
use url::form_urlencoded;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
||||
@@ -24,6 +19,8 @@ use crate::header;
|
||||
|
||||
pub use crate::context;
|
||||
|
||||
type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
|
||||
|
||||
use crate::CallbackApi as Api;
|
||||
use crate::CallbackCallbackWithHeaderPostResponse;
|
||||
use crate::CallbackCallbackPostResponse;
|
||||
@@ -53,15 +50,17 @@ mod paths {
|
||||
}
|
||||
|
||||
|
||||
pub struct MakeService<T, RC> {
|
||||
pub struct MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + Has<Option<Authorization>> + 'static
|
||||
impl<T, C> MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
MakeService {
|
||||
@@ -71,45 +70,46 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, SC, RC> hyper::service::MakeService<&'a SC> for MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + Has<Option<Authorization>> + 'static + Send
|
||||
impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, RC>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
type Service = Service<T, RC>;
|
||||
type Future = future::FutureResult<Self::Service, Self::MakeError>;
|
||||
type MakeError = Error;
|
||||
type Response = Service<T, C>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, _ctx: &'a SC) -> Self::Future {
|
||||
future::FutureResult::from(Ok(Service::new(
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
futures::future::ok(Service::new(
|
||||
self.api_impl.clone(),
|
||||
)))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type ServiceFuture = Box<dyn Future<Item = Response<Body>, Error = Error> + Send>;
|
||||
|
||||
fn method_not_allowed() -> ServiceFuture {
|
||||
Box::new(future::ok(
|
||||
fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
|
||||
Ok(
|
||||
Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Method Not Allowed response")
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Service<T, RC> {
|
||||
pub struct Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> Service<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + Has<Option<Authorization>> + 'static {
|
||||
impl<T, C> Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
Service {
|
||||
api_impl: api_impl,
|
||||
@@ -118,23 +118,38 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service for Service<T, C>
|
||||
where
|
||||
impl<T, C> Clone for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + 'static + Send
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, C>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + Sync + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
type Response = Response<Body>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = ServiceFuture;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let api_impl = self.api_impl.clone();
|
||||
let (parts, body) = req.into_parts();
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.api_impl.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Has<Option<Authorization>> + Send + Sync + 'static
|
||||
{
|
||||
let (request, context) = req;
|
||||
let (parts, body) = request.into_parts();
|
||||
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
|
||||
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
|
||||
let mut context = body.context;
|
||||
let body = body.inner;
|
||||
|
||||
match &method {
|
||||
|
||||
@@ -158,10 +173,10 @@ where
|
||||
Ok(result) =>
|
||||
Some(result.0),
|
||||
Err(err) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Invalid header Information - {}", err)))
|
||||
.expect("Unable to create Bad Request response for invalid header Information")));
|
||||
.expect("Unable to create Bad Request response for invalid header Information"));
|
||||
|
||||
},
|
||||
},
|
||||
@@ -170,16 +185,13 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.callback_callback_with_header_post(
|
||||
let result = api_impl.callback_callback_with_header_post(
|
||||
callback_request_query_url,
|
||||
param_information,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -199,11 +211,7 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
// CallbackCallbackPost - POST /{$request.query.url}/callback
|
||||
@@ -218,15 +226,12 @@ where
|
||||
);
|
||||
|
||||
let callback_request_query_url = path_params["request_query_url"].to_string();
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.callback_callback_post(
|
||||
let result = api_impl.callback_callback_post(
|
||||
callback_request_query_url,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -246,32 +251,16 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
_ if path.matched(paths::ID_REQUEST_QUERY_URL_CALLBACK) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_REQUEST_QUERY_URL_CALLBACK_WITH_HEADER) => method_not_allowed(),
|
||||
_ => Box::new(future::ok(
|
||||
Response::builder().status(StatusCode::NOT_FOUND)
|
||||
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Not Found response")
|
||||
)) as Self::Future
|
||||
.expect("Unable to create Not Found response"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> Clone for Service<T, C> where T: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
} Box::pin(run(self.api_impl.clone(), req)) }
|
||||
}
|
||||
|
||||
/// Request parser for `Api`.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,24 +83,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
{
|
||||
use swagger::auth::Bearer;
|
||||
@@ -117,22 +112,13 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use std::io::Error;
|
||||
use std::error::Error;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::{ApiError, ContextWrapper};
|
||||
|
||||
#[deprecated(note = "Import swagger-rs directly")]
|
||||
pub use swagger::{ApiError, ContextWrapper};
|
||||
#[deprecated(note = "Import futures directly")]
|
||||
pub use futures::Future;
|
||||
type ServiceError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub const BASE_PATH: &'static str = "";
|
||||
pub const API_VERSION: &'static str = "1.0.7";
|
||||
@@ -225,433 +225,478 @@ pub enum GetRepoInfoResponse {
|
||||
}
|
||||
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
fn callback_with_header_post(
|
||||
#[async_trait]
|
||||
pub trait Api<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
async fn callback_with_header_post(
|
||||
&self,
|
||||
url: String,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackWithHeaderPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<CallbackWithHeaderPostResponse, ApiError>;
|
||||
|
||||
fn complex_query_param_get(
|
||||
async fn complex_query_param_get(
|
||||
&self,
|
||||
list_of_strings: Option<&Vec<models::StringObject>>,
|
||||
context: &C) -> Box<dyn Future<Item=ComplexQueryParamGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<ComplexQueryParamGetResponse, ApiError>;
|
||||
|
||||
fn enum_in_path_path_param_get(
|
||||
async fn enum_in_path_path_param_get(
|
||||
&self,
|
||||
path_param: models::StringEnum,
|
||||
context: &C) -> Box<dyn Future<Item=EnumInPathPathParamGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<EnumInPathPathParamGetResponse, ApiError>;
|
||||
|
||||
fn mandatory_request_header_get(
|
||||
async fn mandatory_request_header_get(
|
||||
&self,
|
||||
x_header: String,
|
||||
context: &C) -> Box<dyn Future<Item=MandatoryRequestHeaderGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MandatoryRequestHeaderGetResponse, ApiError>;
|
||||
|
||||
fn merge_patch_json_get(
|
||||
async fn merge_patch_json_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=MergePatchJsonGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MergePatchJsonGetResponse, ApiError>;
|
||||
|
||||
/// Get some stuff.
|
||||
fn multiget_get(
|
||||
async fn multiget_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=MultigetGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MultigetGetResponse, ApiError>;
|
||||
|
||||
fn multiple_auth_scheme_get(
|
||||
async fn multiple_auth_scheme_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleAuthSchemeGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<MultipleAuthSchemeGetResponse, ApiError>;
|
||||
|
||||
fn override_server_get(
|
||||
async fn override_server_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=OverrideServerGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<OverrideServerGetResponse, ApiError>;
|
||||
|
||||
/// Get some stuff with parameters.
|
||||
fn paramget_get(
|
||||
async fn paramget_get(
|
||||
&self,
|
||||
uuid: Option<uuid::Uuid>,
|
||||
some_object: Option<models::ObjectParam>,
|
||||
some_list: Option<models::MyIdList>,
|
||||
context: &C) -> Box<dyn Future<Item=ParamgetGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<ParamgetGetResponse, ApiError>;
|
||||
|
||||
fn readonly_auth_scheme_get(
|
||||
async fn readonly_auth_scheme_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=ReadonlyAuthSchemeGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<ReadonlyAuthSchemeGetResponse, ApiError>;
|
||||
|
||||
fn register_callback_post(
|
||||
async fn register_callback_post(
|
||||
&self,
|
||||
url: String,
|
||||
context: &C) -> Box<dyn Future<Item=RegisterCallbackPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<RegisterCallbackPostResponse, ApiError>;
|
||||
|
||||
fn required_octet_stream_put(
|
||||
async fn required_octet_stream_put(
|
||||
&self,
|
||||
body: swagger::ByteArray,
|
||||
context: &C) -> Box<dyn Future<Item=RequiredOctetStreamPutResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<RequiredOctetStreamPutResponse, ApiError>;
|
||||
|
||||
fn responses_with_headers_get(
|
||||
async fn responses_with_headers_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=ResponsesWithHeadersGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<ResponsesWithHeadersGetResponse, ApiError>;
|
||||
|
||||
fn rfc7807_get(
|
||||
async fn rfc7807_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Rfc7807GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Rfc7807GetResponse, ApiError>;
|
||||
|
||||
fn untyped_property_get(
|
||||
async fn untyped_property_get(
|
||||
&self,
|
||||
object_untyped_props: Option<models::ObjectUntypedProps>,
|
||||
context: &C) -> Box<dyn Future<Item=UntypedPropertyGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<UntypedPropertyGetResponse, ApiError>;
|
||||
|
||||
fn uuid_get(
|
||||
async fn uuid_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=UuidGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<UuidGetResponse, ApiError>;
|
||||
|
||||
fn xml_extra_post(
|
||||
async fn xml_extra_post(
|
||||
&self,
|
||||
duplicate_xml_object: Option<models::DuplicateXmlObject>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlExtraPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<XmlExtraPostResponse, ApiError>;
|
||||
|
||||
fn xml_other_post(
|
||||
async fn xml_other_post(
|
||||
&self,
|
||||
another_xml_object: Option<models::AnotherXmlObject>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlOtherPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<XmlOtherPostResponse, ApiError>;
|
||||
|
||||
fn xml_other_put(
|
||||
async fn xml_other_put(
|
||||
&self,
|
||||
another_xml_array: Option<models::AnotherXmlArray>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlOtherPutResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<XmlOtherPutResponse, ApiError>;
|
||||
|
||||
/// Post an array
|
||||
fn xml_post(
|
||||
async fn xml_post(
|
||||
&self,
|
||||
xml_array: Option<models::XmlArray>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<XmlPostResponse, ApiError>;
|
||||
|
||||
fn xml_put(
|
||||
async fn xml_put(
|
||||
&self,
|
||||
xml_object: Option<models::XmlObject>,
|
||||
context: &C) -> Box<dyn Future<Item=XmlPutResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<XmlPutResponse, ApiError>;
|
||||
|
||||
fn create_repo(
|
||||
async fn create_repo(
|
||||
&self,
|
||||
object_param: models::ObjectParam,
|
||||
context: &C) -> Box<dyn Future<Item=CreateRepoResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<CreateRepoResponse, ApiError>;
|
||||
|
||||
fn get_repo_info(
|
||||
async fn get_repo_info(
|
||||
&self,
|
||||
repo_id: String,
|
||||
context: &C) -> Box<dyn Future<Item=GetRepoInfoResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<GetRepoInfoResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
pub trait ApiNoContext {
|
||||
fn callback_with_header_post(
|
||||
/// API where `Context` isn't passed on every API call
|
||||
#[async_trait]
|
||||
pub trait ApiNoContext<C: Send + Sync> {
|
||||
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
async fn callback_with_header_post(
|
||||
&self,
|
||||
url: String,
|
||||
) -> Box<dyn Future<Item=CallbackWithHeaderPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<CallbackWithHeaderPostResponse, ApiError>;
|
||||
|
||||
fn complex_query_param_get(
|
||||
async fn complex_query_param_get(
|
||||
&self,
|
||||
list_of_strings: Option<&Vec<models::StringObject>>,
|
||||
) -> Box<dyn Future<Item=ComplexQueryParamGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<ComplexQueryParamGetResponse, ApiError>;
|
||||
|
||||
fn enum_in_path_path_param_get(
|
||||
async fn enum_in_path_path_param_get(
|
||||
&self,
|
||||
path_param: models::StringEnum,
|
||||
) -> Box<dyn Future<Item=EnumInPathPathParamGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<EnumInPathPathParamGetResponse, ApiError>;
|
||||
|
||||
fn mandatory_request_header_get(
|
||||
async fn mandatory_request_header_get(
|
||||
&self,
|
||||
x_header: String,
|
||||
) -> Box<dyn Future<Item=MandatoryRequestHeaderGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MandatoryRequestHeaderGetResponse, ApiError>;
|
||||
|
||||
fn merge_patch_json_get(
|
||||
async fn merge_patch_json_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=MergePatchJsonGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MergePatchJsonGetResponse, ApiError>;
|
||||
|
||||
/// Get some stuff.
|
||||
fn multiget_get(
|
||||
async fn multiget_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=MultigetGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MultigetGetResponse, ApiError>;
|
||||
|
||||
fn multiple_auth_scheme_get(
|
||||
async fn multiple_auth_scheme_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=MultipleAuthSchemeGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<MultipleAuthSchemeGetResponse, ApiError>;
|
||||
|
||||
fn override_server_get(
|
||||
async fn override_server_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=OverrideServerGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<OverrideServerGetResponse, ApiError>;
|
||||
|
||||
/// Get some stuff with parameters.
|
||||
fn paramget_get(
|
||||
async fn paramget_get(
|
||||
&self,
|
||||
uuid: Option<uuid::Uuid>,
|
||||
some_object: Option<models::ObjectParam>,
|
||||
some_list: Option<models::MyIdList>,
|
||||
) -> Box<dyn Future<Item=ParamgetGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<ParamgetGetResponse, ApiError>;
|
||||
|
||||
fn readonly_auth_scheme_get(
|
||||
async fn readonly_auth_scheme_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=ReadonlyAuthSchemeGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<ReadonlyAuthSchemeGetResponse, ApiError>;
|
||||
|
||||
fn register_callback_post(
|
||||
async fn register_callback_post(
|
||||
&self,
|
||||
url: String,
|
||||
) -> Box<dyn Future<Item=RegisterCallbackPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<RegisterCallbackPostResponse, ApiError>;
|
||||
|
||||
fn required_octet_stream_put(
|
||||
async fn required_octet_stream_put(
|
||||
&self,
|
||||
body: swagger::ByteArray,
|
||||
) -> Box<dyn Future<Item=RequiredOctetStreamPutResponse, Error=ApiError> + Send>;
|
||||
) -> Result<RequiredOctetStreamPutResponse, ApiError>;
|
||||
|
||||
fn responses_with_headers_get(
|
||||
async fn responses_with_headers_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=ResponsesWithHeadersGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<ResponsesWithHeadersGetResponse, ApiError>;
|
||||
|
||||
fn rfc7807_get(
|
||||
async fn rfc7807_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Rfc7807GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Rfc7807GetResponse, ApiError>;
|
||||
|
||||
fn untyped_property_get(
|
||||
async fn untyped_property_get(
|
||||
&self,
|
||||
object_untyped_props: Option<models::ObjectUntypedProps>,
|
||||
) -> Box<dyn Future<Item=UntypedPropertyGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<UntypedPropertyGetResponse, ApiError>;
|
||||
|
||||
fn uuid_get(
|
||||
async fn uuid_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=UuidGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<UuidGetResponse, ApiError>;
|
||||
|
||||
fn xml_extra_post(
|
||||
async fn xml_extra_post(
|
||||
&self,
|
||||
duplicate_xml_object: Option<models::DuplicateXmlObject>,
|
||||
) -> Box<dyn Future<Item=XmlExtraPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<XmlExtraPostResponse, ApiError>;
|
||||
|
||||
fn xml_other_post(
|
||||
async fn xml_other_post(
|
||||
&self,
|
||||
another_xml_object: Option<models::AnotherXmlObject>,
|
||||
) -> Box<dyn Future<Item=XmlOtherPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<XmlOtherPostResponse, ApiError>;
|
||||
|
||||
fn xml_other_put(
|
||||
async fn xml_other_put(
|
||||
&self,
|
||||
another_xml_array: Option<models::AnotherXmlArray>,
|
||||
) -> Box<dyn Future<Item=XmlOtherPutResponse, Error=ApiError> + Send>;
|
||||
) -> Result<XmlOtherPutResponse, ApiError>;
|
||||
|
||||
/// Post an array
|
||||
fn xml_post(
|
||||
async fn xml_post(
|
||||
&self,
|
||||
xml_array: Option<models::XmlArray>,
|
||||
) -> Box<dyn Future<Item=XmlPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<XmlPostResponse, ApiError>;
|
||||
|
||||
fn xml_put(
|
||||
async fn xml_put(
|
||||
&self,
|
||||
xml_object: Option<models::XmlObject>,
|
||||
) -> Box<dyn Future<Item=XmlPutResponse, Error=ApiError> + Send>;
|
||||
) -> Result<XmlPutResponse, ApiError>;
|
||||
|
||||
fn create_repo(
|
||||
async fn create_repo(
|
||||
&self,
|
||||
object_param: models::ObjectParam,
|
||||
) -> Box<dyn Future<Item=CreateRepoResponse, Error=ApiError> + Send>;
|
||||
) -> Result<CreateRepoResponse, ApiError>;
|
||||
|
||||
fn get_repo_info(
|
||||
async fn get_repo_info(
|
||||
&self,
|
||||
repo_id: String,
|
||||
) -> Box<dyn Future<Item=GetRepoInfoResponse, Error=ApiError> + Send>;
|
||||
) -> Result<GetRepoInfoResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait ContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
fn callback_with_header_post(
|
||||
#[async_trait]
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
async fn callback_with_header_post(
|
||||
&self,
|
||||
url: String,
|
||||
) -> Box<dyn Future<Item=CallbackWithHeaderPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<CallbackWithHeaderPostResponse, ApiError>
|
||||
{
|
||||
self.api().callback_with_header_post(url, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().callback_with_header_post(url, &context).await
|
||||
}
|
||||
|
||||
fn complex_query_param_get(
|
||||
async fn complex_query_param_get(
|
||||
&self,
|
||||
list_of_strings: Option<&Vec<models::StringObject>>,
|
||||
) -> Box<dyn Future<Item=ComplexQueryParamGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<ComplexQueryParamGetResponse, ApiError>
|
||||
{
|
||||
self.api().complex_query_param_get(list_of_strings, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().complex_query_param_get(list_of_strings, &context).await
|
||||
}
|
||||
|
||||
fn enum_in_path_path_param_get(
|
||||
async fn enum_in_path_path_param_get(
|
||||
&self,
|
||||
path_param: models::StringEnum,
|
||||
) -> Box<dyn Future<Item=EnumInPathPathParamGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<EnumInPathPathParamGetResponse, ApiError>
|
||||
{
|
||||
self.api().enum_in_path_path_param_get(path_param, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().enum_in_path_path_param_get(path_param, &context).await
|
||||
}
|
||||
|
||||
fn mandatory_request_header_get(
|
||||
async fn mandatory_request_header_get(
|
||||
&self,
|
||||
x_header: String,
|
||||
) -> Box<dyn Future<Item=MandatoryRequestHeaderGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<MandatoryRequestHeaderGetResponse, ApiError>
|
||||
{
|
||||
self.api().mandatory_request_header_get(x_header, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().mandatory_request_header_get(x_header, &context).await
|
||||
}
|
||||
|
||||
fn merge_patch_json_get(
|
||||
async fn merge_patch_json_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=MergePatchJsonGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<MergePatchJsonGetResponse, ApiError>
|
||||
{
|
||||
self.api().merge_patch_json_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().merge_patch_json_get(&context).await
|
||||
}
|
||||
|
||||
/// Get some stuff.
|
||||
fn multiget_get(
|
||||
async fn multiget_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=MultigetGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<MultigetGetResponse, ApiError>
|
||||
{
|
||||
self.api().multiget_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().multiget_get(&context).await
|
||||
}
|
||||
|
||||
fn multiple_auth_scheme_get(
|
||||
async fn multiple_auth_scheme_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=MultipleAuthSchemeGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<MultipleAuthSchemeGetResponse, ApiError>
|
||||
{
|
||||
self.api().multiple_auth_scheme_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().multiple_auth_scheme_get(&context).await
|
||||
}
|
||||
|
||||
fn override_server_get(
|
||||
async fn override_server_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=OverrideServerGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<OverrideServerGetResponse, ApiError>
|
||||
{
|
||||
self.api().override_server_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().override_server_get(&context).await
|
||||
}
|
||||
|
||||
/// Get some stuff with parameters.
|
||||
fn paramget_get(
|
||||
async fn paramget_get(
|
||||
&self,
|
||||
uuid: Option<uuid::Uuid>,
|
||||
some_object: Option<models::ObjectParam>,
|
||||
some_list: Option<models::MyIdList>,
|
||||
) -> Box<dyn Future<Item=ParamgetGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<ParamgetGetResponse, ApiError>
|
||||
{
|
||||
self.api().paramget_get(uuid, some_object, some_list, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().paramget_get(uuid, some_object, some_list, &context).await
|
||||
}
|
||||
|
||||
fn readonly_auth_scheme_get(
|
||||
async fn readonly_auth_scheme_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=ReadonlyAuthSchemeGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<ReadonlyAuthSchemeGetResponse, ApiError>
|
||||
{
|
||||
self.api().readonly_auth_scheme_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().readonly_auth_scheme_get(&context).await
|
||||
}
|
||||
|
||||
fn register_callback_post(
|
||||
async fn register_callback_post(
|
||||
&self,
|
||||
url: String,
|
||||
) -> Box<dyn Future<Item=RegisterCallbackPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<RegisterCallbackPostResponse, ApiError>
|
||||
{
|
||||
self.api().register_callback_post(url, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().register_callback_post(url, &context).await
|
||||
}
|
||||
|
||||
fn required_octet_stream_put(
|
||||
async fn required_octet_stream_put(
|
||||
&self,
|
||||
body: swagger::ByteArray,
|
||||
) -> Box<dyn Future<Item=RequiredOctetStreamPutResponse, Error=ApiError> + Send>
|
||||
) -> Result<RequiredOctetStreamPutResponse, ApiError>
|
||||
{
|
||||
self.api().required_octet_stream_put(body, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().required_octet_stream_put(body, &context).await
|
||||
}
|
||||
|
||||
fn responses_with_headers_get(
|
||||
async fn responses_with_headers_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=ResponsesWithHeadersGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<ResponsesWithHeadersGetResponse, ApiError>
|
||||
{
|
||||
self.api().responses_with_headers_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().responses_with_headers_get(&context).await
|
||||
}
|
||||
|
||||
fn rfc7807_get(
|
||||
async fn rfc7807_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Rfc7807GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Rfc7807GetResponse, ApiError>
|
||||
{
|
||||
self.api().rfc7807_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().rfc7807_get(&context).await
|
||||
}
|
||||
|
||||
fn untyped_property_get(
|
||||
async fn untyped_property_get(
|
||||
&self,
|
||||
object_untyped_props: Option<models::ObjectUntypedProps>,
|
||||
) -> Box<dyn Future<Item=UntypedPropertyGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<UntypedPropertyGetResponse, ApiError>
|
||||
{
|
||||
self.api().untyped_property_get(object_untyped_props, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().untyped_property_get(object_untyped_props, &context).await
|
||||
}
|
||||
|
||||
fn uuid_get(
|
||||
async fn uuid_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=UuidGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<UuidGetResponse, ApiError>
|
||||
{
|
||||
self.api().uuid_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().uuid_get(&context).await
|
||||
}
|
||||
|
||||
fn xml_extra_post(
|
||||
async fn xml_extra_post(
|
||||
&self,
|
||||
duplicate_xml_object: Option<models::DuplicateXmlObject>,
|
||||
) -> Box<dyn Future<Item=XmlExtraPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<XmlExtraPostResponse, ApiError>
|
||||
{
|
||||
self.api().xml_extra_post(duplicate_xml_object, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().xml_extra_post(duplicate_xml_object, &context).await
|
||||
}
|
||||
|
||||
fn xml_other_post(
|
||||
async fn xml_other_post(
|
||||
&self,
|
||||
another_xml_object: Option<models::AnotherXmlObject>,
|
||||
) -> Box<dyn Future<Item=XmlOtherPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<XmlOtherPostResponse, ApiError>
|
||||
{
|
||||
self.api().xml_other_post(another_xml_object, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().xml_other_post(another_xml_object, &context).await
|
||||
}
|
||||
|
||||
fn xml_other_put(
|
||||
async fn xml_other_put(
|
||||
&self,
|
||||
another_xml_array: Option<models::AnotherXmlArray>,
|
||||
) -> Box<dyn Future<Item=XmlOtherPutResponse, Error=ApiError> + Send>
|
||||
) -> Result<XmlOtherPutResponse, ApiError>
|
||||
{
|
||||
self.api().xml_other_put(another_xml_array, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().xml_other_put(another_xml_array, &context).await
|
||||
}
|
||||
|
||||
/// Post an array
|
||||
fn xml_post(
|
||||
async fn xml_post(
|
||||
&self,
|
||||
xml_array: Option<models::XmlArray>,
|
||||
) -> Box<dyn Future<Item=XmlPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<XmlPostResponse, ApiError>
|
||||
{
|
||||
self.api().xml_post(xml_array, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().xml_post(xml_array, &context).await
|
||||
}
|
||||
|
||||
fn xml_put(
|
||||
async fn xml_put(
|
||||
&self,
|
||||
xml_object: Option<models::XmlObject>,
|
||||
) -> Box<dyn Future<Item=XmlPutResponse, Error=ApiError> + Send>
|
||||
) -> Result<XmlPutResponse, ApiError>
|
||||
{
|
||||
self.api().xml_put(xml_object, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().xml_put(xml_object, &context).await
|
||||
}
|
||||
|
||||
fn create_repo(
|
||||
async fn create_repo(
|
||||
&self,
|
||||
object_param: models::ObjectParam,
|
||||
) -> Box<dyn Future<Item=CreateRepoResponse, Error=ApiError> + Send>
|
||||
) -> Result<CreateRepoResponse, ApiError>
|
||||
{
|
||||
self.api().create_repo(object_param, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().create_repo(object_param, &context).await
|
||||
}
|
||||
|
||||
fn get_repo_info(
|
||||
async fn get_repo_info(
|
||||
&self,
|
||||
repo_id: String,
|
||||
) -> Box<dyn Future<Item=GetRepoInfoResponse, Error=ApiError> + Send>
|
||||
) -> Result<GetRepoInfoResponse, ApiError>
|
||||
{
|
||||
self.api().get_repo_info(repo_id, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().get_repo_info(repo_id, &context).await
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum CallbackCallbackWithHeaderPostResponse {
|
||||
/// OK
|
||||
@@ -666,68 +711,89 @@ pub enum CallbackCallbackPostResponse {
|
||||
|
||||
|
||||
/// Callback API
|
||||
pub trait CallbackApi<C> {
|
||||
fn callback_callback_with_header_post(
|
||||
#[async_trait]
|
||||
pub trait CallbackApi<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
async fn callback_callback_with_header_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
information: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackCallbackWithHeaderPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<CallbackCallbackWithHeaderPostResponse, ApiError>;
|
||||
|
||||
fn callback_callback_post(
|
||||
async fn callback_callback_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackCallbackPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<CallbackCallbackPostResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Callback API without a `Context`
|
||||
pub trait CallbackApiNoContext {
|
||||
fn callback_callback_with_header_post(
|
||||
#[async_trait]
|
||||
pub trait CallbackApiNoContext<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
async fn callback_callback_with_header_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
information: Option<String>,
|
||||
) -> Box<dyn Future<Item=CallbackCallbackWithHeaderPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<CallbackCallbackWithHeaderPostResponse, ApiError>;
|
||||
|
||||
fn callback_callback_post(
|
||||
async fn callback_callback_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
) -> Box<dyn Future<Item=CallbackCallbackPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<CallbackCallbackPostResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait CallbackContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait CallbackContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: CallbackApi<C> + Sized, C> CallbackContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: CallbackApi<C> + Send + Sync, C: Clone + Send + Sync> CallbackContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: CallbackApi<C>, C> CallbackApiNoContext for ContextWrapper<'a, T, C> {
|
||||
fn callback_callback_with_header_post(
|
||||
#[async_trait]
|
||||
impl<T: CallbackApi<C> + Send + Sync, C: Clone + Send + Sync> CallbackApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
async fn callback_callback_with_header_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
information: Option<String>,
|
||||
) -> Box<dyn Future<Item=CallbackCallbackWithHeaderPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<CallbackCallbackWithHeaderPostResponse, ApiError>
|
||||
{
|
||||
let context = self.context().clone();
|
||||
self.api().callback_callback_with_header_post(
|
||||
callback_request_query_url,
|
||||
information,
|
||||
&self.context())
|
||||
&context).await
|
||||
}
|
||||
|
||||
fn callback_callback_post(
|
||||
async fn callback_callback_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
) -> Box<dyn Future<Item=CallbackCallbackPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<CallbackCallbackPostResponse, ApiError>
|
||||
{
|
||||
let context = self.context().clone();
|
||||
self.api().callback_callback_post(
|
||||
callback_request_query_url,
|
||||
&self.context())
|
||||
&context).await
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,68 +1,83 @@
|
||||
use futures;
|
||||
use futures::{Future, Stream, future, stream};
|
||||
use hyper;
|
||||
use hyper::client::HttpConnector;
|
||||
use async_trait::async_trait;
|
||||
use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use hyper::{Body, Uri, Response};
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use hyper_openssl::HttpsConnector;
|
||||
use serde_json;
|
||||
use hyper::{Body, Request, Response, service::Service, Uri};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Read, Error, ErrorKind};
|
||||
use std::error;
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use swagger;
|
||||
use swagger::{ApiError, Connector, client::Service, XSpanIdString, Has, AuthData};
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, AuthData, BodyExt, Connector, Has, XSpanIdString};
|
||||
use url::form_urlencoded;
|
||||
use url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET};
|
||||
use uuid;
|
||||
use serde_xml_rs;
|
||||
|
||||
|
||||
use crate::models;
|
||||
use crate::header;
|
||||
|
||||
url::define_encode_set! {
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
pub ID_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'|'}
|
||||
}
|
||||
/// https://url.spec.whatwg.org/#fragment-percent-encode-set
|
||||
#[allow(dead_code)]
|
||||
const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
|
||||
.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
|
||||
|
||||
/// This encode set is used for object IDs
|
||||
///
|
||||
/// Aside from the special characters defined in the `PATH_SEGMENT_ENCODE_SET`,
|
||||
/// the vertical bar (|) is encoded.
|
||||
#[allow(dead_code)]
|
||||
const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');
|
||||
|
||||
use crate::CallbackApi;
|
||||
use crate::CallbackCallbackWithHeaderPostResponse;
|
||||
use crate::CallbackCallbackPostResponse;
|
||||
|
||||
/// A client that implements the API by making HTTP calls out to a server.
|
||||
pub struct Client<F>
|
||||
pub struct Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
/// Inner service
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for Client<F>
|
||||
impl<S> fmt::Debug for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Client")
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Clone for Client<F>
|
||||
impl<S> Clone for Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Client {
|
||||
Self {
|
||||
client_service: self.client_service.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::ResponseFuture>
|
||||
impl<C> Client<hyper::client::Client<C, Body>> where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static
|
||||
{
|
||||
/// Create a client with a custom implementation of hyper::client::Connect.
|
||||
///
|
||||
@@ -76,26 +91,33 @@ impl Client<hyper::client::ResponseFuture>
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
|
||||
pub fn new_with_connector<C>(
|
||||
connector: C,
|
||||
) -> Self where
|
||||
C: hyper::client::connect::Connect + 'static,
|
||||
C::Transport: 'static,
|
||||
C::Future: 'static,
|
||||
pub fn new_with_connector(connector: C) -> Self
|
||||
{
|
||||
let client_service = Box::new(hyper::client::Client::builder().build(connector));
|
||||
let client_service = hyper::client::Client::builder().build(connector);
|
||||
|
||||
Client {
|
||||
client_service: Arc::new(client_service),
|
||||
Self {
|
||||
client_service,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<hyper::client::Client<hyper::client::HttpConnector, Body>>
|
||||
{
|
||||
/// Create an HTTP client.
|
||||
pub fn new_http() -> Self {
|
||||
let http_connector = Connector::builder().build();
|
||||
Self::new_with_connector(http_connector)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
type HttpConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
|
||||
|
||||
impl Client<hyper::client::Client<HttpsConnector, Body>>
|
||||
{
|
||||
/// Create a client with a TLS connection to the server.
|
||||
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
|
||||
pub fn new_https() -> Result<Self, native_tls::Error>
|
||||
@@ -155,60 +177,82 @@ impl Client<hyper::client::ResponseFuture>
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Client<F>
|
||||
impl<S> Client<S> where
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
{
|
||||
/// Constructor for creating a `Client` by passing in a pre-made `swagger::Service`
|
||||
///
|
||||
/// This allows adding custom wrappers around the underlying transport, for example for logging.
|
||||
pub fn new_with_client_service(
|
||||
client_service: Arc<Box<dyn Service<ReqBody=Body, Future=F> + Send + Sync>>,
|
||||
client_service: S,
|
||||
) -> Self {
|
||||
Client {
|
||||
client_service: client_service,
|
||||
client_service,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, F> CallbackApi<C> for Client<F> where
|
||||
C: Has<XSpanIdString> + Has<Option<AuthData>>,
|
||||
F: Future<Item=Response<Body>, Error=hyper::Error> + Send + 'static
|
||||
#[async_trait]
|
||||
impl<C, S> CallbackApi<C> for Client<S> where
|
||||
C: Has<XSpanIdString> + Has<Option<AuthData>> + Send + Sync,
|
||||
S: Service<
|
||||
Request<Body>,
|
||||
Response=Response<Body>,
|
||||
Error=hyper::Error> + Clone + Send + Sync,
|
||||
S::Future: Send + 'static,
|
||||
S::Error: Into<crate::ServiceError> + fmt::Display,
|
||||
{
|
||||
fn callback_callback_with_header_post(
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
|
||||
match self.client_service.clone().poll_ready(cx) {
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(Box::new(e))),
|
||||
Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
async fn callback_callback_with_header_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
param_information: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackCallbackWithHeaderPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CallbackCallbackWithHeaderPostResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{request_query_url}/callback-with-header"
|
||||
,request_query_url=callback_request_query_url
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
// Header parameters
|
||||
@@ -219,119 +263,112 @@ impl<C, F> CallbackApi<C> for Client<F> where
|
||||
match header::IntoHeaderValue(param_information.clone()).try_into() {
|
||||
Ok(header) => header,
|
||||
Err(e) => {
|
||||
return Box::new(future::err(ApiError(format!(
|
||||
"Invalid header information - {}", e)))) as Box<dyn Future<Item=_, Error=_> + Send>;
|
||||
return Err(ApiError(format!(
|
||||
"Invalid header information - {}", e)));
|
||||
},
|
||||
});
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
204 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
CallbackCallbackWithHeaderPostResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
204 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
CallbackCallbackWithHeaderPostResponse::OK
|
||||
)
|
||||
}
|
||||
}))
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn callback_callback_post(
|
||||
async fn callback_callback_post(
|
||||
&self,
|
||||
callback_request_query_url: String,
|
||||
context: &C) -> Box<dyn Future<Item=CallbackCallbackPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CallbackCallbackPostResponse, ApiError>
|
||||
{
|
||||
let mut client_service = self.client_service.clone();
|
||||
let mut uri = format!(
|
||||
"{request_query_url}/callback"
|
||||
,request_query_url=callback_request_query_url
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
let query_string = {
|
||||
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
|
||||
query_string.finish()
|
||||
};
|
||||
if !query_string.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
uri += &query_string;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
let mut request = match Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
|
||||
};
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
|
||||
});
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
204 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
CallbackCallbackPostResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
let mut response = client_service.call(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e))).await?;
|
||||
|
||||
match response.status().as_u16() {
|
||||
204 => {
|
||||
let body = response.into_body();
|
||||
Ok(
|
||||
CallbackCallbackPostResponse::OK
|
||||
)
|
||||
}
|
||||
}))
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
let body = response.into_body()
|
||||
.take(100)
|
||||
.to_raw().await;
|
||||
Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(body) => match String::from_utf8(body) {
|
||||
Ok(body) => body,
|
||||
Err(e) => format!("<Body was not UTF8: {:?}>", e),
|
||||
},
|
||||
Err(e) => format!("<Failed to read body: {}>", e),
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ edition = "2018"
|
||||
[features]
|
||||
default = ["client", "server"]
|
||||
client = [
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
"serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static"
|
||||
@@ -18,35 +18,37 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -57,13 +59,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use ops_v3::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError,
|
||||
Op10GetResponse,
|
||||
Op11GetResponse,
|
||||
Op12GetResponse,
|
||||
@@ -42,7 +41,7 @@ use ops_v3::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
Op6GetResponse,
|
||||
Op7GetResponse,
|
||||
Op8GetResponse,
|
||||
Op9GetResponse
|
||||
Op9GetResponse,
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -51,7 +50,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -123,21 +124,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:8080";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use ops_v3::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
ops_v3::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +96,6 @@ impl<C> Server<C> {
|
||||
|
||||
use ops_v3::{
|
||||
Api,
|
||||
ApiError,
|
||||
Op10GetResponse,
|
||||
Op11GetResponse,
|
||||
Op12GetResponse,
|
||||
@@ -145,339 +135,343 @@ use ops_v3::{
|
||||
Op9GetResponse,
|
||||
};
|
||||
use ops_v3::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
fn op10_get(
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
async fn op10_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op10GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op10GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op10_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op11_get(
|
||||
async fn op11_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op11GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op11GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op11_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op12_get(
|
||||
async fn op12_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op12GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op12GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op12_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op13_get(
|
||||
async fn op13_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op13GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op13GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op13_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op14_get(
|
||||
async fn op14_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op14GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op14GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op14_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op15_get(
|
||||
async fn op15_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op15GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op15GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op15_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op16_get(
|
||||
async fn op16_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op16GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op16GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op16_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op17_get(
|
||||
async fn op17_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op17GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op17GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op17_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op18_get(
|
||||
async fn op18_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op18GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op18GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op18_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op19_get(
|
||||
async fn op19_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op19GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op19GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op19_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op1_get(
|
||||
async fn op1_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op1GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op1GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op1_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op20_get(
|
||||
async fn op20_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op20GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op20GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op20_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op21_get(
|
||||
async fn op21_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op21GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op21GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op21_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op22_get(
|
||||
async fn op22_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op22GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op22GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op22_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op23_get(
|
||||
async fn op23_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op23GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op23GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op23_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op24_get(
|
||||
async fn op24_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op24GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op24GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op24_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op25_get(
|
||||
async fn op25_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op25GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op25GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op25_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op26_get(
|
||||
async fn op26_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op26GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op26GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op26_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op27_get(
|
||||
async fn op27_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op27GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op27GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op27_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op28_get(
|
||||
async fn op28_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op28GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op28GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op28_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op29_get(
|
||||
async fn op29_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op29GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op29GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op29_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op2_get(
|
||||
async fn op2_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op2GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op2GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op2_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op30_get(
|
||||
async fn op30_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op30GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op30GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op30_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op31_get(
|
||||
async fn op31_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op31GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op31GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op31_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op32_get(
|
||||
async fn op32_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op32GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op32GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op32_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op33_get(
|
||||
async fn op33_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op33GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op33GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op33_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op34_get(
|
||||
async fn op34_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op34GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op34GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op34_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op35_get(
|
||||
async fn op35_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op35GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op35GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op35_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op36_get(
|
||||
async fn op36_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op36GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op36GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op36_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op37_get(
|
||||
async fn op37_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op37GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op37GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op37_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op3_get(
|
||||
async fn op3_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op3GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op3GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op3_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op4_get(
|
||||
async fn op4_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op4GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op4GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op4_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op5_get(
|
||||
async fn op5_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op5GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op5GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op5_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op6_get(
|
||||
async fn op6_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op6GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op6GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op6_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op7_get(
|
||||
async fn op7_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op7GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op7GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op7_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op8_get(
|
||||
async fn op8_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op8GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op8GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op8_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn op9_get(
|
||||
async fn op9_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op9GetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Op9GetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("op9_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,33 +83,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use std::io::Error;
|
||||
use std::error::Error;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::{ApiError, ContextWrapper};
|
||||
|
||||
#[deprecated(note = "Import swagger-rs directly")]
|
||||
pub use swagger::{ApiError, ContextWrapper};
|
||||
#[deprecated(note = "Import futures directly")]
|
||||
pub use futures::Future;
|
||||
type ServiceError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub const BASE_PATH: &'static str = "";
|
||||
pub const API_VERSION: &'static str = "0.0.1";
|
||||
@@ -234,583 +234,642 @@ pub enum Op9GetResponse {
|
||||
}
|
||||
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
fn op10_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op10GetResponse, Error=ApiError> + Send>;
|
||||
#[async_trait]
|
||||
pub trait Api<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn op11_get(
|
||||
async fn op10_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op11GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op10GetResponse, ApiError>;
|
||||
|
||||
fn op12_get(
|
||||
async fn op11_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op12GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op11GetResponse, ApiError>;
|
||||
|
||||
fn op13_get(
|
||||
async fn op12_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op13GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op12GetResponse, ApiError>;
|
||||
|
||||
fn op14_get(
|
||||
async fn op13_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op14GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op13GetResponse, ApiError>;
|
||||
|
||||
fn op15_get(
|
||||
async fn op14_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op15GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op14GetResponse, ApiError>;
|
||||
|
||||
fn op16_get(
|
||||
async fn op15_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op16GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op15GetResponse, ApiError>;
|
||||
|
||||
fn op17_get(
|
||||
async fn op16_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op17GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op16GetResponse, ApiError>;
|
||||
|
||||
fn op18_get(
|
||||
async fn op17_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op18GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op17GetResponse, ApiError>;
|
||||
|
||||
fn op19_get(
|
||||
async fn op18_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op19GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op18GetResponse, ApiError>;
|
||||
|
||||
fn op1_get(
|
||||
async fn op19_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op1GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op19GetResponse, ApiError>;
|
||||
|
||||
fn op20_get(
|
||||
async fn op1_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op20GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op1GetResponse, ApiError>;
|
||||
|
||||
fn op21_get(
|
||||
async fn op20_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op21GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op20GetResponse, ApiError>;
|
||||
|
||||
fn op22_get(
|
||||
async fn op21_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op22GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op21GetResponse, ApiError>;
|
||||
|
||||
fn op23_get(
|
||||
async fn op22_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op23GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op22GetResponse, ApiError>;
|
||||
|
||||
fn op24_get(
|
||||
async fn op23_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op24GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op23GetResponse, ApiError>;
|
||||
|
||||
fn op25_get(
|
||||
async fn op24_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op25GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op24GetResponse, ApiError>;
|
||||
|
||||
fn op26_get(
|
||||
async fn op25_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op26GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op25GetResponse, ApiError>;
|
||||
|
||||
fn op27_get(
|
||||
async fn op26_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op27GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op26GetResponse, ApiError>;
|
||||
|
||||
fn op28_get(
|
||||
async fn op27_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op28GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op27GetResponse, ApiError>;
|
||||
|
||||
fn op29_get(
|
||||
async fn op28_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op29GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op28GetResponse, ApiError>;
|
||||
|
||||
fn op2_get(
|
||||
async fn op29_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op2GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op29GetResponse, ApiError>;
|
||||
|
||||
fn op30_get(
|
||||
async fn op2_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op30GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op2GetResponse, ApiError>;
|
||||
|
||||
fn op31_get(
|
||||
async fn op30_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op31GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op30GetResponse, ApiError>;
|
||||
|
||||
fn op32_get(
|
||||
async fn op31_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op32GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op31GetResponse, ApiError>;
|
||||
|
||||
fn op33_get(
|
||||
async fn op32_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op33GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op32GetResponse, ApiError>;
|
||||
|
||||
fn op34_get(
|
||||
async fn op33_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op34GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op33GetResponse, ApiError>;
|
||||
|
||||
fn op35_get(
|
||||
async fn op34_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op35GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op34GetResponse, ApiError>;
|
||||
|
||||
fn op36_get(
|
||||
async fn op35_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op36GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op35GetResponse, ApiError>;
|
||||
|
||||
fn op37_get(
|
||||
async fn op36_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op37GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op36GetResponse, ApiError>;
|
||||
|
||||
fn op3_get(
|
||||
async fn op37_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op3GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op37GetResponse, ApiError>;
|
||||
|
||||
fn op4_get(
|
||||
async fn op3_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op4GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op3GetResponse, ApiError>;
|
||||
|
||||
fn op5_get(
|
||||
async fn op4_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op5GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op4GetResponse, ApiError>;
|
||||
|
||||
fn op6_get(
|
||||
async fn op5_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op6GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op5GetResponse, ApiError>;
|
||||
|
||||
fn op7_get(
|
||||
async fn op6_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op7GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op6GetResponse, ApiError>;
|
||||
|
||||
fn op8_get(
|
||||
async fn op7_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op8GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op7GetResponse, ApiError>;
|
||||
|
||||
fn op9_get(
|
||||
async fn op8_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Op9GetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<Op8GetResponse, ApiError>;
|
||||
|
||||
async fn op9_get(
|
||||
&self,
|
||||
context: &C) -> Result<Op9GetResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
pub trait ApiNoContext {
|
||||
fn op10_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op10GetResponse, Error=ApiError> + Send>;
|
||||
/// API where `Context` isn't passed on every API call
|
||||
#[async_trait]
|
||||
pub trait ApiNoContext<C: Send + Sync> {
|
||||
|
||||
fn op11_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op11GetResponse, Error=ApiError> + Send>;
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn op12_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op12GetResponse, Error=ApiError> + Send>;
|
||||
fn context(&self) -> &C;
|
||||
|
||||
fn op13_get(
|
||||
async fn op10_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op13GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op10GetResponse, ApiError>;
|
||||
|
||||
fn op14_get(
|
||||
async fn op11_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op14GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op11GetResponse, ApiError>;
|
||||
|
||||
fn op15_get(
|
||||
async fn op12_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op15GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op12GetResponse, ApiError>;
|
||||
|
||||
fn op16_get(
|
||||
async fn op13_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op16GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op13GetResponse, ApiError>;
|
||||
|
||||
fn op17_get(
|
||||
async fn op14_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op17GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op14GetResponse, ApiError>;
|
||||
|
||||
fn op18_get(
|
||||
async fn op15_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op18GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op15GetResponse, ApiError>;
|
||||
|
||||
fn op19_get(
|
||||
async fn op16_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op19GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op16GetResponse, ApiError>;
|
||||
|
||||
fn op1_get(
|
||||
async fn op17_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op1GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op17GetResponse, ApiError>;
|
||||
|
||||
fn op20_get(
|
||||
async fn op18_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op20GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op18GetResponse, ApiError>;
|
||||
|
||||
fn op21_get(
|
||||
async fn op19_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op21GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op19GetResponse, ApiError>;
|
||||
|
||||
fn op22_get(
|
||||
async fn op1_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op22GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op1GetResponse, ApiError>;
|
||||
|
||||
fn op23_get(
|
||||
async fn op20_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op23GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op20GetResponse, ApiError>;
|
||||
|
||||
fn op24_get(
|
||||
async fn op21_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op24GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op21GetResponse, ApiError>;
|
||||
|
||||
fn op25_get(
|
||||
async fn op22_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op25GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op22GetResponse, ApiError>;
|
||||
|
||||
fn op26_get(
|
||||
async fn op23_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op26GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op23GetResponse, ApiError>;
|
||||
|
||||
fn op27_get(
|
||||
async fn op24_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op27GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op24GetResponse, ApiError>;
|
||||
|
||||
fn op28_get(
|
||||
async fn op25_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op28GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op25GetResponse, ApiError>;
|
||||
|
||||
fn op29_get(
|
||||
async fn op26_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op29GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op26GetResponse, ApiError>;
|
||||
|
||||
fn op2_get(
|
||||
async fn op27_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op2GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op27GetResponse, ApiError>;
|
||||
|
||||
fn op30_get(
|
||||
async fn op28_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op30GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op28GetResponse, ApiError>;
|
||||
|
||||
fn op31_get(
|
||||
async fn op29_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op31GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op29GetResponse, ApiError>;
|
||||
|
||||
fn op32_get(
|
||||
async fn op2_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op32GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op2GetResponse, ApiError>;
|
||||
|
||||
fn op33_get(
|
||||
async fn op30_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op33GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op30GetResponse, ApiError>;
|
||||
|
||||
fn op34_get(
|
||||
async fn op31_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op34GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op31GetResponse, ApiError>;
|
||||
|
||||
fn op35_get(
|
||||
async fn op32_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op35GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op32GetResponse, ApiError>;
|
||||
|
||||
fn op36_get(
|
||||
async fn op33_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op36GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op33GetResponse, ApiError>;
|
||||
|
||||
fn op37_get(
|
||||
async fn op34_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op37GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op34GetResponse, ApiError>;
|
||||
|
||||
fn op3_get(
|
||||
async fn op35_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op3GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op35GetResponse, ApiError>;
|
||||
|
||||
fn op4_get(
|
||||
async fn op36_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op4GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op36GetResponse, ApiError>;
|
||||
|
||||
fn op5_get(
|
||||
async fn op37_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op5GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op37GetResponse, ApiError>;
|
||||
|
||||
fn op6_get(
|
||||
async fn op3_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op6GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op3GetResponse, ApiError>;
|
||||
|
||||
fn op7_get(
|
||||
async fn op4_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op7GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op4GetResponse, ApiError>;
|
||||
|
||||
fn op8_get(
|
||||
async fn op5_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op8GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op5GetResponse, ApiError>;
|
||||
|
||||
fn op9_get(
|
||||
async fn op6_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op9GetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<Op6GetResponse, ApiError>;
|
||||
|
||||
async fn op7_get(
|
||||
&self,
|
||||
) -> Result<Op7GetResponse, ApiError>;
|
||||
|
||||
async fn op8_get(
|
||||
&self,
|
||||
) -> Result<Op8GetResponse, ApiError>;
|
||||
|
||||
async fn op9_get(
|
||||
&self,
|
||||
) -> Result<Op9GetResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait ContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
fn op10_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op10GetResponse, Error=ApiError> + Send>
|
||||
{
|
||||
self.api().op10_get(&self.context())
|
||||
#[async_trait]
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn op11_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op11GetResponse, Error=ApiError> + Send>
|
||||
{
|
||||
self.api().op11_get(&self.context())
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
fn op12_get(
|
||||
async fn op10_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op12GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op10GetResponse, ApiError>
|
||||
{
|
||||
self.api().op12_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op10_get(&context).await
|
||||
}
|
||||
|
||||
fn op13_get(
|
||||
async fn op11_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op13GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op11GetResponse, ApiError>
|
||||
{
|
||||
self.api().op13_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op11_get(&context).await
|
||||
}
|
||||
|
||||
fn op14_get(
|
||||
async fn op12_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op14GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op12GetResponse, ApiError>
|
||||
{
|
||||
self.api().op14_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op12_get(&context).await
|
||||
}
|
||||
|
||||
fn op15_get(
|
||||
async fn op13_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op15GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op13GetResponse, ApiError>
|
||||
{
|
||||
self.api().op15_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op13_get(&context).await
|
||||
}
|
||||
|
||||
fn op16_get(
|
||||
async fn op14_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op16GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op14GetResponse, ApiError>
|
||||
{
|
||||
self.api().op16_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op14_get(&context).await
|
||||
}
|
||||
|
||||
fn op17_get(
|
||||
async fn op15_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op17GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op15GetResponse, ApiError>
|
||||
{
|
||||
self.api().op17_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op15_get(&context).await
|
||||
}
|
||||
|
||||
fn op18_get(
|
||||
async fn op16_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op18GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op16GetResponse, ApiError>
|
||||
{
|
||||
self.api().op18_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op16_get(&context).await
|
||||
}
|
||||
|
||||
fn op19_get(
|
||||
async fn op17_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op19GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op17GetResponse, ApiError>
|
||||
{
|
||||
self.api().op19_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op17_get(&context).await
|
||||
}
|
||||
|
||||
fn op1_get(
|
||||
async fn op18_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op1GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op18GetResponse, ApiError>
|
||||
{
|
||||
self.api().op1_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op18_get(&context).await
|
||||
}
|
||||
|
||||
fn op20_get(
|
||||
async fn op19_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op20GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op19GetResponse, ApiError>
|
||||
{
|
||||
self.api().op20_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op19_get(&context).await
|
||||
}
|
||||
|
||||
fn op21_get(
|
||||
async fn op1_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op21GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op1GetResponse, ApiError>
|
||||
{
|
||||
self.api().op21_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op1_get(&context).await
|
||||
}
|
||||
|
||||
fn op22_get(
|
||||
async fn op20_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op22GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op20GetResponse, ApiError>
|
||||
{
|
||||
self.api().op22_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op20_get(&context).await
|
||||
}
|
||||
|
||||
fn op23_get(
|
||||
async fn op21_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op23GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op21GetResponse, ApiError>
|
||||
{
|
||||
self.api().op23_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op21_get(&context).await
|
||||
}
|
||||
|
||||
fn op24_get(
|
||||
async fn op22_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op24GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op22GetResponse, ApiError>
|
||||
{
|
||||
self.api().op24_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op22_get(&context).await
|
||||
}
|
||||
|
||||
fn op25_get(
|
||||
async fn op23_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op25GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op23GetResponse, ApiError>
|
||||
{
|
||||
self.api().op25_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op23_get(&context).await
|
||||
}
|
||||
|
||||
fn op26_get(
|
||||
async fn op24_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op26GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op24GetResponse, ApiError>
|
||||
{
|
||||
self.api().op26_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op24_get(&context).await
|
||||
}
|
||||
|
||||
fn op27_get(
|
||||
async fn op25_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op27GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op25GetResponse, ApiError>
|
||||
{
|
||||
self.api().op27_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op25_get(&context).await
|
||||
}
|
||||
|
||||
fn op28_get(
|
||||
async fn op26_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op28GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op26GetResponse, ApiError>
|
||||
{
|
||||
self.api().op28_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op26_get(&context).await
|
||||
}
|
||||
|
||||
fn op29_get(
|
||||
async fn op27_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op29GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op27GetResponse, ApiError>
|
||||
{
|
||||
self.api().op29_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op27_get(&context).await
|
||||
}
|
||||
|
||||
fn op2_get(
|
||||
async fn op28_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op2GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op28GetResponse, ApiError>
|
||||
{
|
||||
self.api().op2_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op28_get(&context).await
|
||||
}
|
||||
|
||||
fn op30_get(
|
||||
async fn op29_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op30GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op29GetResponse, ApiError>
|
||||
{
|
||||
self.api().op30_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op29_get(&context).await
|
||||
}
|
||||
|
||||
fn op31_get(
|
||||
async fn op2_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op31GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op2GetResponse, ApiError>
|
||||
{
|
||||
self.api().op31_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op2_get(&context).await
|
||||
}
|
||||
|
||||
fn op32_get(
|
||||
async fn op30_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op32GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op30GetResponse, ApiError>
|
||||
{
|
||||
self.api().op32_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op30_get(&context).await
|
||||
}
|
||||
|
||||
fn op33_get(
|
||||
async fn op31_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op33GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op31GetResponse, ApiError>
|
||||
{
|
||||
self.api().op33_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op31_get(&context).await
|
||||
}
|
||||
|
||||
fn op34_get(
|
||||
async fn op32_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op34GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op32GetResponse, ApiError>
|
||||
{
|
||||
self.api().op34_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op32_get(&context).await
|
||||
}
|
||||
|
||||
fn op35_get(
|
||||
async fn op33_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op35GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op33GetResponse, ApiError>
|
||||
{
|
||||
self.api().op35_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op33_get(&context).await
|
||||
}
|
||||
|
||||
fn op36_get(
|
||||
async fn op34_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op36GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op34GetResponse, ApiError>
|
||||
{
|
||||
self.api().op36_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op34_get(&context).await
|
||||
}
|
||||
|
||||
fn op37_get(
|
||||
async fn op35_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op37GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op35GetResponse, ApiError>
|
||||
{
|
||||
self.api().op37_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op35_get(&context).await
|
||||
}
|
||||
|
||||
fn op3_get(
|
||||
async fn op36_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op3GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op36GetResponse, ApiError>
|
||||
{
|
||||
self.api().op3_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op36_get(&context).await
|
||||
}
|
||||
|
||||
fn op4_get(
|
||||
async fn op37_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op4GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op37GetResponse, ApiError>
|
||||
{
|
||||
self.api().op4_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op37_get(&context).await
|
||||
}
|
||||
|
||||
fn op5_get(
|
||||
async fn op3_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op5GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op3GetResponse, ApiError>
|
||||
{
|
||||
self.api().op5_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op3_get(&context).await
|
||||
}
|
||||
|
||||
fn op6_get(
|
||||
async fn op4_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op6GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op4GetResponse, ApiError>
|
||||
{
|
||||
self.api().op6_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op4_get(&context).await
|
||||
}
|
||||
|
||||
fn op7_get(
|
||||
async fn op5_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op7GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op5GetResponse, ApiError>
|
||||
{
|
||||
self.api().op7_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op5_get(&context).await
|
||||
}
|
||||
|
||||
fn op8_get(
|
||||
async fn op6_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op8GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op6GetResponse, ApiError>
|
||||
{
|
||||
self.api().op8_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op6_get(&context).await
|
||||
}
|
||||
|
||||
fn op9_get(
|
||||
async fn op7_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=Op9GetResponse, Error=ApiError> + Send>
|
||||
) -> Result<Op7GetResponse, ApiError>
|
||||
{
|
||||
self.api().op9_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().op7_get(&context).await
|
||||
}
|
||||
|
||||
async fn op8_get(
|
||||
&self,
|
||||
) -> Result<Op8GetResponse, ApiError>
|
||||
{
|
||||
let context = self.context().clone();
|
||||
self.api().op8_get(&context).await
|
||||
}
|
||||
|
||||
async fn op9_get(
|
||||
&self,
|
||||
) -> Result<Op9GetResponse, ApiError>
|
||||
{
|
||||
let context = self.context().clone();
|
||||
self.api().op9_get(&context).await
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub mod client;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ client = [
|
||||
"mime_0_2",
|
||||
"multipart", "multipart/client", "swagger/multipart",
|
||||
"serde_urlencoded",
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
"mime_0_2",
|
||||
@@ -23,20 +23,22 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
@@ -45,20 +47,20 @@ serde_json = "1.0"
|
||||
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"}
|
||||
mime_0_2 = { package = "mime", version = "0.2.6", optional = true }
|
||||
multipart = { version = "0.16", default-features = false, optional = true }
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
uuid = {version = "0.8", features = ["serde", "v4"]}
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
serde_urlencoded = {version = "0.5.1", optional = true}
|
||||
serde_urlencoded = {version = "0.6.1", optional = true}
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -69,12 +71,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use petstore_with_fake_endpoints_models_for_testing::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError,
|
||||
TestSpecialTagsResponse,
|
||||
Call123exampleResponse,
|
||||
FakeOuterBooleanSerializeResponse,
|
||||
@@ -40,7 +39,7 @@ use petstore_with_fake_endpoints_models_for_testing::{Api, ApiNoContext, Client,
|
||||
GetUserByNameResponse,
|
||||
LoginUserResponse,
|
||||
LogoutUserResponse,
|
||||
UpdateUserResponse
|
||||
UpdateUserResponse,
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -49,7 +48,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -109,21 +110,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:80";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
use uuid;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use petstore_with_fake_endpoints_models_for_testing::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
petstore_with_fake_endpoints_models_for_testing::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +96,6 @@ impl<C> Server<C> {
|
||||
|
||||
use petstore_with_fake_endpoints_models_for_testing::{
|
||||
Api,
|
||||
ApiError,
|
||||
TestSpecialTagsResponse,
|
||||
Call123exampleResponse,
|
||||
FakeOuterBooleanSerializeResponse,
|
||||
@@ -143,111 +133,115 @@ use petstore_with_fake_endpoints_models_for_testing::{
|
||||
UpdateUserResponse,
|
||||
};
|
||||
use petstore_with_fake_endpoints_models_for_testing::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
/// To test special tags
|
||||
fn test_special_tags(
|
||||
async fn test_special_tags(
|
||||
&self,
|
||||
body: models::Client,
|
||||
context: &C) -> Box<dyn Future<Item=TestSpecialTagsResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestSpecialTagsResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_special_tags({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn call123example(
|
||||
async fn call123example(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=Call123exampleResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<Call123exampleResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("call123example() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn fake_outer_boolean_serialize(
|
||||
async fn fake_outer_boolean_serialize(
|
||||
&self,
|
||||
body: Option<models::OuterBoolean>,
|
||||
context: &C) -> Box<dyn Future<Item=FakeOuterBooleanSerializeResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FakeOuterBooleanSerializeResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("fake_outer_boolean_serialize({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn fake_outer_composite_serialize(
|
||||
async fn fake_outer_composite_serialize(
|
||||
&self,
|
||||
body: Option<models::OuterComposite>,
|
||||
context: &C) -> Box<dyn Future<Item=FakeOuterCompositeSerializeResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FakeOuterCompositeSerializeResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("fake_outer_composite_serialize({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn fake_outer_number_serialize(
|
||||
async fn fake_outer_number_serialize(
|
||||
&self,
|
||||
body: Option<models::OuterNumber>,
|
||||
context: &C) -> Box<dyn Future<Item=FakeOuterNumberSerializeResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FakeOuterNumberSerializeResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("fake_outer_number_serialize({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn fake_outer_string_serialize(
|
||||
async fn fake_outer_string_serialize(
|
||||
&self,
|
||||
body: Option<models::OuterString>,
|
||||
context: &C) -> Box<dyn Future<Item=FakeOuterStringSerializeResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FakeOuterStringSerializeResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("fake_outer_string_serialize({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn fake_response_with_numerical_description(
|
||||
async fn fake_response_with_numerical_description(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=FakeResponseWithNumericalDescriptionResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FakeResponseWithNumericalDescriptionResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("fake_response_with_numerical_description() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn hyphen_param(
|
||||
async fn hyphen_param(
|
||||
&self,
|
||||
hyphen_param: String,
|
||||
context: &C) -> Box<dyn Future<Item=HyphenParamResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<HyphenParamResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("hyphen_param(\"{}\") - X-Span-ID: {:?}", hyphen_param, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn test_body_with_query_params(
|
||||
async fn test_body_with_query_params(
|
||||
&self,
|
||||
query: String,
|
||||
body: models::User,
|
||||
context: &C) -> Box<dyn Future<Item=TestBodyWithQueryParamsResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestBodyWithQueryParamsResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_body_with_query_params(\"{}\", {:?}) - X-Span-ID: {:?}", query, body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// To test \"client\" model
|
||||
fn test_client_model(
|
||||
async fn test_client_model(
|
||||
&self,
|
||||
body: models::Client,
|
||||
context: &C) -> Box<dyn Future<Item=TestClientModelResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestClientModelResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_client_model({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
|
||||
fn test_endpoint_parameters(
|
||||
async fn test_endpoint_parameters(
|
||||
&self,
|
||||
number: f64,
|
||||
double: f64,
|
||||
@@ -263,15 +257,15 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
date_time: Option<chrono::DateTime::<chrono::Utc>>,
|
||||
password: Option<String>,
|
||||
callback: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=TestEndpointParametersResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestEndpointParametersResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_endpoint_parameters({}, {}, \"{}\", {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", number, double, pattern_without_delimiter, byte, integer, int32, int64, float, string, binary, date, date_time, password, callback, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// To test enum parameters
|
||||
fn test_enum_parameters(
|
||||
async fn test_enum_parameters(
|
||||
&self,
|
||||
enum_header_string_array: Option<&Vec<String>>,
|
||||
enum_header_string: Option<String>,
|
||||
@@ -280,270 +274,270 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
enum_query_integer: Option<i32>,
|
||||
enum_query_double: Option<f64>,
|
||||
enum_form_string: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=TestEnumParametersResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestEnumParametersResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_enum_parameters({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, enum_form_string, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// test inline additionalProperties
|
||||
fn test_inline_additional_properties(
|
||||
async fn test_inline_additional_properties(
|
||||
&self,
|
||||
param: std::collections::HashMap<String, String>,
|
||||
context: &C) -> Box<dyn Future<Item=TestInlineAdditionalPropertiesResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestInlineAdditionalPropertiesResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_inline_additional_properties({:?}) - X-Span-ID: {:?}", param, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// test json serialization of form data
|
||||
fn test_json_form_data(
|
||||
async fn test_json_form_data(
|
||||
&self,
|
||||
param: String,
|
||||
param2: String,
|
||||
context: &C) -> Box<dyn Future<Item=TestJsonFormDataResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestJsonFormDataResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_json_form_data(\"{}\", \"{}\") - X-Span-ID: {:?}", param, param2, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// To test class name in snake case
|
||||
fn test_classname(
|
||||
async fn test_classname(
|
||||
&self,
|
||||
body: models::Client,
|
||||
context: &C) -> Box<dyn Future<Item=TestClassnameResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<TestClassnameResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("test_classname({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Add a new pet to the store
|
||||
fn add_pet(
|
||||
async fn add_pet(
|
||||
&self,
|
||||
body: models::Pet,
|
||||
context: &C) -> Box<dyn Future<Item=AddPetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<AddPetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("add_pet({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Deletes a pet
|
||||
fn delete_pet(
|
||||
async fn delete_pet(
|
||||
&self,
|
||||
pet_id: i64,
|
||||
api_key: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=DeletePetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<DeletePetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("delete_pet({}, {:?}) - X-Span-ID: {:?}", pet_id, api_key, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Finds Pets by status
|
||||
fn find_pets_by_status(
|
||||
async fn find_pets_by_status(
|
||||
&self,
|
||||
status: &Vec<String>,
|
||||
context: &C) -> Box<dyn Future<Item=FindPetsByStatusResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FindPetsByStatusResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("find_pets_by_status({:?}) - X-Span-ID: {:?}", status, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Finds Pets by tags
|
||||
fn find_pets_by_tags(
|
||||
async fn find_pets_by_tags(
|
||||
&self,
|
||||
tags: &Vec<String>,
|
||||
context: &C) -> Box<dyn Future<Item=FindPetsByTagsResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FindPetsByTagsResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("find_pets_by_tags({:?}) - X-Span-ID: {:?}", tags, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Find pet by ID
|
||||
fn get_pet_by_id(
|
||||
async fn get_pet_by_id(
|
||||
&self,
|
||||
pet_id: i64,
|
||||
context: &C) -> Box<dyn Future<Item=GetPetByIdResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<GetPetByIdResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("get_pet_by_id({}) - X-Span-ID: {:?}", pet_id, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Update an existing pet
|
||||
fn update_pet(
|
||||
async fn update_pet(
|
||||
&self,
|
||||
body: models::Pet,
|
||||
context: &C) -> Box<dyn Future<Item=UpdatePetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<UpdatePetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("update_pet({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Updates a pet in the store with form data
|
||||
fn update_pet_with_form(
|
||||
async fn update_pet_with_form(
|
||||
&self,
|
||||
pet_id: i64,
|
||||
name: Option<String>,
|
||||
status: Option<String>,
|
||||
context: &C) -> Box<dyn Future<Item=UpdatePetWithFormResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<UpdatePetWithFormResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("update_pet_with_form({}, {:?}, {:?}) - X-Span-ID: {:?}", pet_id, name, status, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// uploads an image
|
||||
fn upload_file(
|
||||
async fn upload_file(
|
||||
&self,
|
||||
pet_id: i64,
|
||||
additional_metadata: Option<String>,
|
||||
file: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=UploadFileResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<UploadFileResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("upload_file({}, {:?}, {:?}) - X-Span-ID: {:?}", pet_id, additional_metadata, file, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Delete purchase order by ID
|
||||
fn delete_order(
|
||||
async fn delete_order(
|
||||
&self,
|
||||
order_id: String,
|
||||
context: &C) -> Box<dyn Future<Item=DeleteOrderResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<DeleteOrderResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("delete_order(\"{}\") - X-Span-ID: {:?}", order_id, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Returns pet inventories by status
|
||||
fn get_inventory(
|
||||
async fn get_inventory(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=GetInventoryResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<GetInventoryResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("get_inventory() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Find purchase order by ID
|
||||
fn get_order_by_id(
|
||||
async fn get_order_by_id(
|
||||
&self,
|
||||
order_id: i64,
|
||||
context: &C) -> Box<dyn Future<Item=GetOrderByIdResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<GetOrderByIdResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("get_order_by_id({}) - X-Span-ID: {:?}", order_id, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Place an order for a pet
|
||||
fn place_order(
|
||||
async fn place_order(
|
||||
&self,
|
||||
body: models::Order,
|
||||
context: &C) -> Box<dyn Future<Item=PlaceOrderResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<PlaceOrderResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("place_order({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Create user
|
||||
fn create_user(
|
||||
async fn create_user(
|
||||
&self,
|
||||
body: models::User,
|
||||
context: &C) -> Box<dyn Future<Item=CreateUserResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CreateUserResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("create_user({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Creates list of users with given input array
|
||||
fn create_users_with_array_input(
|
||||
async fn create_users_with_array_input(
|
||||
&self,
|
||||
body: &Vec<models::User>,
|
||||
context: &C) -> Box<dyn Future<Item=CreateUsersWithArrayInputResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CreateUsersWithArrayInputResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("create_users_with_array_input({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Creates list of users with given input array
|
||||
fn create_users_with_list_input(
|
||||
async fn create_users_with_list_input(
|
||||
&self,
|
||||
body: &Vec<models::User>,
|
||||
context: &C) -> Box<dyn Future<Item=CreateUsersWithListInputResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<CreateUsersWithListInputResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("create_users_with_list_input({:?}) - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Delete user
|
||||
fn delete_user(
|
||||
async fn delete_user(
|
||||
&self,
|
||||
username: String,
|
||||
context: &C) -> Box<dyn Future<Item=DeleteUserResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<DeleteUserResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("delete_user(\"{}\") - X-Span-ID: {:?}", username, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Get user by user name
|
||||
fn get_user_by_name(
|
||||
async fn get_user_by_name(
|
||||
&self,
|
||||
username: String,
|
||||
context: &C) -> Box<dyn Future<Item=GetUserByNameResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<GetUserByNameResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("get_user_by_name(\"{}\") - X-Span-ID: {:?}", username, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Logs user into the system
|
||||
fn login_user(
|
||||
async fn login_user(
|
||||
&self,
|
||||
username: String,
|
||||
password: String,
|
||||
context: &C) -> Box<dyn Future<Item=LoginUserResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<LoginUserResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("login_user(\"{}\", \"{}\") - X-Span-ID: {:?}", username, password, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Logs out current logged in user session
|
||||
fn logout_user(
|
||||
async fn logout_user(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=LogoutUserResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<LogoutUserResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("logout_user() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Updated user
|
||||
fn update_user(
|
||||
async fn update_user(
|
||||
&self,
|
||||
username: String,
|
||||
body: models::User,
|
||||
context: &C) -> Box<dyn Future<Item=UpdateUserResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<UpdateUserResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("update_user(\"{}\", {:?}) - X-Span-ID: {:?}", username, body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,24 +83,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
{
|
||||
use swagger::auth::api_key_from_header;
|
||||
@@ -117,16 +112,11 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{
|
||||
let key = form_urlencoded::parse(head.uri.query().unwrap_or_default().as_bytes())
|
||||
let key = form_urlencoded::parse(request.uri().query().unwrap_or_default().as_bytes())
|
||||
.filter(|e| e.0 == "api_key_query")
|
||||
.map(|e| e.1.clone().into_owned())
|
||||
.nth(0);
|
||||
@@ -135,11 +125,7 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -150,12 +136,7 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -166,22 +147,13 @@ impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
let context = context.push(Some(auth_data));
|
||||
let context = context.push(None::<Authorization>);
|
||||
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
return Box::new(self.inner.call(hyper::Request::from_parts(head, body)));
|
||||
return self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ edition = "2018"
|
||||
[features]
|
||||
default = ["client", "server"]
|
||||
client = [
|
||||
"hyper", "hyper-openssl", "native-tls", "openssl", "url"
|
||||
"hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
|
||||
]
|
||||
server = [
|
||||
"serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static"
|
||||
@@ -18,35 +18,37 @@ conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
|
||||
hyper-openssl = { version = "0.7.1", optional = true }
|
||||
hyper-openssl = { version = "0.8", optional = true }
|
||||
openssl = {version = "0.10", optional = true }
|
||||
|
||||
[dependencies]
|
||||
# Common
|
||||
async-trait = "0.1.24"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures = "0.1"
|
||||
swagger = "4.0"
|
||||
futures = "0.3"
|
||||
swagger = "5.0.0-alpha-1"
|
||||
log = "0.4.0"
|
||||
mime = "0.3"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Crates included if required by the API definition
|
||||
|
||||
# Common between server and client features
|
||||
hyper = {version = "0.12", optional = true}
|
||||
serde_ignored = {version = "0.0.4", optional = true}
|
||||
url = {version = "1.5", optional = true}
|
||||
hyper = {version = "0.13", optional = true}
|
||||
serde_ignored = {version = "0.1.1", optional = true}
|
||||
url = {version = "2.1", optional = true}
|
||||
|
||||
# Client-specific
|
||||
|
||||
# Server, and client callback-specific
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
percent-encoding = {version = "1.0.0", optional = true}
|
||||
regex = {version = "0.2", optional = true}
|
||||
percent-encoding = {version = "2.1.0", optional = true}
|
||||
regex = {version = "1.3", optional = true}
|
||||
|
||||
# Conversion
|
||||
frunk = { version = "0.3.0", optional = true }
|
||||
@@ -57,13 +59,13 @@ frunk-enum-core = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = "2.25"
|
||||
error-chain = "0.12"
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
uuid = {version = "0.7", features = ["serde", "v4"]}
|
||||
env_logger = "0.7"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "macros", "stream"] }
|
||||
native-tls = "0.2"
|
||||
tokio-tls = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
|
||||
tokio-openssl = "0.3"
|
||||
tokio-openssl = "0.4"
|
||||
openssl = "0.10"
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use futures::{future, Stream, stream};
|
||||
#[allow(unused_imports)]
|
||||
use rust_server_test::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
ApiError,
|
||||
AllOfGetResponse,
|
||||
DummyGetResponse,
|
||||
DummyPutResponse,
|
||||
@@ -14,7 +13,7 @@ use rust_server_test::{Api, ApiNoContext, Client, ContextWrapperExt, models,
|
||||
HtmlPostResponse,
|
||||
PostYamlResponse,
|
||||
RawJsonGetResponse,
|
||||
SoloObjectPostResponse
|
||||
SoloObjectPostResponse,
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
|
||||
@@ -23,7 +22,9 @@ use log::info;
|
||||
|
||||
// swagger::Has may be unused if there are no examples
|
||||
#[allow(unused_imports)]
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
use swagger::{AuthData, ContextBuilder, EmptyContext, Has, Push, XSpanIdString};
|
||||
|
||||
type ClientContext = swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString);
|
||||
|
||||
// rt may be unused if there are no examples
|
||||
#[allow(unused_mut)]
|
||||
@@ -65,21 +66,21 @@ fn main() {
|
||||
matches.value_of("host").unwrap(),
|
||||
matches.value_of("port").unwrap());
|
||||
|
||||
let client = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client")
|
||||
} else {
|
||||
// Using HTTP
|
||||
Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client")
|
||||
};
|
||||
|
||||
let context: swagger::make_context_ty!(ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString) =
|
||||
let context: ClientContext =
|
||||
swagger::make_context!(ContextBuilder, EmptyContext, None as Option<AuthData>, XSpanIdString::default());
|
||||
|
||||
let client = client.with_context(context);
|
||||
let mut client : Box<dyn ApiNoContext<ClientContext>> = if matches.is_present("https") {
|
||||
// Using Simple HTTPS
|
||||
let client = Box::new(Client::try_new_https(&base_url)
|
||||
.expect("Failed to create HTTPS client"));
|
||||
Box::new(client.with_context(context))
|
||||
} else {
|
||||
// Using HTTP
|
||||
let client = Box::new(Client::try_new_http(
|
||||
&base_url)
|
||||
.expect("Failed to create HTTP client"));
|
||||
Box::new(client.with_context(context))
|
||||
};
|
||||
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ mod server;
|
||||
|
||||
/// Create custom server, wire it to the autogenerated router,
|
||||
/// and pass it to the web server.
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let matches = App::new("server")
|
||||
@@ -20,5 +21,5 @@ fn main() {
|
||||
|
||||
let addr = "127.0.0.1:8080";
|
||||
|
||||
hyper::rt::run(server::create(addr, matches.is_present("https")));
|
||||
server::create(addr, matches.is_present("https")).await;
|
||||
}
|
||||
|
||||
@@ -2,30 +2,22 @@
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod errors {
|
||||
error_chain::error_chain!{}
|
||||
}
|
||||
|
||||
pub use self::errors::*;
|
||||
|
||||
use chrono;
|
||||
use futures::{future, Future, Stream};
|
||||
use async_trait::async_trait;
|
||||
use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::MakeService as _;
|
||||
use hyper::service::Service;
|
||||
use log::info;
|
||||
use openssl::ssl::SslAcceptorBuilder;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use swagger;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{Has, XSpanIdString};
|
||||
use swagger::auth::MakeAllowAllAuthenticator;
|
||||
use swagger::EmptyContext;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
@@ -33,18 +25,18 @@ use rust_server_test::models;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
|
||||
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
|
||||
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
|
||||
pub async fn create(addr: &str, https: bool) {
|
||||
let addr = addr.parse().expect("Failed to parse bind address");
|
||||
|
||||
let server = Server::new();
|
||||
|
||||
let service_fn = MakeService::new(server);
|
||||
let service = MakeService::new(server);
|
||||
|
||||
let service_fn = MakeAllowAllAuthenticator::new(service_fn, "cosmo");
|
||||
let service = MakeAllowAllAuthenticator::new(service, "cosmo");
|
||||
|
||||
let service_fn =
|
||||
let mut service =
|
||||
rust_server_test::server::context::MakeAddContext::<_, EmptyContext>::new(
|
||||
service_fn
|
||||
service
|
||||
);
|
||||
|
||||
if https {
|
||||
@@ -62,32 +54,31 @@ pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()>
|
||||
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
|
||||
ssl.check_private_key().expect("Failed to check private key");
|
||||
|
||||
let tls_acceptor = ssl.build();
|
||||
let service_fn = Arc::new(Mutex::new(service_fn));
|
||||
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let tls_acceptor = Arc::new(ssl.build());
|
||||
let mut tcp_listener = TcpListener::bind(&addr).await.unwrap();
|
||||
let mut incoming = tcp_listener.incoming();
|
||||
|
||||
let service_fn = service_fn.clone();
|
||||
while let (Some(tcp), rest) = incoming.into_future().await {
|
||||
if let Ok(tcp) = tcp {
|
||||
let addr = tcp.peer_addr().expect("Unable to get remote address");
|
||||
let service = service.call(addr);
|
||||
let tls_acceptor = Arc::clone(&tls_acceptor);
|
||||
|
||||
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
|
||||
let ms = {
|
||||
let mut service_fn = service_fn.lock().unwrap();
|
||||
service_fn.make_service(&addr)
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let tls = tokio_openssl::accept(&*tls_acceptor, tcp).await.map_err(|_| ())?;
|
||||
|
||||
ms.and_then(move |service| {
|
||||
Http::new().serve_connection(tls, service)
|
||||
}).map_err(|_| ())
|
||||
}));
|
||||
let service = service.await.map_err(|_| ())?;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|_| ());
|
||||
Http::new().serve_connection(tls, service).await.map_err(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(tls_listener)
|
||||
incoming = rest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using HTTP
|
||||
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
|
||||
hyper::server::Server::bind(&addr).serve(service).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +96,6 @@ impl<C> Server<C> {
|
||||
|
||||
use rust_server_test::{
|
||||
Api,
|
||||
ApiError,
|
||||
AllOfGetResponse,
|
||||
DummyGetResponse,
|
||||
DummyPutResponse,
|
||||
@@ -117,96 +107,100 @@ use rust_server_test::{
|
||||
SoloObjectPostResponse,
|
||||
};
|
||||
use rust_server_test::server::MakeService;
|
||||
use std::error::Error;
|
||||
use swagger::ApiError;
|
||||
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
fn all_of_get(
|
||||
#[async_trait]
|
||||
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString> + Send + Sync
|
||||
{
|
||||
async fn all_of_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=AllOfGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<AllOfGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("all_of_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// A dummy endpoint to make the spec valid.
|
||||
fn dummy_get(
|
||||
async fn dummy_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=DummyGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<DummyGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("dummy_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn dummy_put(
|
||||
async fn dummy_put(
|
||||
&self,
|
||||
nested_response: models::InlineObject,
|
||||
context: &C) -> Box<dyn Future<Item=DummyPutResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<DummyPutResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("dummy_put({:?}) - X-Span-ID: {:?}", nested_response, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Get a file
|
||||
fn file_response_get(
|
||||
async fn file_response_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=FileResponseGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<FileResponseGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("file_response_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn get_structured_yaml(
|
||||
async fn get_structured_yaml(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=GetStructuredYamlResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<GetStructuredYamlResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("get_structured_yaml() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Test HTML handling
|
||||
fn html_post(
|
||||
async fn html_post(
|
||||
&self,
|
||||
body: String,
|
||||
context: &C) -> Box<dyn Future<Item=HtmlPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<HtmlPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("html_post(\"{}\") - X-Span-ID: {:?}", body, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
fn post_yaml(
|
||||
async fn post_yaml(
|
||||
&self,
|
||||
value: String,
|
||||
context: &C) -> Box<dyn Future<Item=PostYamlResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<PostYamlResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("post_yaml(\"{}\") - X-Span-ID: {:?}", value, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Get an arbitrary JSON blob.
|
||||
fn raw_json_get(
|
||||
async fn raw_json_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=RawJsonGetResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<RawJsonGetResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("raw_json_get() - X-Span-ID: {:?}", context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
/// Send an arbitrary JSON blob
|
||||
fn solo_object_post(
|
||||
async fn solo_object_post(
|
||||
&self,
|
||||
value: serde_json::Value,
|
||||
context: &C) -> Box<dyn Future<Item=SoloObjectPostResponse, Error=ApiError> + Send>
|
||||
context: &C) -> Result<SoloObjectPostResponse, ApiError>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("solo_object_post({:?}) - X-Span-ID: {:?}", value, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
Err("Generic failuare".into())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
use futures::Future;
|
||||
use hyper;
|
||||
use futures::future::BoxFuture;
|
||||
use hyper::header::HeaderName;
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service, body::Payload};
|
||||
use hyper::{Error, Request, Response, StatusCode, service::Service};
|
||||
use url::form_urlencoded;
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::auth::{AuthData, Authorization, Bearer, Scopes};
|
||||
use swagger::context::ContextualPayload;
|
||||
use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString};
|
||||
use crate::Api;
|
||||
|
||||
@@ -31,58 +30,52 @@ where
|
||||
}
|
||||
|
||||
// Make a service that adds context.
|
||||
impl<'a, T, SC, A, B, C, D, E, ME, S, OB, F> hyper::service::MakeService<&'a SC> for
|
||||
impl<Target, T, A, B, C, D> Service<Target> for
|
||||
MakeAddContext<T, A>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
Target: Send,
|
||||
A: Default + Push<XSpanIdString, Result = B> + Send,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
D: Send + 'static,
|
||||
T: hyper::service::MakeService<
|
||||
&'a SC,
|
||||
Error = E,
|
||||
MakeError = ME,
|
||||
Service = S,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB,
|
||||
Future = F
|
||||
>,
|
||||
S: Service<
|
||||
Error = E,
|
||||
ReqBody = ContextualPayload<hyper::Body, D>,
|
||||
ResBody = OB> + 'static,
|
||||
ME: swagger::ErrorBound,
|
||||
E: swagger::ErrorBound,
|
||||
F: Future<Item=S, Error=ME> + Send + 'static,
|
||||
S::Future: Send,
|
||||
OB: Payload,
|
||||
T: Service<Target> + Send,
|
||||
T::Future: Send + 'static
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = OB;
|
||||
type Error = E;
|
||||
type MakeError = ME;
|
||||
type Service = AddContext<S, A>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = ME> + Send + 'static>;
|
||||
type Error = T::Error;
|
||||
type Response = AddContext<T::Response, A, B, C, D>;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, ctx: &'a SC) -> Self::Future {
|
||||
Box::new(self.inner.make_service(ctx).map(|s| AddContext::new(s)))
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
let service = self.inner.call(target);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(AddContext::new(service.await?))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware to extract authentication data from request
|
||||
pub struct AddContext<T, A> {
|
||||
/// Middleware to add context data from the request
|
||||
pub struct AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>
|
||||
{
|
||||
inner: T,
|
||||
marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> AddContext<T, A>
|
||||
impl<T, A, B, C, D> AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result = B>,
|
||||
B: Push<Option<AuthData>, Result = C>,
|
||||
C: Push<Option<Authorization>, Result = D>,
|
||||
T: Service,
|
||||
{
|
||||
pub fn new(inner: T) -> AddContext<T, A> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
AddContext {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
@@ -90,33 +83,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B, C, D> Service for AddContext<T, A>
|
||||
impl<T, A, B, C, D, ReqBody> Service<Request<ReqBody>> for AddContext<T, A, B, C, D>
|
||||
where
|
||||
A: Default + Push<XSpanIdString, Result=B>,
|
||||
B: Push<Option<AuthData>, Result=C>,
|
||||
C: Push<Option<Authorization>, Result=D>,
|
||||
D: Send + 'static,
|
||||
T: Service<ReqBody = ContextualPayload<hyper::Body, D>>,
|
||||
T::Future: Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static
|
||||
T: Service<(Request<ReqBody>, D)>
|
||||
{
|
||||
type ReqBody = hyper::Body;
|
||||
type ResBody = T::ResBody;
|
||||
type Error = T::Error;
|
||||
type Future = Box<dyn Future<Item=Response<T::ResBody>, Error=T::Error> + Send + 'static>;
|
||||
type Future = T::Future;
|
||||
type Response = T::Response;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&req));
|
||||
let (head, body) = req.into_parts();
|
||||
let headers = head.headers.clone();
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.inner.poll_ready(cx)
|
||||
}
|
||||
|
||||
|
||||
fn call(&mut self, request: Request<ReqBody>) -> Self::Future {
|
||||
let context = A::default().push(XSpanIdString::get_or_generate(&request));
|
||||
let headers = request.headers();
|
||||
|
||||
|
||||
let context = context.push(None::<AuthData>);
|
||||
let context = context.push(None::<Authorization>);
|
||||
let body = ContextualPayload {
|
||||
inner: body,
|
||||
context: context,
|
||||
};
|
||||
|
||||
Box::new(self.inner.call(hyper::Request::from_parts(head, body)))
|
||||
self.inner.call((request, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::Stream;
|
||||
use std::io::Error;
|
||||
use std::error::Error;
|
||||
use std::task::{Poll, Context};
|
||||
use swagger::{ApiError, ContextWrapper};
|
||||
|
||||
#[deprecated(note = "Import swagger-rs directly")]
|
||||
pub use swagger::{ApiError, ContextWrapper};
|
||||
#[deprecated(note = "Import futures directly")]
|
||||
pub use futures::Future;
|
||||
type ServiceError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub const BASE_PATH: &'static str = "";
|
||||
pub const API_VERSION: &'static str = "2.3.4";
|
||||
@@ -71,190 +71,221 @@ pub enum SoloObjectPostResponse {
|
||||
}
|
||||
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
fn all_of_get(
|
||||
#[async_trait]
|
||||
pub trait Api<C: Send + Sync> {
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
async fn all_of_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=AllOfGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<AllOfGetResponse, ApiError>;
|
||||
|
||||
/// A dummy endpoint to make the spec valid.
|
||||
fn dummy_get(
|
||||
async fn dummy_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=DummyGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<DummyGetResponse, ApiError>;
|
||||
|
||||
fn dummy_put(
|
||||
async fn dummy_put(
|
||||
&self,
|
||||
nested_response: models::InlineObject,
|
||||
context: &C) -> Box<dyn Future<Item=DummyPutResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<DummyPutResponse, ApiError>;
|
||||
|
||||
/// Get a file
|
||||
fn file_response_get(
|
||||
async fn file_response_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=FileResponseGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<FileResponseGetResponse, ApiError>;
|
||||
|
||||
fn get_structured_yaml(
|
||||
async fn get_structured_yaml(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=GetStructuredYamlResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<GetStructuredYamlResponse, ApiError>;
|
||||
|
||||
/// Test HTML handling
|
||||
fn html_post(
|
||||
async fn html_post(
|
||||
&self,
|
||||
body: String,
|
||||
context: &C) -> Box<dyn Future<Item=HtmlPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<HtmlPostResponse, ApiError>;
|
||||
|
||||
fn post_yaml(
|
||||
async fn post_yaml(
|
||||
&self,
|
||||
value: String,
|
||||
context: &C) -> Box<dyn Future<Item=PostYamlResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<PostYamlResponse, ApiError>;
|
||||
|
||||
/// Get an arbitrary JSON blob.
|
||||
fn raw_json_get(
|
||||
async fn raw_json_get(
|
||||
&self,
|
||||
context: &C) -> Box<dyn Future<Item=RawJsonGetResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<RawJsonGetResponse, ApiError>;
|
||||
|
||||
/// Send an arbitrary JSON blob
|
||||
fn solo_object_post(
|
||||
async fn solo_object_post(
|
||||
&self,
|
||||
value: serde_json::Value,
|
||||
context: &C) -> Box<dyn Future<Item=SoloObjectPostResponse, Error=ApiError> + Send>;
|
||||
context: &C) -> Result<SoloObjectPostResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
pub trait ApiNoContext {
|
||||
fn all_of_get(
|
||||
/// API where `Context` isn't passed on every API call
|
||||
#[async_trait]
|
||||
pub trait ApiNoContext<C: Send + Sync> {
|
||||
|
||||
fn poll_ready(&self, _cx: &mut Context) -> Poll<Result<(), Box<dyn Error + Send + Sync + 'static>>>;
|
||||
|
||||
fn context(&self) -> &C;
|
||||
|
||||
async fn all_of_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=AllOfGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<AllOfGetResponse, ApiError>;
|
||||
|
||||
/// A dummy endpoint to make the spec valid.
|
||||
fn dummy_get(
|
||||
async fn dummy_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=DummyGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<DummyGetResponse, ApiError>;
|
||||
|
||||
fn dummy_put(
|
||||
async fn dummy_put(
|
||||
&self,
|
||||
nested_response: models::InlineObject,
|
||||
) -> Box<dyn Future<Item=DummyPutResponse, Error=ApiError> + Send>;
|
||||
) -> Result<DummyPutResponse, ApiError>;
|
||||
|
||||
/// Get a file
|
||||
fn file_response_get(
|
||||
async fn file_response_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=FileResponseGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<FileResponseGetResponse, ApiError>;
|
||||
|
||||
fn get_structured_yaml(
|
||||
async fn get_structured_yaml(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=GetStructuredYamlResponse, Error=ApiError> + Send>;
|
||||
) -> Result<GetStructuredYamlResponse, ApiError>;
|
||||
|
||||
/// Test HTML handling
|
||||
fn html_post(
|
||||
async fn html_post(
|
||||
&self,
|
||||
body: String,
|
||||
) -> Box<dyn Future<Item=HtmlPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<HtmlPostResponse, ApiError>;
|
||||
|
||||
fn post_yaml(
|
||||
async fn post_yaml(
|
||||
&self,
|
||||
value: String,
|
||||
) -> Box<dyn Future<Item=PostYamlResponse, Error=ApiError> + Send>;
|
||||
) -> Result<PostYamlResponse, ApiError>;
|
||||
|
||||
/// Get an arbitrary JSON blob.
|
||||
fn raw_json_get(
|
||||
async fn raw_json_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=RawJsonGetResponse, Error=ApiError> + Send>;
|
||||
) -> Result<RawJsonGetResponse, ApiError>;
|
||||
|
||||
/// Send an arbitrary JSON blob
|
||||
fn solo_object_post(
|
||||
async fn solo_object_post(
|
||||
&self,
|
||||
value: serde_json::Value,
|
||||
) -> Box<dyn Future<Item=SoloObjectPostResponse, Error=ApiError> + Send>;
|
||||
) -> Result<SoloObjectPostResponse, ApiError>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
pub trait ContextWrapperExt<'a, C> where Self: Sized {
|
||||
pub trait ContextWrapperExt<C: Send + Sync> where Self: Sized
|
||||
{
|
||||
/// Binds this API to a context.
|
||||
fn with_context(self: &'a Self, context: C) -> ContextWrapper<'a, Self, C>;
|
||||
fn with_context(self: Self, context: C) -> ContextWrapper<Self, C>;
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
|
||||
fn with_context(self: &'a T, context: C) -> ContextWrapper<'a, T, C> {
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt<C> for T {
|
||||
fn with_context(self: T, context: C) -> ContextWrapper<T, C> {
|
||||
ContextWrapper::<T, C>::new(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
fn all_of_get(
|
||||
#[async_trait]
|
||||
impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for ContextWrapper<T, C> {
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), ServiceError>> {
|
||||
self.api().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn context(&self) -> &C {
|
||||
ContextWrapper::context(self)
|
||||
}
|
||||
|
||||
async fn all_of_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=AllOfGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<AllOfGetResponse, ApiError>
|
||||
{
|
||||
self.api().all_of_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().all_of_get(&context).await
|
||||
}
|
||||
|
||||
/// A dummy endpoint to make the spec valid.
|
||||
fn dummy_get(
|
||||
async fn dummy_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=DummyGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<DummyGetResponse, ApiError>
|
||||
{
|
||||
self.api().dummy_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().dummy_get(&context).await
|
||||
}
|
||||
|
||||
fn dummy_put(
|
||||
async fn dummy_put(
|
||||
&self,
|
||||
nested_response: models::InlineObject,
|
||||
) -> Box<dyn Future<Item=DummyPutResponse, Error=ApiError> + Send>
|
||||
) -> Result<DummyPutResponse, ApiError>
|
||||
{
|
||||
self.api().dummy_put(nested_response, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().dummy_put(nested_response, &context).await
|
||||
}
|
||||
|
||||
/// Get a file
|
||||
fn file_response_get(
|
||||
async fn file_response_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=FileResponseGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<FileResponseGetResponse, ApiError>
|
||||
{
|
||||
self.api().file_response_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().file_response_get(&context).await
|
||||
}
|
||||
|
||||
fn get_structured_yaml(
|
||||
async fn get_structured_yaml(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=GetStructuredYamlResponse, Error=ApiError> + Send>
|
||||
) -> Result<GetStructuredYamlResponse, ApiError>
|
||||
{
|
||||
self.api().get_structured_yaml(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().get_structured_yaml(&context).await
|
||||
}
|
||||
|
||||
/// Test HTML handling
|
||||
fn html_post(
|
||||
async fn html_post(
|
||||
&self,
|
||||
body: String,
|
||||
) -> Box<dyn Future<Item=HtmlPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<HtmlPostResponse, ApiError>
|
||||
{
|
||||
self.api().html_post(body, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().html_post(body, &context).await
|
||||
}
|
||||
|
||||
fn post_yaml(
|
||||
async fn post_yaml(
|
||||
&self,
|
||||
value: String,
|
||||
) -> Box<dyn Future<Item=PostYamlResponse, Error=ApiError> + Send>
|
||||
) -> Result<PostYamlResponse, ApiError>
|
||||
{
|
||||
self.api().post_yaml(value, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().post_yaml(value, &context).await
|
||||
}
|
||||
|
||||
/// Get an arbitrary JSON blob.
|
||||
fn raw_json_get(
|
||||
async fn raw_json_get(
|
||||
&self,
|
||||
) -> Box<dyn Future<Item=RawJsonGetResponse, Error=ApiError> + Send>
|
||||
) -> Result<RawJsonGetResponse, ApiError>
|
||||
{
|
||||
self.api().raw_json_get(&self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().raw_json_get(&context).await
|
||||
}
|
||||
|
||||
/// Send an arbitrary JSON blob
|
||||
fn solo_object_post(
|
||||
async fn solo_object_post(
|
||||
&self,
|
||||
value: serde_json::Value,
|
||||
) -> Box<dyn Future<Item=SoloObjectPostResponse, Error=ApiError> + Send>
|
||||
) -> Result<SoloObjectPostResponse, ApiError>
|
||||
{
|
||||
self.api().solo_object_post(value, &self.context())
|
||||
let context = self.context().clone();
|
||||
self.api().solo_object_post(value, &context).await
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub mod client;
|
||||
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
use std::marker::PhantomData;
|
||||
use futures::{Future, future, Stream, stream};
|
||||
use hyper;
|
||||
use hyper::{Request, Response, Error, StatusCode, Body, HeaderMap};
|
||||
use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt};
|
||||
use hyper::{Request, Response, StatusCode, Body, HeaderMap};
|
||||
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||
use log::warn;
|
||||
use serde_json;
|
||||
#[allow(unused_imports)]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io;
|
||||
use url::form_urlencoded;
|
||||
#[allow(unused_imports)]
|
||||
use swagger;
|
||||
use swagger::{ApiError, XSpanIdString, Has, RequestParser};
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::task::{Context, Poll};
|
||||
use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString};
|
||||
pub use swagger::auth::Authorization;
|
||||
use swagger::auth::Scopes;
|
||||
use swagger::context::ContextualPayload;
|
||||
use url::form_urlencoded;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::models;
|
||||
@@ -22,6 +19,8 @@ use crate::header;
|
||||
|
||||
pub use crate::context;
|
||||
|
||||
type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
|
||||
|
||||
use crate::{Api,
|
||||
AllOfGetResponse,
|
||||
DummyGetResponse,
|
||||
@@ -60,15 +59,17 @@ mod paths {
|
||||
pub(crate) static ID_SOLO_OBJECT: usize = 7;
|
||||
}
|
||||
|
||||
pub struct MakeService<T, RC> {
|
||||
pub struct MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static
|
||||
impl<T, C> MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
MakeService {
|
||||
@@ -78,44 +79,45 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, SC, RC> hyper::service::MakeService<&'a SC> for MakeService<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static + Send
|
||||
impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, RC>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
type Service = Service<T, RC>;
|
||||
type Future = future::FutureResult<Self::Service, Self::MakeError>;
|
||||
type MakeError = Error;
|
||||
type Response = Service<T, C>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn make_service(&mut self, _ctx: &'a SC) -> Self::Future {
|
||||
future::FutureResult::from(Ok(Service::new(
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, target: Target) -> Self::Future {
|
||||
futures::future::ok(Service::new(
|
||||
self.api_impl.clone(),
|
||||
)))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
type ServiceFuture = Box<dyn Future<Item = Response<Body>, Error = Error> + Send>;
|
||||
|
||||
fn method_not_allowed() -> ServiceFuture {
|
||||
Box::new(future::ok(
|
||||
fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
|
||||
Ok(
|
||||
Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Method Not Allowed response")
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Service<T, RC> {
|
||||
pub struct Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
api_impl: T,
|
||||
marker: PhantomData<RC>,
|
||||
marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<T, RC> Service<T, RC>
|
||||
where
|
||||
T: Api<RC> + Clone + Send + 'static,
|
||||
RC: Has<XSpanIdString> + 'static {
|
||||
impl<T, C> Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
pub fn new(api_impl: T) -> Self {
|
||||
Service {
|
||||
api_impl: api_impl,
|
||||
@@ -124,36 +126,48 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service for Service<T, C>
|
||||
where
|
||||
impl<T, C> Clone for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + 'static + Send
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type ReqBody = ContextualPayload<Body, C>;
|
||||
type ResBody = Body;
|
||||
type Error = Error;
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
|
||||
T: Api<C> + Clone + Send + Sync + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
type Response = Response<Body>;
|
||||
type Error = crate::ServiceError;
|
||||
type Future = ServiceFuture;
|
||||
|
||||
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
|
||||
let api_impl = self.api_impl.clone();
|
||||
let (parts, body) = req.into_parts();
|
||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.api_impl.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
|
||||
T: Api<C> + Clone + Send + 'static,
|
||||
C: Has<XSpanIdString> + Send + Sync + 'static
|
||||
{
|
||||
let (request, context) = req;
|
||||
let (parts, body) = request.into_parts();
|
||||
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
|
||||
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
|
||||
let mut context = body.context;
|
||||
let body = body.inner;
|
||||
|
||||
match &method {
|
||||
|
||||
// AllOfGet - GET /allOf
|
||||
&hyper::Method::GET if path.matched(paths::ID_ALLOF) => {
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.all_of_get(
|
||||
let result = api_impl.all_of_get(
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -180,23 +194,16 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
// DummyGet - GET /dummy
|
||||
&hyper::Method::GET if path.matched(paths::ID_DUMMY) => {
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.dummy_get(
|
||||
let result = api_impl.dummy_get(
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -216,11 +223,7 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
// DummyPut - PUT /dummy
|
||||
@@ -228,9 +231,8 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw().await;
|
||||
match result {
|
||||
Ok(body) => {
|
||||
let mut unused_elements = Vec::new();
|
||||
let param_nested_response: Option<models::InlineObject> = if !body.is_empty() {
|
||||
@@ -240,29 +242,28 @@ where
|
||||
unused_elements.push(path.to_string());
|
||||
}) {
|
||||
Ok(param_nested_response) => param_nested_response,
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter nested_response - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter nested_response due to schema"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter nested_response due to schema")),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let param_nested_response = match param_nested_response {
|
||||
Some(param_nested_response) => param_nested_response,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required body parameter nested_response"))
|
||||
.expect("Unable to create Bad Request response for missing body parameter nested_response"))),
|
||||
.expect("Unable to create Bad Request response for missing body parameter nested_response")),
|
||||
};
|
||||
|
||||
Box::new(
|
||||
api_impl.dummy_put(
|
||||
let result = api_impl.dummy_put(
|
||||
param_nested_response,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -289,29 +290,22 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter nested_response: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter nested_response"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter nested_response")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
// FileResponseGet - GET /file_response
|
||||
&hyper::Method::GET if path.matched(paths::ID_FILE_RESPONSE) => {
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.file_response_get(
|
||||
let result = api_impl.file_response_get(
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -338,23 +332,16 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
// GetStructuredYaml - GET /get-structured-yaml
|
||||
&hyper::Method::GET if path.matched(paths::ID_GET_STRUCTURED_YAML) => {
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.get_structured_yaml(
|
||||
let result = api_impl.get_structured_yaml(
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -381,11 +368,7 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
// HtmlPost - POST /html
|
||||
@@ -393,36 +376,34 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw().await;
|
||||
match result {
|
||||
Ok(body) => {
|
||||
let param_body: Option<String> = if !body.is_empty() {
|
||||
match String::from_utf8(body.to_vec()) {
|
||||
Ok(param_body) => Some(param_body),
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter body - not valid UTF-8: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter body due to UTF-8"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter body due to UTF-8")),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let param_body = match param_body {
|
||||
Some(param_body) => param_body,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required body parameter body"))
|
||||
.expect("Unable to create Bad Request response for missing body parameter body"))),
|
||||
.expect("Unable to create Bad Request response for missing body parameter body")),
|
||||
};
|
||||
|
||||
Box::new(
|
||||
api_impl.html_post(
|
||||
let result = api_impl.html_post(
|
||||
param_body,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -449,17 +430,13 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter body: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter body"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter body")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
// PostYaml - POST /post-yaml
|
||||
@@ -467,36 +444,34 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw().await;
|
||||
match result {
|
||||
Ok(body) => {
|
||||
let param_value: Option<String> = if !body.is_empty() {
|
||||
match String::from_utf8(body.to_vec()) {
|
||||
Ok(param_value) => Some(param_value),
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter value - not valid UTF-8: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter value due to UTF-8"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter value due to UTF-8")),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let param_value = match param_value {
|
||||
Some(param_value) => param_value,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required body parameter value"))
|
||||
.expect("Unable to create Bad Request response for missing body parameter value"))),
|
||||
.expect("Unable to create Bad Request response for missing body parameter value")),
|
||||
};
|
||||
|
||||
Box::new(
|
||||
api_impl.post_yaml(
|
||||
let result = api_impl.post_yaml(
|
||||
param_value,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -516,29 +491,22 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter value: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter value"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter value")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
// RawJsonGet - GET /raw_json
|
||||
&hyper::Method::GET if path.matched(paths::ID_RAW_JSON) => {
|
||||
Box::new({
|
||||
{{
|
||||
Box::new(
|
||||
api_impl.raw_json_get(
|
||||
let result = api_impl.raw_json_get(
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -565,11 +533,7 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
}}
|
||||
}) as Self::Future
|
||||
Ok(response)
|
||||
},
|
||||
|
||||
// SoloObjectPost - POST /solo-object
|
||||
@@ -577,9 +541,8 @@ where
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
let result = body.to_raw().await;
|
||||
match result {
|
||||
Ok(body) => {
|
||||
let mut unused_elements = Vec::new();
|
||||
let param_value: Option<serde_json::Value> = if !body.is_empty() {
|
||||
@@ -589,29 +552,28 @@ where
|
||||
unused_elements.push(path.to_string());
|
||||
}) {
|
||||
Ok(param_value) => param_value,
|
||||
Err(e) => return Box::new(future::ok(Response::builder()
|
||||
Err(e) => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't parse body parameter value - doesn't match schema: {}", e)))
|
||||
.expect("Unable to create Bad Request response for invalid body parameter value due to schema"))),
|
||||
.expect("Unable to create Bad Request response for invalid body parameter value due to schema")),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let param_value = match param_value {
|
||||
Some(param_value) => param_value,
|
||||
None => return Box::new(future::ok(Response::builder()
|
||||
None => return Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from("Missing required body parameter value"))
|
||||
.expect("Unable to create Bad Request response for missing body parameter value"))),
|
||||
.expect("Unable to create Bad Request response for missing body parameter value")),
|
||||
};
|
||||
|
||||
Box::new(
|
||||
api_impl.solo_object_post(
|
||||
let result = api_impl.solo_object_post(
|
||||
param_value,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
).await;
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
@@ -638,17 +600,13 @@ where
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
Ok(response)
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
Err(e) => Ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter value: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter value"))),
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter value")),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
_ if path.matched(paths::ID_ALLOF) => method_not_allowed(),
|
||||
@@ -659,23 +617,11 @@ where
|
||||
_ if path.matched(paths::ID_POST_YAML) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_RAW_JSON) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_SOLO_OBJECT) => method_not_allowed(),
|
||||
_ => Box::new(future::ok(
|
||||
Response::builder().status(StatusCode::NOT_FOUND)
|
||||
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
|
||||
.body(Body::empty())
|
||||
.expect("Unable to create Not Found response")
|
||||
)) as Self::Future
|
||||
.expect("Unable to create Not Found response"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> Clone for Service<T, C> where T: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Service {
|
||||
api_impl: self.api_impl.clone(),
|
||||
marker: self.marker.clone(),
|
||||
}
|
||||
}
|
||||
} Box::pin(run(self.api_impl.clone(), req)) }
|
||||
}
|
||||
|
||||
/// Request parser for `Api`.
|
||||
|
||||
Reference in New Issue
Block a user