#[macro_use]
extern crate log;
extern crate mxo_env_logger;
extern crate tokio_core;
extern crate futures;
extern crate futures_cpupool;
extern crate hyper;
extern crate url;
extern crate num_cpus;
use mxo_env_logger::*;
use futures_cpupool::{Builder,CpuPool};
use tokio_core::reactor::{Core,Handle};
use tokio_core::net::TcpListener;
use futures::{future,Stream};
use hyper::server::{Http, Request, Response, Service};
use hyper::{header, StatusCode, Error};
extern crate hyper_fs;
use hyper_fs::{Config, StaticFs, FutureObject};
use std::path::PathBuf;
use std::sync::Arc;
use std::rc::Rc;
use std::env;
use std::fs;
fn main() {
init().expect("Init Log Failed");
let port = env::args()
.nth(1)
.and_then(|arg| arg.parse().ok())
.unwrap_or(8000u16);
let addr = format!("0.0.0.0:{}", port).parse().unwrap();
let pool = Builder::new().pool_size(3).name_prefix("hyper-fs").create();
let config = Config::new().cache_secs(60).follow_links(true).show_index(true);
let mut core = Core::new().unwrap();
let handle = core.handle();
let listener = TcpListener::bind(&addr, &handle).unwrap();
let doc = Doge::new( handle.clone(), pool, config);
let http = Http::new();
let server = listener.incoming().for_each(|(socket, addr)| {
http.bind_connection(&handle, socket, addr, doc.clone());
Ok(())
});
println!("Listening on http://{} with 1 thread.", addr);
core.run(server).unwrap();
}
pub struct DogeInner {
doc:Option< PathBuf>, rust:Option<PathBuf>, path: PathBuf, pool:CpuPool,
handle: Handle,
config: Arc<Config>
}
#[derive(Clone)]
pub struct Doge{
inner: Rc<DogeInner>,
}
impl Doge {
fn new(handle: Handle, pool: CpuPool, config: Config)->Self {
let doc = PathBuf::from("target/doc");
let doc = if doc.as_path().is_dir() {
Some(doc)
} else {
None
};
let path =PathBuf::from(env::args().nth(2).unwrap_or("./".to_owned()));
let inner = DogeInner{
doc:doc,
rust: rust(),
path:path,
pool:pool,
handle:handle,
config:Arc::new(config)
};
Doge{
inner: Rc::new(inner),
}
}
}
fn rust()->Option<PathBuf> {
let mut r = PathBuf::from(env::var("HOME").unwrap());
r.push(".rustup/toolchains/");
if let Ok(entrys) = fs::read_dir(&r) {
let entrys = entrys.filter_map(|e|e.ok()).collect::<Vec<_>>();
for entry in entrys {
let mut path =entry.path();
path.push("share/doc/rust/html");
if path.is_dir() {
return Some(path);
}
}
}
None
}
impl Service for Doge
{
type Request = Request;
type Response = Response;
type Error = Error;
type Future = FutureObject;
fn call(&self, req: Request) -> Self::Future {
let path = req.path().to_owned();
if self.inner.doc.is_some()&& (path.starts_with("/doc/") || path.as_str() =="/doc") {
StaticFs::new(self.inner.handle.clone(), self.inner.pool.clone(),"/doc/", self.inner.doc.as_ref().unwrap(),self.inner.config.clone()).call(req)
} else if self.inner.rust.is_some()&& path.as_str()=="/rust" {
Box::new(
future::ok(
Response::new()
.with_status(StatusCode::MovedPermanently)
.with_header(header::Location::new("/rust/index.html")),
))
} else if self.inner.rust.is_some()&& path.starts_with("/rust/") {
StaticFs::new(self.inner.handle.clone(), self.inner.pool.clone(),"/rust/", self.inner.rust.as_ref().unwrap(),self.inner.config.clone()).call(req)
}
else {
StaticFs::new(self.inner.handle.clone(), self.inner.pool.clone(),"/", self.inner.path.clone(),self.inner.config.clone()).call(req)
}
}
}