Commit 95e1b047 authored by Robert Czechowski's avatar Robert Czechowski
Browse files

Add iron as web framework

parent d5ec6df4
use webfw_iron::{to_json, json_val};
use rusqlite::Connection;
use db_conn::MedalConnection;
pub fn blaa() -> (String, json_val::Map<String, json_val::Value>) {
let mut data = json_val::Map::new();
let mut contests = Vec::new();
contests.push("blaa".to_string());
data.insert("contest".to_string(), to_json(&contests));
("greeting".to_owned(), data)
}
#[derive(Serialize, Deserialize)]
pub struct ContestInfo {
pub id: u32,
pub location: String,
pub filename: String,
pub name: String,
pub duration: u32,
pub public: bool,
}
pub fn show_contests<T: MedalConnection>(conn: &T) -> (String, json_val::Map<String, json_val::Value>) {
let mut data = json_val::Map::new();
let v : Vec<ContestInfo> = conn.get_contest_list().iter().map(|c| { ContestInfo {
id: c.id.unwrap(),
location: c.location.clone(),
filename: c.filename.clone(),
name: c.name.clone(),
duration: c.duration,
public: c.public
}}).collect();
data.insert("contest".to_string(), to_json(&v));
("contests".to_owned(), data)
}
pub fn show_contest<T: MedalConnection>(conn: &T, contest_id: u32) -> (String, json_val::Map<String, json_val::Value>) {
let c = conn.get_contest_by_id(contest_id);
let ci = ContestInfo {
id: c.id.unwrap(),
location: c.location.clone(),
filename: c.filename.clone(),
name: c.name.clone(),
duration: c.duration,
public: c.public
};
let mut data = json_val::Map::new();
data.insert("contest".to_string(), to_json(&ci));
("contest".to_owned(), data)
}
pub fn login<T: MedalConnection>(conn: &T, login_data: (String, String)) -> Result<String, (String, json_val::Map<String, json_val::Value>)> {
let (username, password) = login_data;
match conn.login(None, username.clone(), password) {
Ok(session_token) => {
Ok(session_token)
},
Err(()) => {
let mut data = json_val::Map::new();
data.insert("reason".to_string(), to_json(&"Not implemented".to_string()));
data.insert("username".to_string(), to_json(&username));
Err(("login".to_owned(), data))
}
}
}
pub fn logout<T: MedalConnection>(conn: &T, session_token: Option<String>) -> () {
match session_token {
Some(token) => conn.logout(token), _ => ()
}
}
//?state=42&scope=authenticate&code=250a4f49-e122-4b10-8da0-bc400ba5ea3d
// TOKEN -> {"token_type" : "Bearer","expires" : 3600,"refresh_token" : "R3a716e23-b320-4dab-a529-4c19e6b7ffc5","access_token" : "A6f681904-ded6-4e8b-840e-ac79ca1ffc07"}
// DATA -> {"lastName" : "Czechowski","gender" : "?","userType" : "a","userID" : "12622","dateOfBirth" : "2001-01-01","firstName" : "Robert","eMail" : "czechowski@bwinf.de","schoolId" : -1}
use rand::{thread_rng, Rng};
fn make_session_key() -> String {
thread_rng().gen_ascii_chars().take(10).collect()
}
//extern crate serde;
use std::path::Path;
use iron_sessionstorage::traits::*;
use iron::prelude::*;
use iron::{status, AfterMiddleware};
use iron::modifiers::Redirect;
use mount::Mount;
use router::Router;
use staticfile::Static;
use iron_sessionstorage::SessionStorage;
use iron_sessionstorage::backends::SignedCookieBackend;
use rusqlite::Connection;
use urlencoded::{UrlEncodedBody,UrlEncodedQuery};
use persistent::Write;
use handlebars_iron::{HandlebarsEngine,DirectorySource,Template};
pub use handlebars_iron::handlebars::to_json;
use iron::prelude::*;
use iron_sessionstorage::traits::*;
pub use serde_json::value as json_val;
use iron::typemap::Key;
static DB_FILE: &'static str = "medal.db";
static TASK_DIR: &'static str = "tasks";
macro_rules! mime {
($top:tt / $sub:tt) => (
mime!($top / $sub;)
);
($top:tt / $sub:tt ; $($attr:tt = $val:tt),*) => (
iron::mime::Mime(
iron::mime::TopLevel::$top,
iron::mime::SubLevel::$sub,
vec![ $((Attr::$attr,Value::$val)),* ]
)
);
}
struct ErrorReporter;
impl AfterMiddleware for ErrorReporter {
fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
println!("{}", err);
Err(err)
}
}
struct SessionToken {
token: String
}
impl iron_sessionstorage::Value for SessionToken {
fn get_key() -> &'static str { "medal_session" }
fn into_raw(self) -> String { self.token }
fn from_raw(value: String) -> Option<Self> {
if value.is_empty() {
None
} else {
Some(SessionToken { token: value })
}
}
}
use ::functions;
fn greet(req: &mut Request) -> IronResult<Response> {
// hier ggf. Daten aus dem Request holen
// Daten verarbeiten
let (template, data) = functions::blaa();
// Antwort erstellen und zurücksenden
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
/*
self.session().get::<SessionToken>().unwrap();
self.session().set(SessionToken { token: token.clone() }).unwrap();
*/
fn greet_personal(req: &mut Request) -> IronResult<Response> {
SessionRequestExt::session(req).get::<SessionToken>().unwrap();
// hier ggf. Daten aus dem Request holen
// Daten verarbeiten
let (template, data) = functions::blaa();
// Antwort erstellen und zurücksenden
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn contests(req: &mut Request) -> IronResult<Response> {
let (template, data) = {
// hier ggf. Daten aus dem Request holen
let mutex = req.get::<Write<SharedDatabaseConnection>>().unwrap();
let conn = mutex.lock().unwrap();
// Antwort erstellen und zurücksenden
functions::show_contests(&*conn)
};
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn contest(req: &mut Request) -> IronResult<Response> {
let contest_id = req.extensions.get::<Router>().unwrap().find("contestid").unwrap_or("").parse::<u32>().unwrap_or(0);
let (template, data) = {
// hier ggf. Daten aus dem Request holen
let mutex = req.get::<Write<SharedDatabaseConnection>>().unwrap();
let conn = mutex.lock().unwrap();
// Antwort erstellen und zurücksenden
functions::show_contest(&*conn, contest_id)
};
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn login(_: &mut Request) -> IronResult<Response> {
let mut resp = Response::new();
resp.set_mut(Template::new("login", "".to_owned())).set_mut(status::Ok);
Ok(resp)
}
fn login_post(req: &mut Request) -> IronResult<Response> {
let logindata = {
let formdata = itry!(req.get_ref::<UrlEncodedBody>());
(iexpect!(formdata.get("username"))[0].to_owned(),
iexpect!(formdata.get("password"))[0].to_owned())
};
let loginresult = {
let mutex = req.get::<Write<SharedDatabaseConnection>>().unwrap();
let conn = mutex.lock().unwrap();
// Antwort erstellen und zurücksenden
functions::login(&*conn, logindata)
};
match loginresult {
// Login successful
Ok(sessionkey) => {
req.session().set(SessionToken { token: sessionkey }).unwrap();
Ok(Response::with((status::Found, Redirect(url_for!(req, "greet")))))
},
// Login failed
Err((template, data)) => {
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
}
}
fn logout(req: &mut Request) -> IronResult<Response> {
let session_token = SessionRequestExt::session(req).get::<SessionToken>().unwrap();
{
let mutex = req.get::<Write<SharedDatabaseConnection>>().unwrap();
let conn = mutex.lock().unwrap();
functions::logout(&*conn, (|st: Option<SessionToken>| -> Option<String> {Some(st?.token)}) (session_token));
};
Ok(Response::with((status::Found, Redirect(url_for!(req, "greet")))))
}
// Share Database connection between workers
#[derive(Copy, Clone)]
pub struct SharedDatabaseConnection;
impl Key for SharedDatabaseConnection { type Value = rusqlite::Connection; }
pub fn start_server(conn: Connection) {
let router = router!(
greet: get "/" => greet,
contests: get "/contest" => contests,
contest: get "/contest/:contestid" => contest,
login: get "/login" => login,
login_post: post "/login" => login_post,
logout: post "/logout" => logout,/*
task: get "/task/:taskid" => show_task,
load: get "/load" => load_task,
save: post "/save" => save_task,*/
);
let my_secret = b"verysecret".to_vec();
let mut mount = Mount::new();
// Serve the shared JS/CSS at /
mount.mount("/static/", Static::new(Path::new("static")));
//mount.mount("/tasks/", Static::new(Path::new(TASK_DIR)));
mount.mount("/", router);
let mut ch = Chain::new(mount);
ch.link(Write::<SharedDatabaseConnection>::both(conn));
ch.link_around(SessionStorage::new(SignedCookieBackend::new(my_secret)));
/// HandlebarsEngine will look up all files with "./examples/templates/**/*.hbs"
let mut hbse = HandlebarsEngine::new();
hbse.add(Box::new(DirectorySource::new("./templates/", ".hbs")));
// load templates from all registered sources
if let Err(r) = hbse.reload() {
panic!("{}", r);
}
ch.link_after(hbse);
ch.link_after(ErrorReporter);
let _res = Iron::new(ch).http("[::]:8080");
println!("Listening on 8080.");
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment