hook setup
This commit is contained in:
parent
6f81fb947f
commit
8042d2d19a
4 changed files with 100 additions and 22 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -151,6 +151,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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)",
|
||||
]
|
||||
|
||||
|
@ -579,6 +580,11 @@ name = "semver-parser"
|
|||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.1.3"
|
||||
|
@ -793,6 +799,14 @@ dependencies = [
|
|||
"tokio-reactor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.2"
|
||||
|
@ -965,6 +979,7 @@ dependencies = [
|
|||
"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 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"
|
||||
|
@ -987,6 +1002,7 @@ dependencies = [
|
|||
"checksum tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24ab84f574027b0e875378f31575cf175360891919e93a3490f07e76e00e4efb"
|
||||
"checksum tokio-timer 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1c76b4e97a4f61030edff8bd272364e4f731b9f54c7307eb4eb733c3926eb96a"
|
||||
"checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0"
|
||||
"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
|
||||
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
|
|
|
@ -10,4 +10,5 @@ lazy_static = "1.1"
|
|||
notify = "4.0"
|
||||
regex = "1.0"
|
||||
structopt = "0.2"
|
||||
toml = "0.4"
|
||||
walkdir = "2.2"
|
||||
|
|
21
src/hook.rs
21
src/hook.rs
|
@ -1,5 +1,22 @@
|
|||
use failure::{err_msg, Error};
|
||||
use hyper::{Body, Request, Response};
|
||||
use toml::Value;
|
||||
|
||||
pub trait Hook: Send + Sync {
|
||||
fn handle(&self, payload: &Request<Body>) -> Option<Response<Body>>;
|
||||
pub struct Hook {
|
||||
handler_type: String,
|
||||
}
|
||||
|
||||
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"))?
|
||||
.to_owned();
|
||||
Ok(Hook { handler_type })
|
||||
}
|
||||
pub fn handle(&self, payload: &Request<Body>) -> Option<Response<Body>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
84
src/lib.rs
84
src/lib.rs
|
@ -4,24 +4,27 @@ extern crate hyper;
|
|||
extern crate lazy_static;
|
||||
extern crate notify;
|
||||
extern crate regex;
|
||||
extern crate toml;
|
||||
extern crate walkdir;
|
||||
|
||||
mod handler;
|
||||
mod hook;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{mpsc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use failure::Error;
|
||||
use failure::{err_msg, Error};
|
||||
use hyper::rt::Future;
|
||||
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;
|
||||
|
||||
use handler::*;
|
||||
|
@ -31,7 +34,7 @@ lazy_static! {
|
|||
static ref URIPATTERN: Regex =
|
||||
Regex::new(r"/webhook/(?P<name>[A-Za-z_][A-Za-z0-9_]*)").unwrap();
|
||||
static ref HANDLERS: HashMap<String, Box<Handler>> = HashMap::new();
|
||||
static ref HOOKS: HashMap<String, Box<Hook>> = HashMap::new();
|
||||
static ref HOOKS: Mutex<HashMap<String, Hook>> = Mutex::new(HashMap::new());
|
||||
}
|
||||
|
||||
const NOTFOUND: &str = r#"<html>
|
||||
|
@ -56,7 +59,8 @@ fn service_fn(req: Request<Body>) -> Option<Response<Body>> {
|
|||
Some(name) => name.as_str(),
|
||||
None => return None,
|
||||
};
|
||||
let handler = match HOOKS.get(name) {
|
||||
let hooks = HOOKS.lock().unwrap();
|
||||
let handler = match hooks.get(name) {
|
||||
Some(handler) => handler,
|
||||
None => return None,
|
||||
};
|
||||
|
@ -70,6 +74,52 @@ fn service_fn_wrapper(req: Request<Body>) -> Response<Body> {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_config<P>(root: P)
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
println!("Reloading config...");
|
||||
// hold on to the lock while config is being reloaded
|
||||
let mut hooks = HOOKS.lock().unwrap();
|
||||
hooks.clear();
|
||||
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 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)?;
|
||||
hooks.insert(filename, hook);
|
||||
Ok(())
|
||||
})(path)
|
||||
{
|
||||
Ok(_) => (),
|
||||
Err(err) => eprintln!("Failed to read config from {:?}: {}", path, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn watch<P>(root: P) -> notify::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
|
@ -77,10 +127,13 @@ where
|
|||
let (tx, rx) = mpsc::channel();
|
||||
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1))?;
|
||||
println!("Watching {:?}", root.as_ref().to_path_buf());
|
||||
watcher.watch(root, RecursiveMode::Recursive)?;
|
||||
watcher.watch(root.as_ref(), RecursiveMode::Recursive)?;
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => println!("{:?}", event),
|
||||
Ok(_) => {
|
||||
// for now, naively reload entire config every time
|
||||
load_config(root.as_ref())
|
||||
}
|
||||
Err(e) => println!("watch error: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
@ -90,26 +143,17 @@ pub fn run<P>(root: P) -> Result<(), Error>
|
|||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let root = root.as_ref().to_path_buf();
|
||||
let handlers_dir = {
|
||||
let mut p = root.clone();
|
||||
p.push("handlers");
|
||||
p
|
||||
};
|
||||
if handlers_dir.exists() {
|
||||
for entry in WalkDir::new(handlers_dir) {
|
||||
let path = entry?.path().to_path_buf();
|
||||
println!("{:?}", path);
|
||||
}
|
||||
}
|
||||
load_config(&root);
|
||||
|
||||
thread::spawn(|| watch(root));
|
||||
let v = root.as_ref().to_path_buf();
|
||||
thread::spawn(|| watch(v));
|
||||
|
||||
let addr = ([127, 0, 0, 1], 3000).into();
|
||||
|
||||
let server = Server::bind(&addr)
|
||||
.serve(|| service_fn_ok(service_fn_wrapper))
|
||||
.map_err(|e| eprintln!("server error: {}", e));
|
||||
println!("Listening on {:?}", addr);
|
||||
hyper::rt::run(server);
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue