aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs121
1 files changed, 55 insertions, 66 deletions
diff --git a/src/main.rs b/src/main.rs
index 0951518..f284b75 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,86 +1,87 @@
+use std::collections::HashMap;
use std::convert::Infallible;
+use std::fs::read_to_string;
use std::net::SocketAddr;
use std::path::PathBuf;
-use std::rc::Rc;
use std::sync::Arc;
use hyper::service::{make_service_fn, service_fn};
use hyper::{header, Body, Request, Response, Server, StatusCode};
-use rhai::{Dynamic, Engine, FnPtr, Map, NativeCallContext, Scope};
+use serde::Deserialize;
use structopt::StructOpt;
mod utils;
+use utils::HttpHandler;
#[derive(Debug, StructOpt)]
struct Opt {
- #[structopt(long, parse(from_os_str), default_value = "narchttpd.rhai")]
- config_script: PathBuf,
+ #[structopt(long, parse(from_os_str), default_value = "narchttpd.toml")]
+ config_file: PathBuf,
}
-fn make_engine() -> Engine {
- let mut engine = Engine::new();
- engine.register_type_with_name::<Rc<Request<Body>>>("Request");
- engine.register_type::<utils::serve_static::Params>();
- engine.register_fn(
- "handle_request_serve_static",
- utils::serve_static::handle_request,
- );
- engine.register_fn("serve_static", utils::serve_static::serve_static);
- engine.register_fn(
- "handle_request_proxy_child",
- utils::proxy_child::handle_request,
- );
- engine.register_fn("proxy_child", utils::proxy_child::proxy_child);
- engine
+#[derive(Deserialize)]
+#[serde(tag = "mode", rename_all = "kebab-case")]
+enum DomainConfig {
+ Static {
+ root: PathBuf,
+ },
+
+ ProxyChild {
+ command: String,
+ in_dir: Option<PathBuf>,
+ port: u16,
+ },
+}
+
+impl DomainConfig {
+ fn handler(self) -> Box<dyn HttpHandler> {
+ match self {
+ Self::Static { root } => Box::new(utils::serve_static::Params::new(root)),
+ Self::ProxyChild {
+ command,
+ in_dir,
+ port,
+ } => Box::new(utils::proxy_child::ProxyChild::new(command, in_dir, port)),
+ }
+ }
}
-fn get_config_scope(engine: &Engine, opt: &Opt) -> Scope<'static> {
- let mut ast = engine.compile_file(opt.config_script.clone()).unwrap();
-
- let mut scope = Scope::new();
- scope.push("http_ports", [80]);
- scope.push("https_ports", [443]);
- scope.push("domains", Map::new());
- let export_ast = engine
- .compile("export http_ports, https_ports, domains;")
- .unwrap();
- ast.combine(export_ast);
- let _: () = engine.eval_ast_with_scope(&mut scope, &ast).unwrap();
- scope
+#[derive(Deserialize)]
+struct Config {
+ http_ports: Vec<u16>,
+ https_ports: Vec<u16>,
+ #[serde(flatten)]
+ domains: HashMap<String, DomainConfig>,
}
#[tokio::main]
async fn main() {
- let opt = Arc::new(Opt::from_args());
+ let opt = Opt::from_args();
- let engine = make_engine();
- let scope = get_config_scope(&engine, &opt);
+ let config_data = read_to_string(&opt.config_file).expect("Config file not found");
- let http_ports: rhai::Array = scope.get_value("http_ports").unwrap();
- let http_ports: Vec<u16> = http_ports
- .into_iter()
- .map(|x| x.as_int().unwrap() as u16)
- .collect();
- let https_ports: rhai::Array = scope.get_value("https_ports").unwrap();
- let https_ports: Vec<u16> = https_ports
- .into_iter()
- .map(|x| x.as_int().unwrap() as u16)
- .collect();
+ let Config {
+ http_ports,
+ https_ports,
+ domains,
+ } = toml::from_str(&config_data).expect("Config file not valid");
assert!(https_ports.is_empty(), "HTTPS is complicated oops");
+ let domains: HashMap<_, _> = domains
+ .into_iter()
+ .map(|(domain, config)| (domain, Arc::new(config.handler())))
+ .collect();
+ let do_response_domains = domains.clone();
+
// TODO learn hyper
- let do_response = move |ctx: &NativeCallContext, domains: Map, req: Request<Body>| {
- for (domain, handler) in &domains {
+ let do_response = move |req: Request<Body>| async move {
+ for (domain, handler) in do_response_domains.clone() {
let req_domain = req.headers().get(header::HOST).unwrap();
- if domain.as_str() == req_domain {
+ if &domain == req_domain {
eprintln!("request {:?} matched domain {}", req, domain);
// matched!
- let handler: FnPtr = handler.clone_cast();
- let args = [Dynamic::from(Rc::new(req))];
- let result = handler.call_dynamic(ctx, None, args).unwrap();
- let result: Rc<Response<Body>> = result.cast();
- return Rc::try_unwrap(result).unwrap();
+ return handler.handle(req).await;
}
}
Response::builder()
@@ -96,19 +97,7 @@ async fn main() {
let make_svc = make_service_fn(move |_conn| async move {
Ok::<_, Infallible>(service_fn(move |req| async move {
- let handle = tokio::runtime::Handle::current();
- let response = handle
- .spawn_blocking(move || {
- let opt = Opt::from_args();
- let engine = make_engine();
- let scope = get_config_scope(&engine, &opt);
- let request_handler_context =
- NativeCallContext::new(&engine, "handle_request", &[]);
- let domains: Map = scope.get_value("domains").unwrap();
- do_response(&request_handler_context, domains, req)
- })
- .await
- .unwrap();
+ let response = do_response(req).await;
Ok::<_, Infallible>(response)
}))
});