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
## 0.2.0 (2018-04-10)
* Provide protobuf extractor
## 0.1.0 (2018-03-21)
* First release

View File

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

View File

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

View File

@ -12,6 +12,8 @@ extern crate prost;
#[cfg(test)]
#[macro_use] extern crate prost_derive;
use std::fmt;
use std::ops::{Deref, DerefMut};
use bytes::{Bytes, BytesMut};
use futures::{Poll, Future, Stream};
@ -20,11 +22,10 @@ use prost::Message;
use prost::DecodeError as ProtoBufDecodeError;
use prost::EncodeError as ProtoBufEncodeError;
use actix_web::header::http::{CONTENT_TYPE, CONTENT_LENGTH};
use actix_web::{Responder, HttpMessage, HttpRequest, HttpResponse};
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::error::{Error, PayloadError, ResponseError};
use actix_web::httpcodes::{HttpBadRequest, HttpPayloadTooLarge};
#[derive(Fail, Debug)]
@ -50,8 +51,8 @@ impl ResponseError for ProtoBufPayloadError {
fn error_response(&self) -> HttpResponse {
match *self {
ProtoBufPayloadError::Overflow => HttpPayloadTooLarge.into(),
_ => HttpBadRequest.into(),
ProtoBufPayloadError::Overflow => HttpResponse::PayloadTooLarge().into(),
_ => HttpResponse::BadRequest().into(),
}
}
}
@ -68,10 +69,70 @@ impl From<ProtoBufDecodeError> for ProtoBufPayloadError {
}
}
#[derive(Debug)]
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 Error = Error;
@ -82,8 +143,7 @@ impl<T: Message> Responder for ProtoBuf<T> {
.and_then(|()| {
Ok(HttpResponse::Ok()
.content_type("application/protobuf")
.body(buf)
.into())
.body(buf))
})
}
}
@ -178,7 +238,7 @@ impl ProtoBufResponseBuilder for HttpResponseBuilder {
let mut body = Vec::new();
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)]
pub struct MyObject {
#[prost(int32, tag="1")]