Skip to content

Commit 7eca445

Browse files
aaronriekenbergseanmonstar
authored andcommitted
docs(examples): Update send_file example to use tokio-fs
1 parent 14d9246 commit 7eca445

File tree

3 files changed

+26
-89
lines changed

3 files changed

+26
-89
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ num_cpus = "1.0"
4343
pretty_env_logger = "0.2.0"
4444
spmc = "0.2"
4545
url = "1.0"
46+
tokio-fs = "0.1"
4647
tokio-mockstream = "1.1.0"
4748

4849
[features]

examples/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ Run examples with `cargo run --example example_name`.
1414

1515
* [`params`](params.rs) - A webserver that accept a form, with a name and a number, checks the parameters are presents and validates the input.
1616

17-
* [`send_file`](send_file.rs) - A server that sends back content of files either simply or streaming the response.
17+
* [`send_file`](send_file.rs) - A server that sends back content of files using tokio_fs to read the files asynchronously.
1818

1919
* [`web_api`](web_api.rs) - A server consisting in a service that returns incoming POST request's content in the response in uppercase and a service that call that call the first service and includes the first service response in its own response.

examples/send_file.rs

+24-88
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
22
extern crate futures;
33
extern crate hyper;
44
extern crate pretty_env_logger;
5+
extern crate tokio_fs;
6+
extern crate tokio_io;
57

68
use futures::{future, Future};
7-
use futures::sync::oneshot;
89

910
use hyper::{Body, Method, Request, Response, Server, StatusCode};
1011
use hyper::service::service_fn;
1112

12-
use std::fs::File;
13-
use std::io::{self, copy/*, Read*/};
14-
use std::thread;
13+
use std::io;
1514

1615
static NOTFOUND: &[u8] = b"Not Found";
1716
static INDEX: &str = "examples/send_file_index.html";
@@ -35,58 +34,9 @@ type ResponseFuture = Box<Future<Item=Response<Body>, Error=io::Error> + Send>;
3534

3635
fn response_examples(req: Request<Body>) -> ResponseFuture {
3736
match (req.method(), req.uri().path()) {
38-
(&Method::GET, "/") | (&Method::GET, "/index.html") => {
37+
(&Method::GET, "/") | (&Method::GET, "/index.html") | (&Method::GET, "/big_file.html") => {
3938
simple_file_send(INDEX)
4039
},
41-
(&Method::GET, "/big_file.html") => {
42-
// Stream a large file in chunks. This requires a
43-
// little more overhead with two channels, (one for
44-
// the response future, and a second for the response
45-
// body), but can handle arbitrarily large files.
46-
//
47-
// We use an artificially small buffer, since we have
48-
// a small test file.
49-
let (tx, rx) = oneshot::channel();
50-
thread::spawn(move || {
51-
let _file = match File::open(INDEX) {
52-
Ok(f) => f,
53-
Err(_) => {
54-
tx.send(Response::builder()
55-
.status(StatusCode::NOT_FOUND)
56-
.body(NOTFOUND.into())
57-
.unwrap())
58-
.expect("Send error on open");
59-
return;
60-
},
61-
};
62-
let (_tx_body, rx_body) = Body::channel();
63-
let res = Response::new(rx_body.into());
64-
tx.send(res).expect("Send error on successful file read");
65-
/* TODO: fix once we have futures 0.2 Sink working
66-
let mut buf = [0u8; 16];
67-
loop {
68-
match file.read(&mut buf) {
69-
Ok(n) => {
70-
if n == 0 {
71-
// eof
72-
tx_body.close().expect("panic closing");
73-
break;
74-
} else {
75-
let chunk: Chunk = buf[0..n].to_vec().into();
76-
match tx_body.send_data(chunk).wait() {
77-
Ok(t) => { tx_body = t; },
78-
Err(_) => { break; }
79-
};
80-
}
81-
},
82-
Err(_) => { break; }
83-
}
84-
}
85-
*/
86-
});
87-
88-
Box::new(rx.map_err(|e| io::Error::new(io::ErrorKind::Other, e)))
89-
},
9040
(&Method::GET, "/no_file.html") => {
9141
// Test what happens when file cannot be be found
9242
simple_file_send("this_file_should_not_exist.html")
@@ -102,42 +52,28 @@ fn response_examples(req: Request<Body>) -> ResponseFuture {
10252
}
10353

10454
fn simple_file_send(f: &str) -> ResponseFuture {
105-
// Serve a file by reading it entirely into memory. As a result
106-
// this is limited to serving small files, but it is somewhat
107-
// simpler with a little less overhead.
108-
//
109-
// On channel errors, we panic with the expect method. The thread
110-
// ends at that point in any case.
55+
// Serve a file by asynchronously reading it entirely into memory.
56+
// Uses tokio_fs to open file asynchronously, then tokio_io to read into
57+
// memory asynchronously.
11158
let filename = f.to_string(); // we need to copy for lifetime issues
112-
let (tx, rx) = oneshot::channel();
113-
thread::spawn(move || {
114-
let mut file = match File::open(filename) {
115-
Ok(f) => f,
116-
Err(_) => {
117-
tx.send(Response::builder()
118-
.status(StatusCode::NOT_FOUND)
119-
.body(NOTFOUND.into())
120-
.unwrap())
121-
.expect("Send error on open");
122-
return;
123-
},
124-
};
125-
let mut buf: Vec<u8> = Vec::new();
126-
match copy(&mut file, &mut buf) {
127-
Ok(_) => {
128-
let res = Response::new(buf.into());
129-
tx.send(res).expect("Send error on successful file read");
130-
},
131-
Err(_) => {
132-
tx.send(Response::builder()
59+
Box::new(tokio_fs::file::File::open(filename)
60+
.and_then(|file| {
61+
let buf: Vec<u8> = Vec::new();
62+
tokio_io::io::read_to_end(file, buf)
63+
.and_then(|item| {
64+
Ok(Response::new(item.1.into()))
65+
})
66+
.or_else(|_| {
67+
Ok(Response::builder()
13368
.status(StatusCode::INTERNAL_SERVER_ERROR)
13469
.body(Body::empty())
13570
.unwrap())
136-
.expect("Send error on error reading file");
137-
},
138-
};
139-
});
140-
141-
Box::new(rx.map_err(|e| io::Error::new(io::ErrorKind::Other, e)))
71+
})
72+
})
73+
.or_else(|_| {
74+
Ok(Response::builder()
75+
.status(StatusCode::NOT_FOUND)
76+
.body(NOTFOUND.into())
77+
.unwrap())
78+
}))
14279
}
143-

0 commit comments

Comments
 (0)