Skip to content

Commit ef7db01

Browse files
author
lif
committed
Generate a Client method for Dropshot websocket channels
Generated methods return `ResponseValue<reqwest::Upgrade`, which may be passed to a websocket protocol implementation such as `tokio_tungstenite::WebSocketStream::from_raw_stream(rv.into_inner(), ...)` for the purpose of implementing against the raw websocket connection, but may later be extended as a generic to allow higher-level channel message definitions. Per the changelog, consumers will need to depend on reqwest from git until such time upstream cuts a new crates.io release: ``` reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] } ```
1 parent 6e69bb4 commit ef7db01

File tree

11 files changed

+1043
-30
lines changed

11 files changed

+1043
-30
lines changed

CHANGELOG.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ https://github.com/oxidecomputer/progenitor/compare/v0.1.1\...HEAD[Full list of
2020
* Derive `Debug` for `Client` and builders for the various operations (#145)
2121
* Builders for `struct` types (#171)
2222
* Add a prelude that include the `Client` and any extension traits (#176)
23+
* Add support for upgrading connections, which requires a version bump to reqwest. (#183)
2324

2425
== 0.1.1 (released 2022-05-13)
2526

Cargo.lock

+60-23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example-build/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ edition = "2021"
77
[dependencies]
88
chrono = { version = "0.4", features = ["serde"] }
99
progenitor-client = { path = "../progenitor-client" }
10-
reqwest = { version = "0.11", features = ["json", "stream"] }
10+
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] }
11+
#reqwest = { version = "0.11", features = ["json", "stream"] }
1112
serde = { version = "1.0", features = ["derive"] }
1213
uuid = { version = "1.0", features = ["serde", "v4"] }
1314

example-macro/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ edition = "2021"
77
[dependencies]
88
chrono = { version = "0.4", features = ["serde"] }
99
progenitor = { path = "../progenitor" }
10-
reqwest = { version = "0.11", features = ["json", "stream"] }
10+
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] }
11+
#reqwest = { version = "0.11", features = ["json", "stream"] }
1112
schemars = { version = "0.8.10", features = ["uuid1"] }
1213
serde = { version = "1.0", features = ["derive"] }
1314
uuid = { version = "1.0", features = ["serde", "v4"] }

progenitor-client/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ description = "An OpenAPI client generator - client support"
1010
bytes = "1.2.1"
1111
futures-core = "0.3.24"
1212
percent-encoding = "2.1"
13-
reqwest = { version = "0.11", default-features = false, features = ["json", "stream"] }
13+
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "6ceb23958c8b6d7f1d8ee093f0ad73184d133d40", features = ["json", "stream"] }
14+
#reqwest = { version = "0.11", default-features = false, features = ["json", "stream"] }
1415
serde = "1.0"
1516
serde_json = "1.0"
1617
serde_urlencoded = "0.7.1"
18+
base64 = "0.13"
19+
rand = "0.8"

progenitor-client/src/progenitor_client.rs

+29
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,30 @@ impl<T: DeserializeOwned> ResponseValue<T> {
7676
}
7777
}
7878

79+
impl ResponseValue<reqwest::Upgraded> {
80+
#[doc(hidden)]
81+
pub async fn upgrade<E: std::fmt::Debug>(
82+
response: reqwest::Response,
83+
) -> Result<Self, Error<E>> {
84+
let status = response.status();
85+
let headers = response.headers().clone();
86+
if status == reqwest::StatusCode::SWITCHING_PROTOCOLS {
87+
let inner = response
88+
.upgrade()
89+
.await
90+
.map_err(Error::InvalidResponsePayload)?;
91+
92+
Ok(Self {
93+
inner,
94+
status,
95+
headers,
96+
})
97+
} else {
98+
Err(Error::UnexpectedResponse(response))
99+
}
100+
}
101+
}
102+
79103
impl ResponseValue<ByteStream> {
80104
#[doc(hidden)]
81105
pub fn stream(response: reqwest::Response) -> Self {
@@ -377,3 +401,8 @@ impl<E> RequestBuilderExt<E> for RequestBuilder {
377401
})?))
378402
}
379403
}
404+
405+
#[doc(hidden)]
406+
pub fn generate_websocket_key() -> String {
407+
base64::encode(rand::random::<[u8; 16]>())
408+
}

progenitor-impl/src/lib.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub enum Error {
2626
UnexpectedFormat(String),
2727
#[error("invalid operation path {0}")]
2828
InvalidPath(String),
29+
#[error("invalid dropshot extension use: {0}")]
30+
InvalidExtension(String),
2931
#[error("internal error {0}")]
3032
InternalError(String),
3133
}
@@ -213,7 +215,12 @@ impl Generator {
213215
let file = quote! {
214216
// Re-export ResponseValue and Error since those are used by the
215217
// public interface of Client.
216-
pub use progenitor_client::{ByteStream, Error, ResponseValue};
218+
pub use progenitor_client::{
219+
ByteStream,
220+
Error,
221+
ResponseValue,
222+
generate_websocket_key
223+
};
217224
#[allow(unused_imports)]
218225
use progenitor_client::{encode_path, RequestBuilderExt};
219226

@@ -319,6 +326,7 @@ impl Generator {
319326
#[allow(unused_imports)]
320327
use super::{
321328
encode_path,
329+
generate_websocket_key,
322330
ByteStream,
323331
Error,
324332
RequestBuilderExt,
@@ -358,11 +366,14 @@ impl Generator {
358366
#[allow(unused_imports)]
359367
use super::{
360368
encode_path,
369+
generate_websocket_key,
361370
ByteStream,
362371
Error,
363372
RequestBuilderExt,
364373
ResponseValue,
365374
};
375+
#[allow(unused_imports)]
376+
use std::convert::TryInto;
366377

367378
#(#builder_struct)*
368379

0 commit comments

Comments
 (0)