108 lines
3.7 KiB
Rust
108 lines
3.7 KiB
Rust
#[macro_use] extern crate nickel;
|
|
extern crate rustc_serialize;
|
|
extern crate handlebars;
|
|
|
|
use nickel::{Nickel, HttpRouter, FormBody};
|
|
use std::io;
|
|
use std::sync::{Arc, Mutex};
|
|
mod todo;
|
|
mod store;
|
|
mod template;
|
|
|
|
// Lets us type `Add("Todo item".to_string())` instead of `TodoAction::Add("Todo item".to_string())
|
|
use todo::TodoAction::{ Add, Remove, Toggle };
|
|
|
|
// Same with the Action enum and VisibilityFilter, Action::* would work too, but this way we list what we use
|
|
use store::Action::{ Todos, Visibility };
|
|
use store::VisibilityFilter::{ ShowActive, ShowAll, ShowCompleted };
|
|
use todo::{Todo};
|
|
use store::{ Store, State, reducer };
|
|
use template::render;
|
|
|
|
fn main() {
|
|
let mut server = Nickel::new();
|
|
|
|
// Create our todo list store
|
|
let mut store = Store::create_store(reducer);
|
|
|
|
// Add some todos so we've got something to remember
|
|
store.dispatch( Todos( Add("one thing".to_string()) ) );
|
|
store.dispatch( Todos( Add("another thing".to_string()) ) );
|
|
|
|
// Put the store in a container that will let us
|
|
// safely use it in multi-threaded environment
|
|
let store_container = Arc::new( Mutex::new(store) );
|
|
|
|
// Every clone of our container is counted
|
|
// so that when the last clone goes out of scope
|
|
// the container can be deallocated
|
|
let store = store_container.clone();
|
|
|
|
// At the / path let's just render our current todo list
|
|
server.get("/", middleware! { |_req, res|
|
|
// We get our store from the container by locking it
|
|
// from other threads
|
|
let store = store.lock().unwrap();
|
|
|
|
// Render from nickel_mustache takes the
|
|
// nickel Result struct, a path to a mustache
|
|
// template, and the data to use
|
|
return render(res, "./src/todos.tpl", store.get_state())
|
|
// And here the lock is released...
|
|
});
|
|
|
|
// Let's clone it again for the next closure
|
|
let store = store_container.clone();
|
|
|
|
// This time we look for requests like /toggle/1
|
|
server.get("/:action/:id", middleware! { |_req, res|
|
|
// We will dispatch an action on our store so we
|
|
// get a mutable reference
|
|
let mut store = store.lock().unwrap();
|
|
|
|
// We try to parse the id param to an int, this words for the
|
|
// toggle and remove actions
|
|
if let Ok(num) = _req.param("id").unwrap().parse::<i16>() {
|
|
match _req.param("action").unwrap() {
|
|
"toggle" => {
|
|
store.dispatch( Todos( Toggle(num) ) )
|
|
},
|
|
"remove" => store.dispatch( Todos ( Remove(num) ) ),
|
|
_ => (),
|
|
}
|
|
} else {
|
|
// Otherwise look for a show action
|
|
match _req.param("action").unwrap() {
|
|
"show" => {
|
|
match _req.param("id").unwrap() {
|
|
"all" => store.dispatch( Visibility(ShowAll) ),
|
|
"active" => store.dispatch( Visibility(ShowActive) ),
|
|
"completed" => store.dispatch( Visibility(ShowCompleted) ),
|
|
_ => (),
|
|
}
|
|
},
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
// And render the now updated todo list
|
|
return render(res, "./src/todos.tpl", store.get_state())
|
|
});
|
|
|
|
// Let's clone it again for the next closure
|
|
let store = store_container.clone();
|
|
|
|
server.post("/*", middleware! { |req, res|
|
|
let mut store = store.lock().unwrap();
|
|
let form_body = req.form_body().ok().unwrap();
|
|
if let Some(new_todo) = form_body.get("todo") {
|
|
if new_todo.len() > 0 {
|
|
store.dispatch( Todos( Add(new_todo.to_string()) ) );
|
|
}
|
|
}
|
|
|
|
return render(res, "./src/todos.tpl", store.get_state())
|
|
});
|
|
|
|
server.listen("0.0.0.0:3000");
|
|
} |