the hell am i doing
This commit is contained in:
commit
6f81fb947f
8 changed files with 1183 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
|
||||
/testroot
|
1006
Cargo.lock
generated
Normal file
1006
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal 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
13
README.md
Normal 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
5
src/handler.rs
Normal 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
5
src/hook.rs
Normal 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
115
src/lib.rs
Normal 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
22
src/main.rs
Normal 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)
|
||||
}
|
Loading…
Reference in a new issue