the hell am i doing

This commit is contained in:
Michael Zhang 2018-08-12 22:57:56 -07:00
commit 6f81fb947f
No known key found for this signature in database
GPG key ID: A1B65B603268116B
8 changed files with 1183 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
**/*.rs.bk
/testroot

1006
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "dip"
version = "0.1.0"
authors = ["Michael Zhang <failed.down@gmail.com>"]
[dependencies]
failure = "0.1"
hyper = "0.12"
lazy_static = "1.1"
notify = "4.0"
regex = "1.0"
structopt = "0.2"
walkdir = "2.2"

13
README.md Normal file
View file

@ -0,0 +1,13 @@
Dip
===
[![](https://img.shields.io/badge/rewritten-in%20rust-%23dea584.svg)](https://github.com/ansuz/RIIR)
Configurable webhook server.
Contact
-------
Author: Michael Zhang
License: MIT

5
src/handler.rs Normal file
View file

@ -0,0 +1,5 @@
use hyper::{Body, Request, Response};
pub trait Handler: Send + Sync {
fn handle(&self, payload: &Request<Body>) -> Option<Response<Body>>;
}

5
src/hook.rs Normal file
View file

@ -0,0 +1,5 @@
use hyper::{Body, Request, Response};
pub trait Hook: Send + Sync {
fn handle(&self, payload: &Request<Body>) -> Option<Response<Body>>;
}

115
src/lib.rs Normal file
View file

@ -0,0 +1,115 @@
extern crate failure;
extern crate hyper;
#[macro_use]
extern crate lazy_static;
extern crate notify;
extern crate regex;
extern crate walkdir;
mod handler;
mod hook;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use failure::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 walkdir::WalkDir;
use handler::*;
use hook::*;
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();
}
const NOTFOUND: &str = r#"<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>) -> Option<Response<Body>> {
let captures = match URIPATTERN.captures(req.uri().path()) {
Some(value) => value,
None => return None,
};
let name = match captures.name("name") {
Some(name) => name.as_str(),
None => return None,
};
let handler = match HOOKS.get(name) {
Some(handler) => handler,
None => return None,
};
handler.handle(&req)
}
fn service_fn_wrapper(req: Request<Body>) -> Response<Body> {
match service_fn(req) {
Some(response) => response,
None => Response::new(Body::from(NOTFOUND)),
}
}
fn watch<P>(root: P) -> notify::Result<()>
where
P: AsRef<Path>,
{
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)?;
loop {
match rx.recv() {
Ok(event) => println!("{:?}", event),
Err(e) => println!("watch error: {:?}", e),
}
}
}
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);
}
}
thread::spawn(|| watch(root));
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));
hyper::rt::run(server);
Ok(())
}

22
src/main.rs Normal file
View file

@ -0,0 +1,22 @@
#[macro_use]
extern crate structopt;
extern crate dip;
extern crate failure;
use std::path::PathBuf;
use failure::Error;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
struct Opt {
#[structopt(short = "d", long = "root", parse(from_os_str))]
root: PathBuf,
}
fn main() -> Result<(), Error> {
let opt = Opt::from_args();
println!("{:?}", opt);
assert!(opt.root.exists());
dip::run(opt.root)
}