sharp_pencil/
serving.rs

1//! This module implements the http server support for our application.
2
3use std::{net::ToSocketAddrs, path::PathBuf, sync::Arc, sync::RwLock};
4use std::fmt::Write;
5
6use handlebars::{Handlebars, TemplateFileError};
7use hyper::server::Server;
8use notify::{Error as NotifyError, Event, EventFn, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
9use Pencil;
10
11fn handle_modify(paths: &[PathBuf], registry: &RwLock<Handlebars<'_>>) {
12    for path in paths {
13        if let Some(fname) = path.file_name() {
14            let mut write_guard = registry.write().unwrap();
15            let fname = fname.to_str().unwrap();
16            let compile_result = write_guard.register_template_file(fname, &path);
17            if let Err(TemplateFileError::TemplateError(err)) = compile_result {
18                let mut msg = "Template syntax error:".to_owned();
19                if let Some(line_no) = err.line_no {
20                    write!(msg, " line no: {}", line_no).unwrap();
21                }
22                if let Some(col_no) = err.column_no {
23                    write!(msg, " col no: {}", col_no).unwrap();
24                }
25                write!(msg, " cause: {}", err.reason).unwrap();
26                warn!("{}", msg);
27                write_guard.register_template_string(fname, msg).unwrap();
28            } else {
29                info!("Registered template {}", fname);
30            }
31        }
32    }
33}
34
35fn watch_files(registry: Arc<RwLock<Handlebars<'static>>>) -> impl EventFn {
36    move |event: Result<Event, NotifyError>| match event {
37        Ok(Event { kind: EventKind::Create(_), paths, ..}) => handle_modify(&paths, &registry),
38        Ok(Event { kind: EventKind::Modify(_), paths, ..}) => handle_modify(&paths, &registry),
39        Err(e) => warn!("template watch error: {:?}", e),
40        _ => (),
41    }
42}
43
44
45/// Run the `Pencil` application.
46pub fn run_server<A: ToSocketAddrs>(application: Pencil, addr: A, threads: usize) {
47
48    let mut watcher: RecommendedWatcher;
49    if application.template_debug {
50        let registry = application.handlebars_registry.clone();
51        let template_dir = application.template_folder.clone();
52        watcher = Watcher::new_immediate(watch_files(registry)).unwrap();
53        info!("Begin watching {}", &template_dir);
54        watcher.watch(&template_dir, RecursiveMode::Recursive).unwrap();
55    }
56
57    let server = Server::http(addr).unwrap();
58    let _guard = server.handle_threads(application, threads).unwrap();
59}