1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-01-22 23:05:56 +01:00

add protobuf extractor

This commit is contained in:
Nikolay Kim 2018-04-10 12:40:11 -07:00
parent bf240121b9
commit 69c73c52cd
4 changed files with 81 additions and 23 deletions

View File

@ -1,5 +1,9 @@
# Changes # Changes
## 0.2.0 (2018-04-10)
* Provide protobuf extractor
## 0.1.0 (2018-03-21) ## 0.1.0 (2018-03-21)
* First release * First release

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-protobuf" name = "actix-protobuf"
version = "0.1.0" version = "0.2.0"
authors = ["kingxsp <jin.hb.zh@outlook.com>"] authors = ["kingxsp <jin.hb.zh@outlook.com>"]
description = "Protobuf support for actix-web framework." description = "Protobuf support for actix-web framework."
readme = "README.md" readme = "README.md"
@ -24,7 +24,7 @@ futures = "0.1"
failure = "0.1" failure = "0.1"
actix = "0.5" actix = "0.5"
actix-web = "0.4" actix-web = "0.5"
prost = "0.2" prost = "0.2"

View File

@ -6,8 +6,8 @@ Protobuf support for actix-web framework.
## Example ## Example
```rust,ignore ```rust,ignore
use actix_web::*; use actix_web::HttpResponse;
use actix_protobuf::*; use actix_protobuf::ProtoBuf;
use futures::Future; use futures::Future;
#[derive(Clone, Debug, PartialEq, Message)] #[derive(Clone, Debug, PartialEq, Message)]
@ -18,14 +18,9 @@ pub struct MyObj {
pub name: String, pub name: String,
} }
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> { fn index(msg: ProtoBuf<MyObj>) -> HttpResponse {
req.protobuf()
.from_err() // convert all errors into `Error`
.and_then(|val: MyObj| {
println!("model: {:?}", val); println!("model: {:?}", val);
Ok(httpcodes::HTTPOk.build().protobuf(val)?) // <- send response HttpResponse::Ok().protobuf(val)?) // <- send response
})
.responder()
} }
``` ```

View File

@ -12,6 +12,8 @@ extern crate prost;
#[cfg(test)] #[cfg(test)]
#[macro_use] extern crate prost_derive; #[macro_use] extern crate prost_derive;
use std::fmt;
use std::ops::{Deref, DerefMut};
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use futures::{Poll, Future, Stream}; use futures::{Poll, Future, Stream};
@ -20,11 +22,10 @@ use prost::Message;
use prost::DecodeError as ProtoBufDecodeError; use prost::DecodeError as ProtoBufDecodeError;
use prost::EncodeError as ProtoBufEncodeError; use prost::EncodeError as ProtoBufEncodeError;
use actix_web::header::http::{CONTENT_TYPE, CONTENT_LENGTH}; use actix_web::http::header::{CONTENT_TYPE, CONTENT_LENGTH};
use actix_web::{Responder, HttpMessage, HttpRequest, HttpResponse}; use actix_web::{Responder, HttpMessage, HttpRequest, HttpResponse, FromRequest};
use actix_web::dev::HttpResponseBuilder; use actix_web::dev::HttpResponseBuilder;
use actix_web::error::{Error, PayloadError, ResponseError}; use actix_web::error::{Error, PayloadError, ResponseError};
use actix_web::httpcodes::{HttpBadRequest, HttpPayloadTooLarge};
#[derive(Fail, Debug)] #[derive(Fail, Debug)]
@ -50,8 +51,8 @@ impl ResponseError for ProtoBufPayloadError {
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> HttpResponse {
match *self { match *self {
ProtoBufPayloadError::Overflow => HttpPayloadTooLarge.into(), ProtoBufPayloadError::Overflow => HttpResponse::PayloadTooLarge().into(),
_ => HttpBadRequest.into(), _ => HttpResponse::BadRequest().into(),
} }
} }
} }
@ -68,10 +69,70 @@ impl From<ProtoBufDecodeError> for ProtoBufPayloadError {
} }
} }
#[derive(Debug)]
pub struct ProtoBuf<T: Message>(pub T); pub struct ProtoBuf<T: Message>(pub T);
impl<T: Message> Responder for ProtoBuf<T> { impl<T: Message> Deref for ProtoBuf<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: Message> DerefMut for ProtoBuf<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: Message> fmt::Debug for ProtoBuf<T> where T: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ProtoBuf: {:?}", self.0)
}
}
impl<T: Message> fmt::Display for ProtoBuf<T> where T: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
pub struct ProtoBufConfig {
limit: usize,
}
impl ProtoBufConfig {
/// Change max size of payload. By default max size is 256Kb
pub fn limit(&mut self, limit: usize) -> &mut Self {
self.limit = limit;
self
}
}
impl Default for ProtoBufConfig {
fn default() -> Self {
ProtoBufConfig{limit: 262_144}
}
}
impl<T, S> FromRequest<S> for ProtoBuf<T>
where T: Message + Default + 'static, S: 'static
{
type Config = ProtoBufConfig;
type Result = Box<Future<Item=Self, Error=Error>>;
#[inline]
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
Box::new(
ProtoBufMessage::new(req.clone())
.limit(cfg.limit)
.from_err()
.map(ProtoBuf))
}
}
impl<T: Message + Default> Responder for ProtoBuf<T> {
type Item = HttpResponse; type Item = HttpResponse;
type Error = Error; type Error = Error;
@ -82,8 +143,7 @@ impl<T: Message> Responder for ProtoBuf<T> {
.and_then(|()| { .and_then(|()| {
Ok(HttpResponse::Ok() Ok(HttpResponse::Ok()
.content_type("application/protobuf") .content_type("application/protobuf")
.body(buf) .body(buf))
.into())
}) })
} }
} }
@ -178,7 +238,7 @@ impl ProtoBufResponseBuilder for HttpResponseBuilder {
let mut body = Vec::new(); let mut body = Vec::new();
value.encode(&mut body).map_err(ProtoBufPayloadError::Serialize)?; value.encode(&mut body).map_err(ProtoBufPayloadError::Serialize)?;
Ok(self.body(body)?) Ok(self.body(body))
} }
} }
@ -222,7 +282,6 @@ mod tests {
} }
} }
#[derive(Clone, Debug, PartialEq, Message)] #[derive(Clone, Debug, PartialEq, Message)]
pub struct MyObject { pub struct MyObject {
#[prost(int32, tag="1")] #[prost(int32, tag="1")]