Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rust-server] Drop file support #547

Merged
merged 2 commits into from
Jul 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ public RustServerCodegen() {
typeMapping.put("date", "chrono::DateTime<chrono::Utc>");
typeMapping.put("DateTime", "chrono::DateTime<chrono::Utc>");
typeMapping.put("password", "String");
typeMapping.put("File", "Box<Stream<Item=Vec<u8>, Error=Error> + Send>");
typeMapping.put("file", "Box<Stream<Item=Vec<u8>, Error=Error> + Send>");
typeMapping.put("File", "swagger::ByteArray");
typeMapping.put("file", "swagger::ByteArray");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For other generators, we're also mapping file and binary to the same type.

typeMapping.put("array", "Vec");
typeMapping.put("map", "HashMap");

Expand Down Expand Up @@ -710,8 +710,6 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
}
header.nameInCamelCase = toModelName(header.baseName);
}

additionalProperties.put("apiHasFile", true);
}

return objs;
Expand Down Expand Up @@ -1069,22 +1067,11 @@ private boolean paramHasXmlNamespace(CodegenParameter param, Map<String, Schema>
private void processParam(CodegenParameter param, CodegenOperation op) {
String example = null;

if (param.isFile) {
param.vendorExtensions.put("formatString", "{:?}");
op.vendorExtensions.put("hasFile", true);
additionalProperties.put("apiHasFile", true);
example = "Box::new(stream::once(Ok(b\"hello\".to_vec()))) as Box<Stream<Item=_, Error=_> + Send>";
} else if (param.isString) {
if (param.dataFormat != null && param.dataFormat.equals("byte")) {
param.vendorExtensions.put("formatString", "\\\"{:?}\\\"");
example = "swagger::ByteArray(\"" + ((param.example != null) ? param.example : "") + "\".to_string().into_bytes())";
} else {
param.vendorExtensions.put("formatString", "\\\"{}\\\"");
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";
}
if (param.isString) {
param.vendorExtensions.put("formatString", "\\\"{}\\\"");
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";
} else if (param.isPrimitiveType) {
if ((param.isByteArray) ||
(param.isBinary)) {
if ((param.isByteArray) || (param.isBinary)) {
// Binary primitive types don't implement `Display`.
param.vendorExtensions.put("formatString", "{:?}");
example = "swagger::ByteArray(Vec::from(\"" + ((param.example != null) ? param.example : "") + "\"))";
Expand Down Expand Up @@ -1119,12 +1106,7 @@ private void processParam(CodegenParameter param, CodegenOperation op) {
} else {
// Not required, so override the format string and example
param.vendorExtensions.put("formatString", "{:?}");
if (param.isFile) {
// Optional file types are wrapped in a future
param.vendorExtensions.put("example", (example != null) ? "Box::new(future::ok(Some(" + example + "))) as Box<Future<Item=_, Error=_> + Send>" : "None");
} else {
param.vendorExtensions.put("example", (example != null) ? "Some(" + example + ")" : "None");
}
param.vendorExtensions.put("example", (example != null) ? "Some(" + example + ")" : "None");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ license = "Unlicense"

[features]
default = ["client", "server"]
client = ["serde_json", {{#usesUrlEncodedForm}}"serde_urlencoded", {{/usesUrlEncodedForm}} {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"{{#apiHasFile}}, "multipart"{{/apiHasFile}}]
server = ["serde_json", {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"{{#apiHasFile}}, "multipart"{{/apiHasFile}}]
client = ["serde_json", {{#usesUrlEncodedForm}}"serde_urlencoded", {{/usesUrlEncodedForm}} {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"]
server = ["serde_json", {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"]

[dependencies]
# Required by example server.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ extern crate openssl;
extern crate mime;
extern crate chrono;
extern crate url;
{{#apiHasFile}}extern crate multipart;{{/apiHasFile}}
{{#usesUrlEncodedForm}}extern crate serde_urlencoded;{{/usesUrlEncodedForm}}

{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}
{{#apiHasFile}}use self::multipart::client::lazy::Multipart;{{/apiHasFile}}
use hyper;
use hyper::header::{Headers, ContentType};
use hyper::Uri;
Expand Down Expand Up @@ -239,7 +237,7 @@ impl<F, C> Api<C> for Client<F> where
F: Future<Item=hyper::Response, Error=hyper::Error> + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<AuthData>>{{/hasAuthMethods}}{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, param_{{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
{{#queryParams}}{{#-first}}
// Query parameters
{{/-first}}{{#required}} let query_{{paramName}} = format!("{{baseName}}={{=<% %>=}}{<% paramName %>}<%={{ }}=%>&", {{paramName}}=param_{{paramName}}{{#isListContainer}}.join(","){{/isListContainer}}{{^isListContainer}}.to_string(){{/isListContainer}});
Expand All @@ -259,47 +257,13 @@ impl<F, C> Api<C> for Client<F> where

let mut request = hyper::Request::new(hyper::Method::{{#vendorExtensions}}{{HttpMethod}}{{/vendorExtensions}}, uri);

{{#vendorExtensions}}{{#hasFile}} // Form data body
let mut multipart = Multipart::new();

// Helper function to convert a Stream into a String. The String can then be used to build the HTTP body.
fn convert_stream_to_string(stream: Box<Stream<Item=Vec<u8>, Error=Error> + Send>) -> Result<String, ApiError> {

stream.concat2()
.wait()
.map_err(|e| ApiError(format!("Unable to collect stream: {}", e)))
.and_then(|body| String::from_utf8(body)
.map_err(|e| ApiError(format!("Failed to convert utf8 stream to String: {}", e))))
}{{/hasFile}}{{/vendorExtensions}}{{#formParams}}{{#isFile}}

{{^required}} if let Ok(Some(param_{{paramName}})) = param_{{paramName}}.wait() { {{/required}}
{{^required}} {{/required}} match convert_stream_to_string(param_{{paramName}}) {
{{^required}} {{/required}} Ok(param_{{paramName}}) => {
// Add file to multipart form.
multipart.add_text("{{paramName}}", param_{{paramName}});
},
{{^required}} {{/required}} Err(err) => return Box::new(futures::done(Err(err))),
{{^required}} {{/required}} }
{{^required}}}{{/required}}{{/isFile}}{{/formParams}}{{#vendorExtensions}}{{#hasFile}}

let mut fields = match multipart.prepare() {
Ok(fields) => fields,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build request: {}", err))))),
};

let mut body_string = String::new();
let body = fields.to_body().read_to_string(&mut body_string);
let boundary = fields.boundary();
let multipart_header = match mime::Mime::from_str(&format!("multipart/form-data;boundary={}", boundary)) {
Ok(multipart_header) => multipart_header,
Err(err) => return Box::new(futures::done(Err(ApiError(format!("Unable to build multipart header: {:?}", err))))),
};{{/hasFile}}{{^hasFile}}{{#formParams}}{{#-first}} let params = &[{{/-first}}
{{#vendorExtensions}}{{#formParams}}{{#-first}} let params = &[{{/-first}}
("{{baseName}}", {{#vendorExtensions}}{{#required}}Some({{#isString}}param_{{paramName}}{{/isString}}{{^isString}}format!("{:?}", param_{{paramName}}){{/isString}}){{/required}}{{^required}}{{#isString}}param_{{paramName}}{{/isString}}{{^isString}}param_{{paramName}}.map(|param| format!("{:?}", param)){{/isString}}{{/required}}),{{/vendorExtensions}}{{#-last}}
];
let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize");

request.headers_mut().set(ContentType(mimetypes::requests::{{#vendorExtensions}}{{uppercase_operation_id}}{{/vendorExtensions}}.clone()));
request.set_body(body.into_bytes());{{/-last}}{{/formParams}}{{/hasFile}}{{/vendorExtensions}}{{#bodyParam}}{{#-first}}
request.set_body(body.into_bytes());{{/-last}}{{/formParams}}{{/vendorExtensions}}{{#bodyParam}}{{#-first}}
// Body parameter
{{/-first}}{{#vendorExtensions}}{{#required}}{{#consumesPlainText}} let body = param_{{paramName}};{{/consumesPlainText}}{{#consumesXml}}
{{^has_namespace}} let body = serde_xml_rs::to_string(&param_{{paramName}}).expect("impossible to fail to serialize");{{/has_namespace}}{{#has_namespace}}
Expand Down Expand Up @@ -340,11 +304,6 @@ impl<F, C> Api<C> for Client<F> where
{{/required}}{{/isMapContainer}}{{#isMapContainer}} let param_{{paramName}}: Option<{{{dataType}}}> = None;
{{/isMapContainer}}{{/headerParams}}

{{#vendorExtensions}}{{#hasFile}}
request.headers_mut().set(ContentType(multipart_header));
request.set_body(body_string.into_bytes());
{{/hasFile}}{{/vendorExtensions}}

Box::new(self.client_service.call(request)
.map_err(|e| ApiError(format!("No response received: {}", e)))
.and_then(|mut response| {
Expand All @@ -357,13 +316,9 @@ impl<F, C> Api<C> for Client<F> where
None => return Box::new(future::err(ApiError(String::from("Required response header {{baseName}} for response {{code}} was not found.")))) as Box<Future<Item=_, Error=_>>,
};
{{/headers}}
{{^isFile}}let body = response.body();{{/isFile}}{{#isFile}}let body = Box::new(response.body()
.map(|chunk| chunk.to_vec())
.map_err(|_|
Error::new(ErrorKind::Other, "Received error reading response.")
));{{/isFile}}
let body = response.body();
Box::new(
{{#dataType}}{{^isFile}}
{{#dataType}}
body
.concat2()
.map_err(|e| ApiError(format!("Failed to read response: {}", e)))
Expand All @@ -383,9 +338,6 @@ impl<F, C> Api<C> for Client<F> where
{{/producesPlainText}}{{/vendorExtensions}}
))
.map(move |body|
{{/isFile}}{{#isFile}}
future::ok(
{{/isFile}}
{{operationId}}Response::{{#vendorExtensions}}{{x-responseId}}{{/vendorExtensions}}{{^headers}}(body){{/headers}}{{#headers}}{{#-first}}{ body: body, {{/-first}}{{name}}: response_{{name}}{{^-last}}, {{/-last}}{{#-last}} }{{/-last}}{{/headers}}
)
{{/dataType}}{{^dataType}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

use futures::{self, Future};
use chrono;
{{#apiHasFile}}use futures::Stream;{{/apiHasFile}}
use std::collections::HashMap;
{{#apiHasFile}}use std::io::Error;{{/apiHasFile}}
use std::marker::PhantomData;
{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}
use swagger;
Expand All @@ -31,10 +29,9 @@ impl<C> Server<C> {
impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
let context = context.clone();
println!("{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{^isFile}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/isFile}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}{{^isFile}}, {{paramName}}{{/isFile}}{{/allParams}}, context.get().0.clone());{{#allParams}}{{#isFile}}
let _ = {{paramName}}; //Suppresses unused param warning{{/isFile}}{{/allParams}}
println!("{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{#vendorExtensions}}{{{formatString}}}{{/vendorExtensions}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{paramName}}{{/allParams}}, context.get().0.clone());{{#allParams}}{{/allParams}}
Box::new(futures::failed("Generic failure".into()))
}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ pub enum {{operationId}}Response {
pub trait Api<C> {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}, context: &C) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}

/// API without a `Context`
pub trait ApiNoContext {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>>;
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}

Expand All @@ -78,7 +78,7 @@ impl<'a, T: Api<C> + Sized, C> ContextWrapperExt<'a, C> for T {
impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{{#summary}} /// {{{summary}}}{{/summary}}
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}{{#isFile}}Box<Future<Item={{/isFile}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{#isFile}}, Error=Error> + Send>{{/isFile}}{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
fn {{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}(&self{{#allParams}}, {{paramName}}: {{^required}}Option<{{/required}}{{#isListContainer}}&{{/isListContainer}}{{{dataType}}}{{^required}}>{{/required}}{{/allParams}}) -> Box<Future<Item={{operationId}}Response, Error=ApiError>> {
self.api().{{#vendorExtensions}}{{operation_id}}{{/vendorExtensions}}({{#allParams}}{{paramName}}, {{/allParams}}&self.context())
}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ pub mod requests {
lazy_static! {
pub static ref {{#vendorExtensions}}{{uppercase_operation_id}}{{/vendorExtensions}}: Mime = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}".parse().unwrap();
}
{{/bodyParam}}{{^bodyParam}}{{#vendorExtensions}}{{#formParams}}{{#-first}}{{^hasFile}} /// Create Mime objects for the request content types for {{operationId}}
{{/bodyParam}}{{^bodyParam}}{{#vendorExtensions}}{{#formParams}}{{#-first}} /// Create Mime objects for the request content types for {{operationId}}
lazy_static! {
pub static ref {{#vendorExtensions}}{{uppercase_operation_id}}{{/vendorExtensions}}: Mime = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/x-www-form-urlencoded{{/consumes}}".parse().unwrap();
}
{{/hasFile}}{{/-first}}{{/formParams}}{{/vendorExtensions}}{{/bodyParam}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
{{/-first}}{{/formParams}}{{/vendorExtensions}}{{/bodyParam}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
}
Loading