extern crate getopts; extern crate pencil; extern crate modelthing; extern crate env_logger; extern crate pulldown_cmark; #[macro_use] extern crate log; use std::env; use std::collections::BTreeMap; use std::path::Path; use getopts::Options; use pencil::Pencil; use pencil::{Request, PencilResult, Response, HTTPError, PencilError}; /* This command doesn't use error_chain (or raise errors in general) because the web framework handles panics as 500 errors automatically. */ fn home(r: &mut Request) -> PencilResult { let context: BTreeMap = BTreeMap::new(); return r.app.render_template("home.html", &context); } fn readme(r: &mut Request) -> PencilResult { let mut context = BTreeMap::new(); let raw_text = include_str!("../../README.txt"); context.insert("raw_text".to_string(), raw_text.to_string()); return r.app.render_template("raw.html", &context); } fn model_list(r: &mut Request) -> PencilResult { let namespace = r.view_args.get("namespace").unwrap(); let paths = modelthing::search_models(Path::new(namespace)); let l: Vec> = paths.iter() .map(|x| vec![namespace.to_string(), Path::new(x).strip_prefix(namespace) .unwrap() .to_string_lossy() .to_string() ]) .collect(); let mut context = BTreeMap::new(); context.insert("model_slug_list".to_string(), l); return r.app.render_template("model_list.html", &context); } fn model_view(r: &mut Request) -> PencilResult { let namespace = r.view_args.get("namespace").unwrap(); let model_slug = r.view_args.get("model_slug").unwrap(); let model_path = Path::new(namespace).join(model_slug); match modelthing::load_model_entry(model_path.as_path()) { Ok(me) => { let mut markdown_html = String::new(); let p = pulldown_cmark::Parser::new_ext( &me.markdown, pulldown_cmark::Options::empty()); pulldown_cmark::html::push_html(&mut markdown_html, p); let mut context = BTreeMap::new(); context.insert("namespace".to_string(), namespace.to_string()); context.insert("model_slug".to_string(), model_slug.to_string()); context.insert("model_name".to_string(), me.ast.name.clone()); context.insert("model_description".to_string(), me.ast.description.clone().unwrap_or("".to_string())); context.insert("markdown_html".to_string(), markdown_html); context.insert("markdown".to_string(), me.markdown.clone()); context.insert("modelica".to_string(), format!("{:?}", me.ast)); r.app.render_template("model_view.html", &context) }, Err(_) => Err(PencilError::PenHTTPError(pencil::HTTPError::NotFound)), } } // Sends the modelica file fn model_raw(r: &mut Request) -> PencilResult { let namespace = r.view_args.get("namespace").unwrap(); let model_slug = r.view_args.get("model_slug").unwrap(); let model_path = Path::new(namespace).join(model_slug).to_string_lossy().to_string(); pencil::helpers::send_from_directory(&model_path, "model.modelica", true) } fn page_not_found(_: HTTPError) -> PencilResult { let mut response = Response::from("404: Not Found"); response.status_code = 404; Ok(response) } fn server_error(_: HTTPError) -> PencilResult { let mut response = Response::from("500: Server Error"); response.status_code = 500; Ok(response) } fn print_usage(opts: Options) { let brief = "usage:\tmt-webface [options]"; println!(""); print!("{}", opts.usage(&brief)); } fn main() { let args: Vec = env::args().collect(); let mut opts = Options::new(); opts.optflag("h", "help", "print this help menu"); opts.optflag("b", "bind", "local IP:port to bind to"); opts.optflag("", "version", "print the version"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, Err(f) => { println!("{}\n", f.to_string()); print_usage(opts); ::std::process::exit(-1); } }; if matches.opt_present("help") { print_usage(opts); return; } if matches.opt_present("version") { println!("modelthing {}", env!("CARGO_PKG_VERSION")); return; } env_logger::init().unwrap(); let mut app = Pencil::new("webface"); app.name = "modelthing-webface".to_string(); app.set_debug(true); app.set_log_level(); app.httperrorhandler(404, page_not_found); app.httperrorhandler(500, server_error); app.enable_static_file_handling(); debug!("root_path: {}", app.root_path); app.register_template("base.html"); app.register_template("home.html"); app.register_template("raw.html"); app.get("/", "home", home); app.get("/readme/", "readme", readme); app.register_template("model_list.html"); app.get("/m//", "model_list", model_list); app.register_template("model_view.html"); app.get("/m///", "model_view", model_view); app.get("/m///raw/", "model_raw", model_raw); let bind = matches.opt_str("bind").unwrap_or("127.0.0.1:5000".to_string()); let bind_str: &str = &bind; info!("Running on {}", bind); app.run(bind_str); }