diff --git a/Cargo.toml b/Cargo.toml
index 95e27e0..5bda36a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,9 +21,12 @@ byteorder = "0.3"
bincode = "0.4.0"
docopt = "0.6"
rustc-serialize = "0.3"
+nickel = "*"
+plugin = "*"
+typemap = "*"
+hyper = "*"
+cookie = "0.1"
+url = "*"
[dependencies.server]
path = "server"
-
-[dependencies.iron]
-version = "*"
diff --git a/src/webclient/main.rs b/src/webclient/main.rs
index c0a0e20..b6137c9 100644
--- a/src/webclient/main.rs
+++ b/src/webclient/main.rs
@@ -1,88 +1,208 @@
-extern crate iron;
+#[macro_use]
+extern crate nickel;
+extern crate plugin;
+extern crate typemap;
+extern crate hyper;
extern crate uosql;
+extern crate rustc_serialize;
+extern crate cookie;
+extern crate url;
-use iron::prelude::*;
-use iron::status;
use uosql::Connection;
+use std::io::Read;
use uosql::Error;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ops::DerefMut;
use std::sync::{Arc, Mutex};
+use plugin::Extensible;
+use hyper::header::{Cookie, SetCookie};
+use nickel::{Nickel, HttpRouter};
+use cookie::Cookie as CookiePair;
+use hyper::method::Method;
+use url::form_urlencoded as urlencode;
+
+// Dummy key for typemap
+struct ConnKey;
+impl typemap::Key for ConnKey {
+ type Value = Arc>;
+}
+
+#[derive(Debug)]
+struct Login {
+ user : String,
+ password: String
+}
+
/// Web based client
fn main() {
- // Key Value pairs: User + connections
- // Every user has one connection
- let map: HashMap = HashMap::new();
- let ptr = Arc::new(Mutex::new(map));
+ let mut server = Nickel::new();
+ let map: HashMap>>= HashMap::new();
+ let map = Arc::new(Mutex::new(map));
+ let map2 = map.clone();
+
+ // Cookie managing
+ server.utilize(middleware! { |req, res|
+
+ // If login data has been posted, continue
+ if req.origin.method == Method::Post {
+ return Ok(nickel::Action::Continue(res));
+ }
+
+ // Look for session string in Cookies
+ let sess = match req.origin.headers.get::() {
+ // If no Cookie found, go to Login
+ None => {
+ let m = HashMap::::new();
+ return res.render("src/webclient/templates/login.tpl", &m);
+ }
+ // If there is a Cookie, eat it
+ // (or find the matching UosqlDB-Cookie and extract session string)
+ Some(cs) => {
+ if let Some(sess) = cs.to_cookie_jar(&[1u8]).find("UosqlDB") {
+ sess.value
+ // There is a cookie, but it is not ours :'(
+ // Return to Login
+ } else {
+ let m = HashMap::::new();
+ return res.render("src/webclient/templates/login.tpl", &m);
+ }
+ },
+ };
+
+ // We have a session string and look for the matching connection in
+ // our Session-Connection map
+ let guard = map.lock().unwrap();
+ match guard.get(&sess) {
+ // No matching session: Old cookie
+ None => {
+ let mut data = HashMap::new();
+ data.insert("err_msg", "Invalid Session");
+ return res.render("src/webclient/templates/login.tpl", &data);
+ }
+ // There is a connection, we are logged in, we can enter the site!
+ Some(con) => {
+ req.extensions_mut().insert::(con.clone());
+ return Ok(nickel::Action::Continue(res));
+ }
+ }
+ });
+
+ // Login managing
+ server.post("/login", middleware! { |req, mut res|
+
+ // Read the post data
+ let mut login_data = String::new();
+ let read = req.origin.read_to_string(&mut login_data).unwrap();
+
+ // Not sufficiently filled in, return to Login with error msg
+ if read < 15 {
+ let mut data = HashMap::new();
+ data.insert("err_msg", "No data given");
+ return res.render("src/webclient/templates/login.tpl", &data);
+ }
+
+ // Extract login data from Post string
+ let pairs = urlencode::parse(login_data.as_bytes());
+ let username = pairs.iter().find(|e| e.0 == "user").map(|e| e.1.clone());
+ let password = pairs.iter().find(|e| e.0 == "password").map(|e| e.1.clone());
+
+ // If eihter username or password are empty, return to Login page
+ if username.is_none() || password.is_none() {
+ let mut data = HashMap::new();
+ data.insert("err_msg", "Not all required fields given");
+ return res.render("src/webclient/templates/login.tpl", &data);
+ }
+
+ // build Login struct
+ let login = Login {
+ user: username.unwrap(),
+ password: password.unwrap()
+ };
+
+ // Generate new session string
+ let sess_str = login.user.clone(); // Dummy
- let mut chain = Chain::new(move |_: &mut Request| {
- let own = ptr.clone();
- // Locked until guard dies
- let mut guard = own.lock().unwrap();
+ // Try connect to db server
+ // Insert connection and session string into hashmap
+ let mut guard = map2.lock().unwrap();
-//==================== TODO Read user data input somehow ==========================//
- // Get login data
- let username = "Peter".to_string();
+ // DUMMY DATA
let connection = "127.0.0.1".to_string();
let port = 4242;
- let password = "Bob".to_string();
- // Get connection of user or build new connection and insert it into
- // hashmap
- let con = match guard.deref_mut().entry(username.clone()) {
- Entry::Occupied(o) => o.into_mut(),
+ // create new connections
+ match guard.deref_mut().entry(sess_str.clone()) {
+ Entry::Occupied(_) => {},
Entry::Vacant(v) => {
let cres = Connection::connect(connection, port,
- username, password);
+ login.user.clone(), login.password.clone());
match cres {
Err(e) => {
- match e {
+ let errstr = match e {
+ // Connection error handling
+ // TO DO: Wait for Display/Debug
Error::AddrParse(_) => {
- return Ok(Response::with((iron::status::Ok,
- format!("Could not connect to specified server."))))
+ "Could not connect to specified server."
},
Error::Io(_) => {
- return Ok(Response::with((iron::status::Ok,
- format!("Connection failure. Try again later."))))
+ "Connection failure. Try again later."
},
Error::Decode(_) => {
- return Ok(Response::with((iron::status::Ok,
- format!("Could not read data from server."))))
+ "Could not readfsdfd data from server."
},
Error::Encode(_) => {
- return Ok(Response::with((iron::status::Ok,
- format!("Could not send data to server."))))
+ "Could not send data to server."
},
- Error::UnexpectedPkg(e) => {
- return Ok(Response::with((iron::status::Ok,
- format!("{}", e.to_string()))))
+ Error::UnexpectedPkg(_) => {
+ "Unexpected Package."
},
- Error::Auth(e) => {
- return Ok(Response::with((iron::status::Ok,
- format!("{}", e.to_string()))))
+ Error::Auth(_) => {
+ "Authentication failed."
},
- }
+ };
+ let mut data = HashMap::new();
+ data.insert("err", errstr);
+ return res.render("src/webclient/templates/error.tpl", &data);
}
- Ok(c) => v.insert(c),
+ Ok(c) => {
+ v.insert(Arc::new(Mutex::new(c)));
+ },
}
}
};
- // Msg to print to web
- let msg = format!("Connected (version {}) to {}:{}\n{}\n",
- con.get_version(), con.get_ip(),
- con.get_port(), con.get_message());
+ // Set a Cookie with the session string as its value
+ // sess_str is set to a value here, so we can safely unwrap
+ let keks = CookiePair::new("UosqlDB".to_owned(), sess_str.clone());
+ res.headers_mut().set(SetCookie(vec![keks]));
- Ok(Response::with((iron::status::Ok, msg)))
+ // Redirect to the greeting page
+ *res.status_mut() = nickel::status::StatusCode::Found;
+ res.headers_mut().set_raw("location", vec![b"/".to_vec()]);
+ return res.send("");
});
- // Build webclient on localhost 3000
- Iron::new(chain).http("localhost:3000").unwrap();
-}
-/*
- Get data input from user via webclient and
- process it
+ // Greeting page
+ server.get("/", middleware! { |req, response|
+
+ // Look for connection
+ let con = req.extensions().get::().unwrap().lock().unwrap();
-*/
+ // Current display with short welcome message
+ let version = con.get_version().to_string();
+ let port = con.get_port().to_string();
+ let mut data = HashMap::new();
+
+ data.insert("name", con.get_username());
+ data.insert("version", &version);
+ data.insert("bind", con.get_ip());
+ data.insert("port", &port);
+ data.insert("msg", con.get_message());
+ return response.render("src/webclient/templates/hello.tpl", &data);
+ });
+
+
+ server.listen("127.0.0.1:6767");
+}
diff --git a/src/webclient/templates/error.tpl b/src/webclient/templates/error.tpl
new file mode 100644
index 0000000..8e17557
--- /dev/null
+++ b/src/webclient/templates/error.tpl
@@ -0,0 +1,7 @@
+
+
+
+ Error: {{ err }}
+
+
+
diff --git a/src/webclient/templates/hello.tpl b/src/webclient/templates/hello.tpl
new file mode 100644
index 0000000..cfdcbcb
--- /dev/null
+++ b/src/webclient/templates/hello.tpl
@@ -0,0 +1,15 @@
+
+
+
+
+ Hello {{ name }}!
+
+
+ Connected (version : {{ version }}) to {{ bind }} : {{ port }}
+ {{ msg }}
+
+
+
+
diff --git a/src/webclient/templates/login.tpl b/src/webclient/templates/login.tpl
new file mode 100644
index 0000000..2e52b3d
--- /dev/null
+++ b/src/webclient/templates/login.tpl
@@ -0,0 +1,19 @@
+
+
+
+ Login
+
+
+ {{ err_msg }}
+
+
+
+
+
+
diff --git a/src/webclient/templates/success.tpl b/src/webclient/templates/success.tpl
new file mode 100644
index 0000000..2869a76
--- /dev/null
+++ b/src/webclient/templates/success.tpl
@@ -0,0 +1,7 @@
+
+
+
+ Success!
+
+
+