most of git delivery, gotta refactor the whole thing for body tho

This commit is contained in:
Michael Zhang 2018-08-15 22:16:13 -07:00
parent afe94b53d1
commit 03e965791f
No known key found for this signature in database
GPG key ID: A1B65B603268116B
5 changed files with 91 additions and 44 deletions

1
Cargo.lock generated
View file

@ -187,6 +187,7 @@ name = "dip"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -14,6 +14,7 @@ sha-1 = "0.7"
[dependencies] [dependencies]
failure = "0.1" failure = "0.1"
futures = "0.1"
hyper = "0.12" hyper = "0.12"
lazy_static = "1.1" lazy_static = "1.1"
notify = "4.0" notify = "4.0"

View file

@ -13,6 +13,7 @@ extern crate structopt;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::{self, Read}; use std::io::{self, Read};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::path::PathBuf;
use failure::{err_msg, Error}; use failure::{err_msg, Error};
use generic_array::GenericArray; use generic_array::GenericArray;
@ -31,6 +32,7 @@ struct Opt {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Config { struct Config {
secret: String, secret: String,
outdir: PathBuf,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -45,7 +47,9 @@ fn main() -> Result<(), Error> {
let mut payload = String::new(); let mut payload = String::new();
io::stdin().read_to_string(&mut payload)?; io::stdin().read_to_string(&mut payload)?;
println!("raw payload: {}", payload);
let payload: Payload = serde_json::from_str(&payload)?; let payload: Payload = serde_json::from_str(&payload)?;
println!("processed payload: {}", payload.body);
let secret = GenericArray::from_iter(config.secret.bytes()); let secret = GenericArray::from_iter(config.secret.bytes());
let mut mac = Hmac::<Sha1>::new(&secret); let mut mac = Hmac::<Sha1>::new(&secret);
@ -60,13 +64,13 @@ fn main() -> Result<(), Error> {
let auth = payload let auth = payload
.headers .headers
.get("X-Hub-Signature") .get("x-hub-signature")
.ok_or(err_msg("Missing auth header"))?; .ok_or(err_msg("Missing auth header"))?;
let left = SecStr::from(format!("sha1={}", signature)); let left = SecStr::from(format!("sha1={}", signature));
let right = SecStr::from(auth.bytes().collect::<Vec<_>>()); let right = SecStr::from(auth.bytes().collect::<Vec<_>>());
assert!(left == right, "HMAC signature didn't match"); assert!(left == right, "HMAC signature didn't match");
println!("{}", payload.body); println!("gonna clone it to {:?}", config.outdir);
Ok(()) Ok(())
} }

View file

@ -1,13 +1,16 @@
use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::{Command, Stdio};
use failure::{err_msg, Error}; use failure::{err_msg, Error};
use serde_json::Value as JsonValue; use serde::Serialize;
use serde_json::{Serializer as JsonSerializer, Value as JsonValue};
use toml::Value as TomlValue; use toml::Value as TomlValue;
use PROGRAMS; use PROGRAMS;
pub struct Handler { pub struct Handler {
config: TomlValue,
exec: PathBuf, exec: PathBuf,
} }
@ -25,21 +28,46 @@ impl Handler {
.ok_or(err_msg(format!("'{}' is not a valid executable", handler))) .ok_or(err_msg(format!("'{}' is not a valid executable", handler)))
.map(|value| value.clone())? .map(|value| value.clone())?
}; };
Ok(Handler { exec }) let config = config.clone();
Ok(Handler { config, exec })
} }
pub fn run(&self, _: Result<JsonValue, Error>) -> Result<JsonValue, Error> { pub fn run(&self, input: JsonValue) -> Result<JsonValue, Error> {
Command::new(&self.exec) let config = {
let mut buf: Vec<u8> = Vec::new();
{
let mut serializer = JsonSerializer::new(&mut buf);
TomlValue::serialize(&self.config, &mut serializer)?;
}
String::from_utf8(buf).unwrap()
};
let mut child = Command::new(&self.exec)
.env("DIP_ROOT", "") .env("DIP_ROOT", "")
.output() .arg("--config")
.map_err(|err| err_msg(format!("{}", err))) .arg(config)
.and_then(|output| { .stdin(Stdio::piped())
if !output.status.success() { .stdout(Stdio::piped())
return Err(err_msg(format!( .stderr(Stdio::piped())
"'{:?}' returned with a non-zero status code: {}", .spawn()?;
self.exec, output.status {
))); match child.stdin {
Some(ref mut stdin) => {
write!(stdin, "{}", input)?;
} }
Ok(json!({})) None => bail!("done fucked"),
}) };
}
let output = child.wait_with_output()?;
if !output.status.success() {
// TODO: get rid of unwraps
return Err(err_msg(format!(
"'{:?}' returned with a non-zero status code: {}\nstdout:\n{}\nstderr:\n{}",
self.exec,
output.status,
String::from_utf8(output.stdout).unwrap(),
String::from_utf8(output.stderr).unwrap()
)));
}
Ok(json!({}))
} }
} }

View file

@ -1,7 +1,9 @@
//! # Dip //! # Dip
#[macro_use]
extern crate failure; extern crate failure;
extern crate hyper; extern crate hyper;
extern crate futures;
extern crate serde; extern crate serde;
#[macro_use] #[macro_use]
extern crate serde_json; extern crate serde_json;
@ -27,7 +29,7 @@ use std::time::Duration;
use failure::{err_msg, Error}; use failure::{err_msg, Error};
use hyper::rt::Future; use hyper::rt::Future;
use hyper::service::service_fn_ok; use hyper::service::service_fn_ok;
use hyper::{Body, Request, Response, Server}; use hyper::{Body, Request, Response, Server, StatusCode};
use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use regex::Regex; use regex::Regex;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -45,22 +47,12 @@ lazy_static! {
static ref HOOKS: Mutex<HashMap<String, Hook>> = Mutex::new(HashMap::new()); static ref HOOKS: Mutex<HashMap<String, Hook>> = Mutex::new(HashMap::new());
} }
const NOTFOUND: &str = r#"<html> const NOTFOUND: &str = "<html> <head> <style> * { font-family: sans-serif; } body { padding: 20px 60px; } </style> </head> <body> <h1>Looks like you took a wrong turn!</h1> <p>There's nothing to see here.</p> </body> </html>";
<head>
<style>
* { font-family: sans-serif; }
body { padding: 20px 60px; }
</style>
</head>
<body>
<h1>Looks like you took a wrong turn!</h1>
<p>There's nothing to see here.</p>
</body>
</html>"#;
fn service_fn(req: &Request<Body>) -> Result<Response<Body>, Error> { fn service_fn(req: Request<Body>) -> Result<Response<Body>, Error> {
let path = req.uri().path().to_owned();
let captures = URIPATTERN let captures = URIPATTERN
.captures(req.uri().path()) .captures(path.as_ref())
.ok_or(err_msg("Did not match url pattern"))?; .ok_or(err_msg("Did not match url pattern"))?;
let name = captures let name = captures
.name("name") .name("name")
@ -70,22 +62,41 @@ fn service_fn(req: &Request<Body>) -> Result<Response<Body>, Error> {
let hook = hooks let hook = hooks
.get(name) .get(name)
.ok_or(err_msg(format!("Hook '{}' doesn't exist", name)))?; .ok_or(err_msg(format!("Hook '{}' doesn't exist", name)))?;
let req_obj = json!({
"method": req.method().as_str(), let req_obj = {
}); let headers = req
.headers()
.clone()
.into_iter()
.filter_map(|(k, v)| {
let key = k.unwrap().as_str().to_owned();
v.to_str().map(|value| (key, value.to_owned())).ok()
}).collect::<HashMap<_, _>>();
let method = req.method().as_str().to_owned();
// probably not idiomatically the best way to do it
// i was just trying to get something working
let body = "wip".to_owned();
json!({
"body": body,
"headers": headers,
"method": method,
})
};
hook.iter() hook.iter()
.fold(Ok(req_obj), |prev, handler| handler.run(prev)) .fold(Ok(req_obj), |prev, handler| {
.map(|_| Response::new(Body::from("success"))) prev.and_then(|val| handler.run(val))
}).map(|_| Response::new(Body::from("success")))
} }
fn service_fn_wrapper(req: Request<Body>) -> Response<Body> { fn service_fn_wrapper(req: Request<Body>) -> Response<Body> {
match service_fn(&req) { let uri = req.uri().path().to_owned();
Ok(response) => response, service_fn(req).unwrap_or_else(|err| {
Err(err) => { eprintln!("Error from '{}': {}", uri, err);
eprintln!("Got error from '{}': {}", req.uri().path(), err); Response::builder()
Response::new(Body::from(NOTFOUND)) .status(StatusCode::NOT_FOUND)
} .body(Body::from(NOTFOUND))
} .unwrap()
})
} }
fn load_config<P>(root: P) fn load_config<P>(root: P)
@ -96,6 +107,7 @@ where
// hold on to the lock while config is being reloaded // hold on to the lock while config is being reloaded
{ {
let mut programs = PROGRAMS.lock().unwrap(); let mut programs = PROGRAMS.lock().unwrap();
// TODO: some kind of smart diff
programs.clear(); programs.clear();
let programs_dir = { let programs_dir = {
let mut p = root.as_ref().to_path_buf(); let mut p = root.as_ref().to_path_buf();
@ -168,6 +180,7 @@ where
match rx.recv() { match rx.recv() {
Ok(_) => { Ok(_) => {
// for now, naively reload entire config every time // for now, naively reload entire config every time
// TODO: don't do this
load_config(root.as_ref()) load_config(root.as_ref())
} }
Err(e) => println!("watch error: {:?}", e), Err(e) => println!("watch error: {:?}", e),