Add really basic webserver

This commit is contained in:
Tiffany Bennett 2016-08-13 21:57:46 -04:00
parent dddf6f6177
commit f29ccdae8b
2 changed files with 108 additions and 0 deletions

View file

@ -12,6 +12,7 @@ keywords = ["unit", "math", "conversion", "cli", "tool"]
[features]
default = ["rustyline", "chrono-humanize"]
ircbot = ["irc", "glob"]
web = ["hyper", "url"]
[dependencies]
rust-gmp = "0.3.2"
@ -20,6 +21,8 @@ chrono-humanize = { version = "0.0.6", optional = true }
rustyline = { version = "0.2.3", optional = true }
irc = { version = "0.11.3", optional = true }
glob = { version = "0.2.11", optional = true }
hyper = { version = "0.9.10", optional = true }
url = { version = "1.2.0", optional = true }
[[bin]]
name = "rink"
@ -32,3 +35,7 @@ doc = false
[[bin]]
name = "rink-irc"
doc = false
[[bin]]
name = "rink-web"
doc = false

101
src/bin/rink-web.rs Normal file
View file

@ -0,0 +1,101 @@
#[cfg(feature = "web")]
extern crate hyper;
#[cfg(feature = "web")]
extern crate url;
#[cfg(feature = "web")]
extern crate rink;
#[cfg(feature = "web")]
static TEMPLATE: &'static str = r##"
<html>
<head>
<title>Rink</title>
</head>
<body>
<form action="#" method="POST" target="_self">
<input name="value" type="text" />
<input type="submit" />
</form>
</body>
</html>
"##;
#[cfg(feature = "web")]
fn main() {
use hyper;
use hyper::status::StatusCode;
use hyper::server::{Server, Request, Response};
use hyper::header;
use hyper::mime::{Mime, TopLevel, SubLevel};
use std::env::args;
use std::io::{Read, Write};
use url::form_urlencoded;
use std::sync::mpsc;
use std::sync::Mutex;
use std::thread;
let (tx, rx) = mpsc::channel::<(String, mpsc::Sender<String>)>();
thread::spawn(move || {
let mut ctx = rink::load().unwrap();
while let Ok((req, tx)) = rx.recv() {
let reply = match rink::one_line(&mut ctx, &*req) {
Ok(v) => v,
Err(v) => v
};
tx.send(reply).unwrap();
}
});
let tx = Mutex::new(tx);
let req = move |mut req: Request, mut res: Response| {
match req.method {
hyper::Get => {
write!(res.start().unwrap(), "{}", TEMPLATE).unwrap();
},
hyper::Post => {
let mut buf = String::new();
match req.read_to_string(&mut buf) {
Ok(_) => (),
Err(e) => {
*res.status_mut() = StatusCode::BadRequest;
write!(res.start().unwrap(), "{}", e).unwrap();
return
}
};
let is_form = req.headers.get::<header::ContentType>()
.map(|x| match x.0 {
Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _) => true,
_ => false,
})
.unwrap_or(false);
let input = if is_form {
let mut form = form_urlencoded::parse(buf.as_bytes());
let value = form.find(|&(ref k, _)| k == "value");
if let Some((_, value)) = value {
value.into_owned()
} else {
*res.status_mut() = StatusCode::BadRequest;
write!(&mut res.start().unwrap(), "Bad form").unwrap();
return
}
} else {
buf
};
let (tx2, rx2) = mpsc::channel();
tx.lock().unwrap().send((input, tx2)).unwrap();
let reply = rx2.recv().unwrap();
write!(&mut res.start().unwrap(), "{}", reply).unwrap();
},
_ => *res.status_mut() = StatusCode::MethodNotAllowed
}
};
let port = args().nth(1).map(|x| x.parse::<u16>().expect("Invalid port number")).unwrap_or(8000);
Server::http(&*format!("127.0.0.1:{}", port)).unwrap().handle(req).unwrap();
}
#[cfg(not(feature = "web"))]
fn main() {
println!("Rink was not compiled with web support.");
}