Compatiblity with actix-web 4.0.0-beta.8

Fixes #114

Signed-off-by: Jim Crossley <jim@crossleys.org>
This commit is contained in:
Jim Crossley 2021-07-23 16:27:08 -04:00
parent e626cffa3e
commit 94f65f656d
7 changed files with 36 additions and 55 deletions

View File

@ -35,7 +35,7 @@ snafu = "^0.6"
bitflags = "^1.2" bitflags = "^1.2"
# runtime optional deps # runtime optional deps
actix-web = { version = "^3", default-features = false, optional = true } actix-web = { version = "4.0.0-beta.8", default-features = false, optional = true }
reqwest-lib = { version = "^0.11", default-features = false, features = ["rustls-tls"], optional = true, package = "reqwest" } reqwest-lib = { version = "^0.11", default-features = false, features = ["rustls-tls"], optional = true, package = "reqwest" }
rdkafka-lib = { version = "^0.25", features = ["cmake-build"], optional = true, package = "rdkafka" } rdkafka-lib = { version = "^0.25", features = ["cmake-build"], optional = true, package = "rdkafka" }
warp-lib = { version = "^0.3", optional = true, package = "warp" } warp-lib = { version = "^0.3", optional = true, package = "warp" }

View File

@ -6,8 +6,8 @@ edition = "2018"
[dependencies] [dependencies]
cloudevents-sdk = { path = "../..", features = ["actix"] } cloudevents-sdk = { path = "../..", features = ["actix"] }
actix-web = "^3" actix-web = "4.0.0-beta.8"
actix-cors = "^0.5" actix-cors = "0.6.0-beta.2"
serde_json = "^1.0" serde_json = "^1.0"
url = { version = "^2.1" } url = { version = "^2.1" }
env_logger = "0.7.1" env_logger = "0.7.1"

View File

@ -29,8 +29,8 @@ async fn main() -> std::io::Result<()> {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.wrap(actix_web::middleware::Logger::default())
.wrap(actix_cors::Cors::permissive()) .wrap(actix_cors::Cors::permissive())
.wrap(actix_web::middleware::Logger::default())
.service(post_event) .service(post_event)
.service(get_event) .service(get_event)
}) })

View File

@ -24,7 +24,7 @@
//! //!
//! #[get("/")] //! #[get("/")]
//! async fn get_event() -> Result<HttpResponse, actix_web::Error> { //! async fn get_event() -> Result<HttpResponse, actix_web::Error> {
//! Ok(HttpResponse::Ok() //! HttpResponse::Ok()
//! .event( //! .event(
//! EventBuilderV10::new() //! EventBuilderV10::new()
//! .id("0001") //! .id("0001")
@ -34,8 +34,6 @@
//! .build() //! .build()
//! .expect("No error while building the event"), //! .expect("No error while building the event"),
//! ) //! )
//! .await?
//! )
//! } //! }
//! ``` //! ```

View File

@ -83,11 +83,11 @@ mod tests {
let expected = fixtures::v10::minimal_string_extension(); let expected = fixtures::v10::minimal_string_extension();
let (req, payload) = test::TestRequest::post() let (req, payload) = test::TestRequest::post()
.header("ce-specversion", "1.0") .insert_header(("ce-specversion", "1.0"))
.header("ce-id", "0001") .insert_header(("ce-id", "0001"))
.header("ce-type", "test_event.test_application") .insert_header(("ce-type", "test_event.test_application"))
.header("ce-source", "http://localhost/") .insert_header(("ce-source", "http://localhost/"))
.header("ce-someint", "10") .insert_header(("ce-someint", "10"))
.to_http_parts(); .to_http_parts();
let resp = req.to_event(web::Payload(payload)).await.unwrap(); let resp = req.to_event(web::Payload(payload)).await.unwrap();
@ -99,16 +99,16 @@ mod tests {
let expected = fixtures::v10::full_binary_json_data_string_extension(); let expected = fixtures::v10::full_binary_json_data_string_extension();
let (req, payload) = test::TestRequest::post() let (req, payload) = test::TestRequest::post()
.header("ce-specversion", "1.0") .insert_header(("ce-specversion", "1.0"))
.header("ce-id", "0001") .insert_header(("ce-id", "0001"))
.header("ce-type", "test_event.test_application") .insert_header(("ce-type", "test_event.test_application"))
.header("ce-subject", "cloudevents-sdk") .insert_header(("ce-subject", "cloudevents-sdk"))
.header("ce-source", "http://localhost/") .insert_header(("ce-source", "http://localhost/"))
.header("ce-time", fixtures::time().to_rfc3339()) .insert_header(("ce-time", fixtures::time().to_rfc3339()))
.header("ce-string_ex", "val") .insert_header(("ce-string_ex", "val"))
.header("ce-int_ex", "10") .insert_header(("ce-int_ex", "10"))
.header("ce-bool_ex", "true") .insert_header(("ce-bool_ex", "true"))
.header("content-type", "application/json") .insert_header(("content-type", "application/json"))
.set_json(&fixtures::json_data()) .set_json(&fixtures::json_data())
.to_http_parts(); .to_http_parts();
@ -136,7 +136,7 @@ mod tests {
let expected = fixtures::v10::full_json_data_string_extension(); let expected = fixtures::v10::full_json_data_string_extension();
let (req, payload) = test::TestRequest::post() let (req, payload) = test::TestRequest::post()
.header("content-type", "application/cloudevents+json") .insert_header(("content-type", "application/cloudevents+json"))
.set_payload(bytes) .set_payload(bytes)
.to_http_parts(); .to_http_parts();

View File

@ -1,16 +1,12 @@
use crate::binding::http::{Builder, Serializer}; use crate::binding::http::{Builder, Serializer};
use crate::message::{BinaryDeserializer, Result}; use crate::message::{BinaryDeserializer, Result};
use crate::Event; use crate::Event;
use actix_web::dev::HttpResponseBuilder;
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::HttpResponse; use actix_web::{HttpRequest, HttpResponse, HttpResponseBuilder};
use async_trait::async_trait;
use futures::future::LocalBoxFuture;
use futures::FutureExt;
impl Builder<HttpResponse> for HttpResponseBuilder { impl Builder<HttpResponse> for HttpResponseBuilder {
fn header(&mut self, key: &str, value: http::header::HeaderValue) { fn header(&mut self, key: &str, value: http::header::HeaderValue) {
self.set_header(key, value); self.insert_header((key, value));
} }
fn body(&mut self, bytes: Vec<u8>) -> Result<HttpResponse> { fn body(&mut self, bytes: Vec<u8>) -> Result<HttpResponse> {
Ok(HttpResponseBuilder::body(self, bytes)) Ok(HttpResponseBuilder::body(self, bytes))
@ -21,7 +17,7 @@ impl Builder<HttpResponse> for HttpResponseBuilder {
} }
/// Method to fill an [`HttpResponseBuilder`] with an [`Event`]. /// Method to fill an [`HttpResponseBuilder`] with an [`Event`].
pub async fn event_to_response<T: Builder<HttpResponse> + 'static>( pub fn event_to_response<T: Builder<HttpResponse> + 'static>(
event: Event, event: Event,
response: T, response: T,
) -> std::result::Result<HttpResponse, actix_web::error::Error> { ) -> std::result::Result<HttpResponse, actix_web::error::Error> {
@ -31,40 +27,29 @@ pub async fn event_to_response<T: Builder<HttpResponse> + 'static>(
/// So that an actix-web handler may return an Event /// So that an actix-web handler may return an Event
impl actix_web::Responder for Event { impl actix_web::Responder for Event {
type Error = actix_web::Error; fn respond_to(self, _: &HttpRequest) -> HttpResponse {
type Future = LocalBoxFuture<'static, std::result::Result<HttpResponse, Self::Error>>; HttpResponse::build(StatusCode::OK).event(self).unwrap()
fn respond_to(self, _: &actix_web::HttpRequest) -> Self::Future {
async { HttpResponse::build(StatusCode::OK).event(self).await }.boxed_local()
} }
} }
/// Extension Trait for [`HttpResponseBuilder`] which acts as a wrapper for the function [`event_to_response()`]. /// Extension Trait for [`HttpResponseBuilder`] which acts as a wrapper for the function [`event_to_response()`].
/// ///
/// This trait is sealed and cannot be implemented for types outside of this crate. /// This trait is sealed and cannot be implemented for types outside of this crate.
#[async_trait(?Send)]
pub trait HttpResponseBuilderExt: private::Sealed { pub trait HttpResponseBuilderExt: private::Sealed {
/// Fill this [`HttpResponseBuilder`] with an [`Event`]. /// Fill this [`HttpResponseBuilder`] with an [`Event`].
async fn event( fn event(self, event: Event) -> std::result::Result<HttpResponse, actix_web::Error>;
self,
event: Event,
) -> std::result::Result<HttpResponse, actix_web::error::Error>;
} }
#[async_trait(?Send)]
impl HttpResponseBuilderExt for HttpResponseBuilder { impl HttpResponseBuilderExt for HttpResponseBuilder {
async fn event( fn event(self, event: Event) -> std::result::Result<HttpResponse, actix_web::Error> {
self, event_to_response(event, self)
event: Event,
) -> std::result::Result<HttpResponse, actix_web::error::Error> {
event_to_response(event, self).await
} }
} }
// Sealing the HttpResponseBuilderExt // Sealing the HttpResponseBuilderExt
mod private { mod private {
pub trait Sealed {} pub trait Sealed {}
impl Sealed for actix_web::dev::HttpResponseBuilder {} impl Sealed for actix_web::HttpResponseBuilder {}
} }
#[cfg(test)] #[cfg(test)]
@ -74,7 +59,6 @@ mod tests {
use crate::test::fixtures; use crate::test::fixtures;
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::test; use actix_web::test;
use futures::TryStreamExt;
#[actix_rt::test] #[actix_rt::test]
async fn test_response() { async fn test_response() {
@ -82,7 +66,6 @@ mod tests {
let resp = HttpResponseBuilder::new(StatusCode::OK) let resp = HttpResponseBuilder::new(StatusCode::OK)
.event(input) .event(input)
.await
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
@ -115,9 +98,8 @@ mod tests {
async fn test_response_with_full_data() { async fn test_response_with_full_data() {
let input = fixtures::v10::full_binary_json_data_string_extension(); let input = fixtures::v10::full_binary_json_data_string_extension();
let mut resp = HttpResponseBuilder::new(StatusCode::OK) let resp = HttpResponseBuilder::new(StatusCode::OK)
.event(input) .event(input)
.await
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
@ -153,9 +135,10 @@ mod tests {
"10" "10"
); );
let bytes = test::load_stream(resp.take_body().into_stream()) // let bytes = test::load_stream(resp.take_body().into_stream())
.await // .await
.unwrap(); // .unwrap();
let bytes = test::load_body(resp.into_body()).await.unwrap();
assert_eq!(fixtures::json_data_binary(), bytes.as_ref()) assert_eq!(fixtures::json_data_binary(), bytes.as_ref())
} }
} }

View File

@ -39,7 +39,7 @@
//! - `actix`: Enables the [`binding::actix`] protocol binding module. This //! - `actix`: Enables the [`binding::actix`] protocol binding module. This
//! extends the [`actix_web::HttpRequest`] with a //! extends the [`actix_web::HttpRequest`] with a
//! [`to_event`](binding::actix::HttpRequestExt::to_event) function, the //! [`to_event`](binding::actix::HttpRequestExt::to_event) function, the
//! [`actix_web::dev::HttpResponseBuilder`] with an //! [`actix_web::HttpResponseBuilder`] with an
//! [`event`](binding::actix::HttpResponseBuilderExt::event) function, //! [`event`](binding::actix::HttpResponseBuilderExt::event) function,
//! and implementations for [`actix_web::FromRequest`] and //! and implementations for [`actix_web::FromRequest`] and
//! [`actix_web::Responder`] in order to take advantage of actix-web's //! [`actix_web::Responder`] in order to take advantage of actix-web's