use dev_prefix::*;
use std::sync::Mutex;
use nickel::{Request, Response, MiddlewareResult, Nickel, HttpRouter, MediaType};
use nickel::status::StatusCode;
use nickel::StaticFilesHandler;
use tar::Archive;
use tempdir::TempDir;
use core::{Project, ArtifactData};
mod constants;
mod utils;
mod handler;
mod update;
#[cfg(test)]
mod tests;
const WEB_FRONTEND_TAR: &'static [u8] = include_bytes!("data/web-ui.tar");
lazy_static! {
static ref ARTIFACTS: Mutex<Vec<ArtifactData>> = Mutex::new(Vec::new());
static ref PROJECT: Mutex<Project> = Mutex::new(Project::default());
}
fn setup_headers(res: &mut Response) {
let head = res.headers_mut();
let bv = |s: &str| Vec::from(s.as_bytes());
head.set_raw("Access-Control-Allow-Origin", vec![bv("*")]);
head.set_raw("Access-Control-Allow-Methods",
vec![bv("GET, POST, OPTIONS, PUT, PATCH, DELETE")]);
head.set_raw("Access-Control-Allow-Headers",
vec![bv("X-Requested-With,content-type")]);
}
fn config_json_res(res: &mut Response) {
res.set(MediaType::Json);
res.set(StatusCode::Ok);
}
fn handle_artifacts<'a>(req: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
setup_headers(&mut res);
debug!("handling json-rpc request");
let mut body = vec![];
req.origin.read_to_end(&mut body).unwrap();
let body = match str::from_utf8(&body) {
Ok(b) => b,
Err(e) => {
res.set(StatusCode::BadRequest);
return res.send(format!("invalid utf8: {:?}", e));
}
};
trace!("request: {:?}", body);
match handler::RPC_HANDLER.handle_request_sync(body) {
Some(body) => {
trace!("- response {}", body);
config_json_res(&mut res);
res.send(body)
}
None => {
let msg = "InternalServerError: Got None from json-rpc handler";
error!("{}", msg);
res.set(StatusCode::InternalServerError);
res.send(msg)
}
}
}
fn host_frontend(server: &mut Nickel, addr: &str) -> TempDir {
let tmp_dir = TempDir::new("artifact-web-ui").expect("unable to create temporary directory");
let dir = tmp_dir.path().to_path_buf(); info!("unpacking web-ui at: {}", dir.display());
let mut archive = Archive::new(WEB_FRONTEND_TAR);
archive.unpack(&dir).expect("unable to unpack web frontend");
let app_js_path = dir.join("app.js");
let mut app_js = fs::OpenOptions::new()
.read(true)
.write(true)
.open(app_js_path)
.expect("couldn't open app.js");
let mut text = String::new();
app_js.read_to_string(&mut text).expect("app.js couldn't be read");
app_js.seek(SeekFrom::Start(0)).unwrap();
app_js.set_len(0).unwrap(); app_js.write_all(text.replace("localhost:3733", addr).as_bytes()).unwrap();
app_js.flush().unwrap();
server.utilize(StaticFilesHandler::new(&dir));
println!("hosting web ui at {}", addr);
tmp_dir
}
#[allow(unused_variables)] pub fn start_api(project: Project, addr: &str, edit: bool) {
{
let artifacts: Vec<ArtifactData> = project.artifacts
.iter()
.map(|(name, model)| model.to_data(name))
.collect();
let mut locked = ARTIFACTS.lock().unwrap();
let global: &mut Vec<ArtifactData> = locked.deref_mut();
let compare_by = |a: &ArtifactData| a.name.replace(" ", "").to_ascii_uppercase();
global.sort_by(|a, b| compare_by(a).cmp(&compare_by(b)));
*global = artifacts;
}
{
let mut locked = PROJECT.lock().unwrap();
let global = locked.deref_mut();
*global = project;
}
let endpoint = "/json-rpc";
let mut server = Nickel::new();
server.get(endpoint, handle_artifacts);
server.put(endpoint, handle_artifacts);
server.options(endpoint,
middleware! { |_, mut res|
setup_headers(&mut res);
res.set(StatusCode::Ok);
"ok"
});
let tmp_dir = host_frontend(&mut server, addr);
server.listen(addr).expect("cannot connect to port");
}