This commit is contained in:
Michael 2018-08-15 21:26:05 +00:00 committed by Michael Zhang
parent ea731f78bf
commit fdb5c7a9b3
No known key found for this signature in database
GPG key ID: A1B65B603268116B
8 changed files with 124 additions and 125 deletions

31
Cargo.lock generated
View file

@ -150,6 +150,9 @@ dependencies = [
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -554,6 +557,11 @@ dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "1.0.2"
@ -585,6 +593,26 @@ name = "serde"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "slab"
version = "0.1.3"
@ -975,11 +1003,14 @@ dependencies = [
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "16aa12da69951804cddf5f74d96abcc414a31b064e610dc81e37c1536082f491"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)" = "6dfad05c8854584e5f72fb859385ecdfa03af69c3fd0572f0da2d4c95f060bdb"
"checksum serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)" = "b719c6d5e9f73fbc37892246d5852333f040caa617b8873c6aced84bcb28e7bb"
"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970"

View file

@ -9,6 +9,9 @@ hyper = "0.12"
lazy_static = "1.1"
notify = "4.0"
regex = "1.0"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
structopt = "0.2"
toml = "0.4"
walkdir = "2.2"

1
src/handlers/builder.rs Normal file
View file

@ -0,0 +1 @@
pub struct HandlerBuilder {}

View file

@ -1,20 +0,0 @@
use toml::Value;
use failure::Error;
use hyper::{Body, Request, Response, Method};
use handlers::Handler;
pub struct GithubHandler {}
impl GithubHandler {
pub fn new() -> Self {
GithubHandler {}
}
}
impl Handler for GithubHandler {
fn handle(&self, req: &Request<Body>) -> Result<Response<Body>, Error> {
if req.method() != Method::POST { bail!("Github webhooks should use the POST method.") }
Ok(Response::new(Body::from("Lol")))
}
}

View file

@ -1,12 +1,17 @@
mod git;
mod script;
mod builder;
use failure::Error;
use hyper::{Body, Request, Response};
use serde_json::Value as JsonValue;
use toml::Value as TomlValue;
pub use self::git::*;
pub use self::script::*;
pub use self::builder::*;
pub trait Handler: Send + Sync {
fn handle(&self, &Request<Body>) -> Result<Response<Body>, Error>;
pub struct Handler {
pub handle: fn(Result<JsonValue, Error>) -> Result<JsonValue, Error>,
}
impl Handler {
pub fn from(config: &TomlValue) -> Result<Self, Error> {
bail!("rip")
}
}

View file

@ -1,18 +0,0 @@
use failure::Error;
use hyper::{Body, Request, Response};
use handlers::Handler;
pub struct ScriptHandler {}
impl ScriptHandler {
pub fn new() -> Self {
ScriptHandler {}
}
}
impl Handler for ScriptHandler {
fn handle(&self, req: &Request<Body>) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::from("Lol")))
}
}

View file

@ -1,69 +1,58 @@
use std::collections::HashMap;
use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::slice::Iter;
use failure::{err_msg, Error};
use hyper::{Body, Request, Response};
use toml::Value;
use walkdir::WalkDir;
use Handler;
pub struct Hook {
handler_type: String,
name: String,
handlers: Vec<Handler>,
}
impl Hook {
pub fn from(config: &Value) -> Result<Self, Error> {
let handler_type = config
.get("type")
.ok_or(err_msg("Missing field 'type'"))?
.as_str()
.ok_or(err_msg("Field 'type' is not a string"))?
pub fn from(name: impl Into<String>, config: &Value) -> Result<Self, Error> {
let name = name.into();
let handlers = config
.get("handlers")
.ok_or(err_msg("No 'handlers' found."))?
.as_array()
.ok_or(err_msg("'handlers' is not an array."))?
.iter()
.map(|value: &Value| Handler::from(value))
.collect::<Result<Vec<_>, _>>()?;
Ok(Hook { name, handlers })
}
pub fn from_file<P>(path: P) -> Result<Hook, Error>
where
P: AsRef<Path>,
{
let filename = path
.as_ref()
.file_name()
.ok_or(err_msg("what the fuck bro"))?
.to_str()
.ok_or(err_msg("???"))?
.to_owned();
Ok(Hook { handler_type })
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let config = contents.parse::<Value>()?;
let hook = Hook::from(filename, &config)?;
Ok(hook)
}
pub fn get_name(&self) -> String {
self.name.clone()
}
pub fn iter(&self) -> Iter<Handler> {
self.handlers.iter()
}
pub fn handle(&self, payload: &Request<Body>) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::from("lol")))
}
}
pub fn load_from_config<P>(path: P, hooks: &mut HashMap<String, Hook>) where P: AsRef<Path> {
let hooks_dir = {
let mut p = path.as_ref().to_path_buf();
p.push("hooks");
p
};
if hooks_dir.exists() {
for entry in WalkDir::new(hooks_dir) {
let path = match entry.as_ref().map(|e| e.path()) {
Ok(path) => path,
_ => continue,
};
if !path.is_file() {
continue;
}
match (|path: &Path| -> Result<(), Error> {
let filename = path
.file_name()
.ok_or(err_msg("what the fuck bro"))?
.to_str()
.ok_or(err_msg("???"))?
.to_owned();
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let config = contents.parse::<Value>()?;
let hook = Hook::from(&config)?;
println!("Added hook '{}'", filename);
hooks.insert(filename, hook);
Ok(())
})(path)
{
Ok(_) => (),
Err(err) => eprintln!("Failed to read config from {:?}: {}", path, err),
}
}
}
}

View file

@ -1,29 +1,11 @@
//! # Dip
//!
//! Set up some kind of directory structure like this:
//!
//! ```
//! root/
//! - config.toml
//! - hooks/
//! - website.com
//! ```
//!
//! where every file in the `hooks` subdirectory is a TOML document of the following format:
//!
//! ```toml
//! # The handler to use. This must match one of the handlers defined in the
//! # handlers directory or one of the builtins such as "github"
//! type = "github"
//!
//! # wip lol
//! ```
//!
//! Then run the `dip` binary with the option `-d <root>` where `root` points to the root directory you made above.
#[macro_use]
extern crate failure;
extern crate hyper;
extern crate serde;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate lazy_static;
extern crate notify;
@ -35,8 +17,6 @@ pub mod handlers;
pub mod hook;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::{mpsc, Mutex};
use std::thread;
@ -48,7 +28,6 @@ use hyper::service::service_fn_ok;
use hyper::{Body, Request, Response, Server};
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use regex::Regex;
use toml::Value;
use walkdir::WalkDir;
pub use handlers::Handler;
@ -84,10 +63,15 @@ fn service_fn(req: &Request<Body>) -> Result<Response<Body>, Error> {
.ok_or(err_msg("Missing name"))?
.as_str();
let hooks = HOOKS.lock().unwrap();
let handler = hooks
let hook = hooks
.get(name)
.ok_or(err_msg(format!("Hook '{}' doesn't exist", name)))?;
handler.handle(&req)
let req_obj = json!({
"method": req.method().as_str(),
});
hook.iter()
.fold(Ok(req_obj), |prev, handler| (handler.handle)(prev))
.map(|_| Response::new(Body::from("success")))
}
fn service_fn_wrapper(req: Request<Body>) -> Response<Body> {
@ -109,12 +93,36 @@ where
{
let mut handlers = HANDLERS.lock().unwrap();
handlers.clear();
handlers.insert("github".to_owned(), Box::new(handlers::GithubHandler::new()));
}
{
let mut hooks = HOOKS.lock().unwrap();
hooks.clear();
hook::load_from_config(root, &mut hooks);
let hooks_dir = {
let mut p = root.as_ref().to_path_buf();
p.push("hooks");
p
};
if hooks_dir.exists() {
for entry in WalkDir::new(hooks_dir) {
let path = match entry.as_ref().map(|e| e.path()) {
Ok(path) => path,
_ => continue,
};
if !path.is_file() {
continue;
}
match (|path: &Path| -> Result<(), Error> {
let hook = Hook::from_file(path)?;
let name = hook.get_name();
hooks.insert(name, hook);
Ok(())
})(path)
{
Ok(_) => (),
Err(err) => eprintln!("Failed to read config from {:?}: {}", path, err),
}
}
}
}
}