implement static file download

Fully async using futures and stream.
This commit is contained in:
Dietmar Maurer 2018-11-11 15:54:05 +01:00
parent cec9f02ebc
commit 579fbe7dc8
1 changed files with 55 additions and 17 deletions

View File

@ -13,8 +13,12 @@ use apitest::json_schema::*;
//use serde_derive::{Serialize, Deserialize}; //use serde_derive::{Serialize, Deserialize};
use serde_json::{json, Value}; use serde_json::{json, Value};
use tokio::prelude::*; use futures::future::*;
use tokio::timer::Delay; //use tokio::prelude::*;
//use tokio::timer::Delay;
use tokio::fs::File;
use tokio_codec;
//use bytes::{BytesMut, BufMut};
//use hyper::body::Payload; //use hyper::body::Payload;
use hyper::http::request::Parts; use hyper::http::request::Parts;
@ -23,9 +27,7 @@ use hyper::rt::{Future, Stream};
use hyper::service::service_fn; use hyper::service::service_fn;
use hyper::header; use hyper::header;
use futures::future::*; //use std::time::{Duration, Instant};
use std::time::{Duration, Instant};
type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>; type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
@ -163,6 +165,33 @@ fn handle_sync_api_request<'a>(
Box::new(resp) Box::new(resp)
} }
fn handle_static_file_download(filename: PathBuf) -> BoxFut {
let response = File::open(filename)
.and_then(|file| {
let payload = tokio_codec::FramedRead::new(file, tokio_codec::BytesCodec::new()).
map(|bytes| {
//sigh - howto avoid copy here? or the whole map() ??
hyper::Chunk::from(bytes.to_vec())
});
let body = Body::wrap_stream(payload);
// fixme: set content type and other headers
Ok(Response::builder()
.status(StatusCode::OK)
.body(body)
.unwrap())
})
.or_else(|err| {
// fixme: set content type and other headers
Ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(format!("File access problems: {}\n", err).into())
.unwrap())
});
return Box::new(response);
}
fn handle_request(req: Request<Body>) -> BoxFut { fn handle_request(req: Request<Body>) -> BoxFut {
let (parts, body) = req.into_parts(); let (parts, body) = req.into_parts();
@ -170,8 +199,14 @@ fn handle_request(req: Request<Body>) -> BoxFut {
let method = parts.method.clone(); let method = parts.method.clone();
let path = parts.uri.path(); let path = parts.uri.path();
// normalize path
let components: Vec<&str> = path.split('/').filter(|x| !x.is_empty()).collect(); let components: Vec<&str> = path.split('/').filter(|x| !x.is_empty()).collect();
let comp_len = components.len(); let comp_len = components.len();
let path = components.iter().fold(String::new(), |mut acc, chunk| {
acc.push('/');
acc.push_str(chunk);
acc
});
println!("REQUEST {} {}", method, path); println!("REQUEST {} {}", method, path);
println!("COMPO {:?}", components); println!("COMPO {:?}", components);
@ -202,14 +237,19 @@ fn handle_request(req: Request<Body>) -> BoxFut {
//return handle_sync_api_request(api_method, parts, body); //return handle_sync_api_request(api_method, parts, body);
return handle_async_api_request(api_method, parts, body); return handle_async_api_request(api_method, parts, body);
} else {
http_error_future!(NOT_FOUND, "Path not found.");
} }
} }
} }
Box::new(ok(Response::new(Body::from("RETURN WEB GUI\n")))) // not Auth for accessing files!
if let Some(filename) = CACHED_DIRS.get(&path) {
println!("SERVER STATIC FILE {:?}", path);
return handle_static_file_download(filename.clone());
}
http_error_future!(NOT_FOUND, "Path not found.")
//Box::new(ok(Response::new(Body::from("RETURN WEB GUI\n"))))
} }
// add default dirs which includes jquery and bootstrap // add default dirs which includes jquery and bootstrap
@ -218,8 +258,8 @@ fn handle_request(req: Request<Body>) -> BoxFut {
// add_dirs($self->{dirs}, '/js/' => "$base/js/"); // add_dirs($self->{dirs}, '/js/' => "$base/js/");
// add_dirs($self->{dirs}, '/fonts/' => "$base/fonts/"); // add_dirs($self->{dirs}, '/fonts/' => "$base/fonts/");
use std::io; //use std::io;
use std::fs::{self, DirEntry}; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
fn add_dirs(cache: &mut HashMap<String, PathBuf>, alias: String, path: &Path) -> Result<(), Error> { fn add_dirs(cache: &mut HashMap<String, PathBuf>, alias: String, path: &Path) -> Result<(), Error> {
@ -254,7 +294,9 @@ fn initialize_directory_cache() -> HashMap<String, PathBuf> {
let mut cache = HashMap::new(); let mut cache = HashMap::new();
add_dirs(&mut cache, "/pve2/ext6/".into(), basedirs["extjs"]); if let Err(err) = add_dirs(&mut cache, "/pve2/ext6/".into(), basedirs["extjs"]) {
eprintln!("directory cache init error: {}", err);
}
cache cache
} }
@ -270,11 +312,7 @@ lazy_static!{
fn main() { fn main() {
println!("Fast Static Type Definitions 1"); println!("Fast Static Type Definitions 1");
let mut count = 0; let count = CACHED_DIRS.iter().count();
for (k, v) in CACHED_DIRS.iter() {
println!("DIRCACHE: {:?} => {:?}", k, v);
count += 1;
}
println!("Dircache contains {} entries.", count); println!("Dircache contains {} entries.", count);
let addr = ([127, 0, 0, 1], 8007).into(); let addr = ([127, 0, 0, 1], 8007).into();