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