diff --git a/.travis.yml b/.travis.yml index 32fe873ae..5ac82ea72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: rust rust: - - 1.21.0 - stable - beta - nightly diff --git a/CHANGES.md b/CHANGES.md index e631f811d..74b18c7dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ # Changes +## 0.4.0 (2019-05-18) + +* Upgrade to actix-web 1.0.0-rc +* Removed `protobuf` method for `HttpRequest` (use `ProtoBuf` extractor instead) + ## 0.3.0 (2019-03-07) * Upgrade to actix-web 0.7.18 diff --git a/Cargo.toml b/Cargo.toml index 2c07a39df..67475cf8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-protobuf" -version = "0.3.0" +version = "0.4.0" authors = ["kingxsp "] description = "Protobuf support for actix-web framework." readme = "README.md" @@ -21,10 +21,10 @@ path = "src/lib.rs" [dependencies] bytes = "0.4" futures = "0.1" -failure = "0.1" +derive_more = "0.14" -actix = "0.7" -actix-web = "0.7" +actix = "0.8.1" +actix-web = "1.0.0-rc" prost = "0.4" diff --git a/examples/prost-example/Cargo.toml b/examples/prost-example/Cargo.toml index e797e7833..ef4156049 100644 --- a/examples/prost-example/Cargo.toml +++ b/examples/prost-example/Cargo.toml @@ -10,6 +10,6 @@ env_logger = "*" prost = "0.4" prost-derive = "0.4" -actix = "0.7" -actix-web = "0.7" +actix = "0.8.1" +actix-web = "1.0.0-rc" actix-protobuf = { path="../../" } \ No newline at end of file diff --git a/examples/prost-example/client.py b/examples/prost-example/client.py old mode 100644 new mode 100755 index c55f78885..1f16270f4 --- a/examples/prost-example/client.py +++ b/examples/prost-example/client.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 # just start server and run client.py # wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-python-3.5.1.zip @@ -5,12 +6,11 @@ # cd protobuf-3.5.1/python/ # python3.6 setup.py install -# pip3.6 install --upgrade pip -# pip3.6 install aiohttp +# pip3 install --upgrade pip +# pip3 install aiohttp -# python3.6 client.py +# python3 client.py -#!/usr/bin/env python import test_pb2 import traceback import sys @@ -48,7 +48,7 @@ async def fetch(session): obj = test_pb2.MyObj() obj.number = 9 obj.name = 'USB' - async with session.post('http://localhost:8080/', data=obj.SerializeToString(), + async with session.post('http://127.0.0.1:8081/', data=obj.SerializeToString(), headers={"content-type": "application/protobuf"}) as resp: print(resp.status) data = await resp.read() diff --git a/examples/prost-example/src/main.rs b/examples/prost-example/src/main.rs index d61ea1402..15f7f4c88 100644 --- a/examples/prost-example/src/main.rs +++ b/examples/prost-example/src/main.rs @@ -1,43 +1,43 @@ -extern crate bytes; extern crate actix; -extern crate actix_web; extern crate actix_protobuf; +extern crate actix_web; +extern crate bytes; extern crate env_logger; extern crate prost; -#[macro_use] +#[macro_use] extern crate prost_derive; -use actix_web::*; use actix_protobuf::*; +use actix_web::*; #[derive(Clone, PartialEq, Message)] pub struct MyObj { - #[prost(int32, tag="1")] + #[prost(int32, tag = "1")] pub number: i32, - #[prost(string, tag="2")] + #[prost(string, tag = "2")] pub name: String, } - fn index(msg: ProtoBuf) -> Result { println!("model: {:?}", msg); - HttpResponse::Ok().protobuf(msg.0) // <- send response + HttpResponse::Ok().protobuf(msg.0) // <- send response } - fn main() { ::std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); let sys = actix::System::new("prost-example"); - server::new(|| { + HttpServer::new(|| { App::new() - .middleware(middleware::Logger::default()) - .resource("/", |r| r.method(http::Method::POST).with(index))}) - .bind("127.0.0.1:8080").unwrap() - .shutdown_timeout(1) - .start(); + .wrap(middleware::Logger::default()) + .service(web::resource("/").route(web::post().to(index))) + }) + .bind("127.0.0.1:8081") + .unwrap() + .shutdown_timeout(1) + .start(); - println!("Started http server: 127.0.0.1:8080"); + println!("Started http server: 127.0.0.1:8081"); let _ = sys.run(); } diff --git a/src/lib.rs b/src/lib.rs index a461763eb..7c0811879 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,7 @@ extern crate actix; extern crate actix_web; extern crate bytes; extern crate futures; -#[macro_use] -extern crate failure; +extern crate derive_more; #[cfg(test)] extern crate http; @@ -13,6 +12,7 @@ extern crate prost; #[macro_use] extern crate prost_derive; use std::fmt; +use derive_more::Display; use std::ops::{Deref, DerefMut}; use bytes::{BytesMut, IntoBuf}; @@ -23,27 +23,26 @@ use prost::EncodeError as ProtoBufEncodeError; use futures::{Poll, Future, Stream}; use actix_web::http::header::{CONTENT_TYPE, CONTENT_LENGTH}; use actix_web::{Responder, HttpMessage, HttpRequest, HttpResponse, FromRequest}; -use actix_web::dev::HttpResponseBuilder; +use actix_web::dev::{HttpResponseBuilder, Payload}; use actix_web::error::{Error, PayloadError, ResponseError}; - -#[derive(Fail, Debug)] +#[derive(Debug, Display)] pub enum ProtoBufPayloadError { /// Payload size is bigger than 256k - #[fail(display="Payload size is bigger than 256k")] + #[display(fmt="Payload size is bigger than 256k")] Overflow, /// Content type error - #[fail(display="Content type error")] + #[display(fmt="Content type error")] ContentType, /// Serialize error - #[fail(display="ProtoBuf serialize error: {}", _0)] - Serialize(#[cause] ProtoBufEncodeError), + #[display(fmt="ProtoBuf serialize error: {}", _0)] + Serialize(ProtoBufEncodeError), /// Deserialize error - #[fail(display="ProtoBuf deserialize error: {}", _0)] - Deserialize(#[cause] ProtoBufDecodeError), + #[display(fmt="ProtoBuf deserialize error: {}", _0)] + Deserialize(ProtoBufDecodeError), /// Payload error - #[fail(display="Error that occur during reading payload: {}", _0)] - Payload(#[cause] PayloadError), + #[display(fmt="Error that occur during reading payload: {}", _0)] + Payload(PayloadError), } impl ResponseError for ProtoBufPayloadError { @@ -115,27 +114,31 @@ impl Default for ProtoBufConfig { } } -impl FromRequest for ProtoBuf - where T: Message + Default + 'static, S: 'static +impl FromRequest for ProtoBuf + where T: Message + Default + 'static { type Config = ProtoBufConfig; - type Result = Box>; + type Error = Error; + type Future = Box>; #[inline] - fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result { + fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { + let limit = req.app_data::().map(|c| c.limit).unwrap_or(262_144); Box::new( - ProtoBufMessage::new(req) - .limit(cfg.limit) - .from_err() + ProtoBufMessage::new(req, payload) + .limit(limit) + .map_err(move |e| { + e.into() + }) .map(ProtoBuf)) } } impl Responder for ProtoBuf { - type Item = HttpResponse; type Error = Error; + type Future = Result; - fn respond_to(self, _: &HttpRequest) -> Result { + fn respond_to(self, _: &HttpRequest) -> Self::Future { let mut buf = Vec::new(); self.0.encode(&mut buf) .map_err(|e| Error::from(ProtoBufPayloadError::Serialize(e))) @@ -147,18 +150,18 @@ impl Responder for ProtoBuf { } } -pub struct ProtoBufMessage{ +pub struct ProtoBufMessage{ limit: usize, length: Option, - stream: Option, + stream: Option, err: Option, - fut: Option>>, + fut: Option>>, } -impl ProtoBufMessage { +impl ProtoBufMessage { /// Create `ProtoBufMessage` for request. - pub fn new(req: &T) -> Self { + pub fn new(req: &HttpRequest, payload: &mut Payload) -> Self { if req.content_type() != "application/protobuf" { return ProtoBufMessage { limit: 262_144, @@ -181,7 +184,7 @@ impl ProtoBufMessage { ProtoBufMessage { limit: 262_144, length: len, - stream: Some(req.payload()), + stream: Some(payload.take()), fut: None, err: None, } @@ -194,13 +197,12 @@ impl ProtoBufMessage { } } -impl Future for ProtoBufMessage -where T: HttpMessage + 'static +impl Future for ProtoBufMessage { - type Item = U; + type Item = T; type Error = ProtoBufPayloadError; - fn poll(&mut self) -> Poll { + fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut { return fut.poll(); } @@ -228,7 +230,7 @@ where T: HttpMessage + 'static body.extend_from_slice(&chunk); Ok(body) } - }).and_then(|body| Ok(::decode(&mut body.into_buf())?)); + }).and_then(|body| Ok(::decode(&mut body.into_buf())?)); self.fut = Some(Box::new(fut)); self.poll() } @@ -251,30 +253,11 @@ impl ProtoBufResponseBuilder for HttpResponseBuilder { } } - - -pub trait ProtoBufHttpMessage { - fn protobuf(&self) -> ProtoBufMessage - where Self: HttpMessage + 'static; -} - -impl ProtoBufHttpMessage for HttpRequest { - - #[inline] - fn protobuf(&self) -> ProtoBufMessage - where Self: HttpMessage + 'static - { - ProtoBufMessage::new(self) - } -} - - - #[cfg(test)] mod tests { use super::*; use http::header; - use actix_web::test::TestRequest; + use actix_web::test::{block_on, TestRequest}; impl PartialEq for ProtoBufPayloadError { fn eq(&self, other: &ProtoBufPayloadError) -> bool { @@ -303,33 +286,34 @@ mod tests { #[test] fn test_protobuf() { let protobuf = ProtoBuf(MyObject{number: 9 , name: "test".to_owned()}); - let resp = protobuf.respond_to(&TestRequest::default().finish()).unwrap(); + let req = TestRequest::default().to_http_request(); + let resp = protobuf.respond_to(&req).unwrap(); assert_eq!(resp.headers().get(header::CONTENT_TYPE).unwrap(), "application/protobuf"); } #[test] fn test_protobuf_message() { - let req = TestRequest::default().finish(); - let mut protobuf = req.protobuf::(); - assert_eq!(protobuf.poll().err().unwrap(), ProtoBufPayloadError::ContentType); + let (req, mut pl) = TestRequest::default().to_http_parts(); + let protobuf = block_on(ProtoBufMessage::::new(&req, &mut pl)); + assert_eq!(protobuf.err().unwrap(), ProtoBufPayloadError::ContentType); - let req = TestRequest::default() + let (req, mut pl) = TestRequest::default() .header( header::CONTENT_TYPE, header::HeaderValue::from_static("application/text"), - ).finish(); - let mut protobuf = req.protobuf::(); - assert_eq!(protobuf.poll().err().unwrap(), ProtoBufPayloadError::ContentType); + ).to_http_parts(); + let protobuf = block_on(ProtoBufMessage::::new(&req, &mut pl)); + assert_eq!(protobuf.err().unwrap(), ProtoBufPayloadError::ContentType); - let req = TestRequest::default() + let (req, mut pl) = TestRequest::default() .header( header::CONTENT_TYPE, header::HeaderValue::from_static("application/protobuf"), ).header( header::CONTENT_LENGTH, header::HeaderValue::from_static("10000"), - ).finish(); - let mut protobuf = req.protobuf::().limit(100); - assert_eq!(protobuf.poll().err().unwrap(), ProtoBufPayloadError::Overflow); + ).to_http_parts(); + let protobuf = block_on(ProtoBufMessage::::new(&req, &mut pl).limit(100)); + assert_eq!(protobuf.err().unwrap(), ProtoBufPayloadError::Overflow); } }