|
4 | 4 | [](https://docs.rs/stream-body) |
5 | 5 | [](./LICENSE) |
6 | 6 |
|
7 | | -An [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) implementation which supports streaming for the Rust HTTP library [hyper](https://hyper.rs/). |
| 7 | +An [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) implementation with efficient streaming support for the Rust HTTP library [hyper](https://hyper.rs/). |
8 | 8 |
|
9 | 9 | [Docs](https://docs.rs/stream-body) |
10 | 10 |
|
11 | | -## Example |
| 11 | +## Motivation |
12 | 12 |
|
| 13 | +The existing [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html) type in [hyper](https://hyper.rs/) uses [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) |
| 14 | +as streaming chunk. Hence, a lot of buffer allocation and de-allocation happen during the real-time large data streaming because of the [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) type. |
| 15 | +Therefore, `StreamBody` comes to tackle this kind of situation. The `StreamBody` implements [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) and uses `&[u8]` |
| 16 | +slice as the streaming chunk, so it is possible to use the same buffer without allocating a new one; hence it overcomes any allocation/de-allocation overhead. |
| 17 | + |
| 18 | +Also, the [channel()](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html#method.channel) method in hyper [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html) returns |
| 19 | +a pair of a [Sender](https://docs.rs/hyper/0.13.4/hyper/body/struct.Sender.html) and a [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html). |
| 20 | +Here, the [Sender](https://docs.rs/hyper/0.13.4/hyper/body/struct.Sender.html) accepts [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) as a data chunk which again |
| 21 | +creates allocation/de-allocation overhead. |
| 22 | +To solve this, `StreamBody` has a method named `StreamBody::channel()` which returns a pair of an [AsyncWrite](https://docs.rs/tokio/0.2.16/tokio/io/trait.AsyncWrite.html) and the `StreamBody` |
| 23 | +itself. As the [AsyncWrite](https://docs.rs/tokio/0.2.16/tokio/io/trait.AsyncWrite.html) accepts `&[u8]` instead of [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html), there will |
| 24 | +be no allocation/de-allocation overhead. |
| 25 | + |
| 26 | +## Usage |
| 27 | + |
| 28 | +First add this to your Cargo.toml: |
| 29 | + |
| 30 | +```toml |
| 31 | +[dependencies] |
| 32 | +stream-body = "0.1" |
| 33 | +``` |
| 34 | + |
| 35 | +An example on handling a large file: |
13 | 36 | ```rust |
14 | | -use stream_body; |
| 37 | +use hyper::service::{make_service_fn, service_fn}; |
| 38 | +use hyper::{Body, Request, Response, Server}; |
| 39 | +use std::{convert::Infallible, net::SocketAddr}; |
| 40 | +use stream_body::StreamBody; |
| 41 | +use tokio::fs::File; |
| 42 | +use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
| 43 | + |
| 44 | +async fn handle(_: Request<Body>) -> Result<Response<StreamBody>, Infallible> { |
| 45 | + let (mut writer, body) = StreamBody::channel(); |
| 46 | + |
| 47 | + tokio::spawn(async move { |
| 48 | + let mut f = File::open("large-file").await.unwrap(); |
| 49 | + |
| 50 | + // Reuse this buffer |
| 51 | + let mut buf = [0_u8; 1024 * 16]; |
| 52 | + loop { |
| 53 | + let read_count = f.read(&mut buf).await.unwrap(); |
| 54 | + if read_count == 0 { |
| 55 | + break; |
| 56 | + } |
| 57 | + writer.write_all(&buf[..read_count]).await.unwrap(); |
| 58 | + } |
| 59 | + }); |
| 60 | + |
| 61 | + Ok(Response::builder().body(body).unwrap()) |
| 62 | +} |
| 63 | + |
| 64 | +#[tokio::main] |
| 65 | +async fn main() { |
| 66 | + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); |
| 67 | + |
| 68 | + let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle)) }); |
| 69 | + |
| 70 | + let server = Server::bind(&addr).serve(make_svc); |
15 | 71 |
|
| 72 | + if let Err(e) = server.await { |
| 73 | + eprintln!("server error: {}", e); |
| 74 | + } |
| 75 | +} |
16 | 76 | ``` |
17 | 77 |
|
18 | 78 | ## Contributing |
|
0 commit comments