Skip to content

Commit

Permalink
Generate a Client method for Dropshot websocket channels
Browse files Browse the repository at this point in the history
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 0.11.12 or
newer for HTTP Upgrade support, as well as base64 and rand if any
endpoints are websocket channels:
```
[dependencies]
reqwest = { version = "0.11.12" features = ["json", "stream"] }
base64 = "0.13"
rand = "0.8"
```
  • Loading branch information
lif committed Sep 22, 2022
1 parent bffee9c commit 7d0df33
Show file tree
Hide file tree
Showing 16 changed files with 5,513 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Expand Up @@ -24,6 +24,7 @@ https://github.com/oxidecomputer/progenitor/compare/v0.1.1\...v0.2.0[Full list o
* Derive `Debug` for `Client` and builders for the various operations (#145)
* Builders for `struct` types (#171)
* Add a prelude that include the `Client` and any extension traits (#176)
* Add support for upgrading connections, which requires a version bump to reqwest. (#183)

== 0.1.1 (released 2022-05-13)

Expand Down
46 changes: 43 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions README.md
Expand Up @@ -54,6 +54,13 @@ Similarly if there is a `format` field set to `uuid`:
+uuid = { version = "1.0.0", features = ["serde", "v4"] }
```

And if there are any websocket channel endpoints:
```diff
[dependencies]
+base64 = "0.13"
+rand = "0.8"
```

The macro has some additional fancy options to control the generated code:

```rust
Expand Down Expand Up @@ -116,7 +123,7 @@ You'll need to add add the following to `Cargo.toml`:
+serde_json = "1.0"
```

(`chrono` and `uuid` as above)
(`chrono`, `uuid`, `base64`, and `rand` as above)

Note that `progenitor` is used by `build.rs`, but the generated code required
`progenitor-client`.
Expand Down Expand Up @@ -290,4 +297,4 @@ let result = client
```

Consumers do not need to specify parameters and struct properties that are not
required or for which the API specifies defaults. Neat!
required or for which the API specifies defaults. Neat!
4 changes: 3 additions & 1 deletion example-build/Cargo.toml
Expand Up @@ -7,7 +7,9 @@ edition = "2021"
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
progenitor-client = { path = "../progenitor-client" }
reqwest = { version = "0.11", features = ["json", "stream"] }
reqwest = { version = "0.11.12", features = ["json", "stream"] }
base64 = "0.13"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
uuid = { version = "1.0", features = ["serde", "v4"] }

Expand Down
2 changes: 1 addition & 1 deletion example-macro/Cargo.toml
Expand Up @@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
progenitor = { path = "../progenitor" }
reqwest = { version = "0.11", features = ["json", "stream"] }
reqwest = { version = "0.11.12", features = ["json", "stream"] }
schemars = { version = "0.8.10", features = ["uuid1"] }
serde = { version = "1.0", features = ["derive"] }
uuid = { version = "1.0", features = ["serde", "v4"] }
2 changes: 1 addition & 1 deletion progenitor-client/Cargo.toml
Expand Up @@ -10,7 +10,7 @@ description = "An OpenAPI client generator - client support"
bytes = "1.2.1"
futures-core = "0.3.24"
percent-encoding = "2.2"
reqwest = { version = "0.11", default-features = false, features = ["json", "stream"] }
reqwest = { version = "0.11.12", default-features = false, features = ["json", "stream"] }
serde = "1.0"
serde_json = "1.0"
serde_urlencoded = "0.7.1"
24 changes: 24 additions & 0 deletions progenitor-client/src/progenitor_client.rs
Expand Up @@ -76,6 +76,30 @@ impl<T: DeserializeOwned> ResponseValue<T> {
}
}

impl ResponseValue<reqwest::Upgraded> {
#[doc(hidden)]
pub async fn upgrade<E: std::fmt::Debug>(
response: reqwest::Response,
) -> Result<Self, Error<E>> {
let status = response.status();
let headers = response.headers().clone();
if status == reqwest::StatusCode::SWITCHING_PROTOCOLS {
let inner = response
.upgrade()
.await
.map_err(Error::InvalidResponsePayload)?;

Ok(Self {
inner,
status,
headers,
})
} else {
Err(Error::UnexpectedResponse(response))
}
}
}

impl ResponseValue<ByteStream> {
#[doc(hidden)]
pub fn stream(response: reqwest::Response) -> Self {
Expand Down
11 changes: 10 additions & 1 deletion progenitor-impl/src/lib.rs
Expand Up @@ -26,6 +26,8 @@ pub enum Error {
UnexpectedFormat(String),
#[error("invalid operation path {0}")]
InvalidPath(String),
#[error("invalid dropshot extension use: {0}")]
InvalidExtension(String),
#[error("internal error {0}")]
InternalError(String),
}
Expand All @@ -36,6 +38,7 @@ pub struct Generator {
type_space: TypeSpace,
settings: GenerationSettings,
uses_futures: bool,
uses_websockets: bool,
}

#[derive(Default, Clone)]
Expand Down Expand Up @@ -116,6 +119,7 @@ impl Default for Generator {
),
settings: Default::default(),
uses_futures: Default::default(),
uses_websockets: Default::default(),
}
}
}
Expand All @@ -133,6 +137,7 @@ impl Generator {
type_space: TypeSpace::new(&type_settings),
settings: settings.clone(),
uses_futures: false,
uses_websockets: false,
}
}

Expand Down Expand Up @@ -426,7 +431,7 @@ impl Generator {
"bytes = \"1.1\"",
"futures-core = \"0.3\"",
"percent-encoding = \"2.1\"",
"reqwest = { version = \"0.11\", features = [\"json\", \"stream\"] }",
"reqwest = { version = \"0.11.12\", features = [\"json\", \"stream\"] }",
"serde = { version = \"1.0\", features = [\"derive\"] }",
"serde_urlencoded = \"0.7\"",
];
Expand All @@ -444,6 +449,10 @@ impl Generator {
if self.uses_futures {
deps.push("futures = \"0.3\"")
}
if self.uses_websockets {
deps.push("base64 = \"0.13\"");
deps.push("rand = \"0.8\"");
}
if self.type_space.uses_serde_json() {
deps.push("serde_json = \"1.0\"")
}
Expand Down

0 comments on commit 7d0df33

Please sign in to comment.