From 7fecc3cf624ad8a68c5227a14a7d092c72fa9c35 Mon Sep 17 00:00:00 2001 From: Louis Capitanchik <contact@louiscap.co> Date: Tue, 17 Apr 2018 16:27:03 +0100 Subject: [PATCH] Implement config routes support, get lua runtime from the request --- example/.swerve/config.yml | 13 +++---- src/cli/config_file.rs | 7 ++++ src/cli/config_routes.rs | 17 +++++++++ src/cli/mod.rs | 4 ++- src/routing/request.rs | 73 +++++++++++++++++++++++++++++++++++++- src/routing/scripting.rs | 10 +++++- src/server/lua.rs | 32 +++++++++++++++-- src/server/mod.rs | 2 +- src/server/server.rs | 4 --- 9 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 src/cli/config_routes.rs diff --git a/example/.swerve/config.yml b/example/.swerve/config.yml index f4bac07..b6f87d2 100644 --- a/example/.swerve/config.yml +++ b/example/.swerve/config.yml @@ -2,16 +2,17 @@ field_handling: Log file_handling: File server: port: 9000 -requests: - - /users/@user_id : scripts/get_user_by_id.dyon - - /users : +routes: + - route: /users/@user_id + script: scripts/get_user_by_id.dyon + - route: /users + response: failure_rate: 5 - response_headers: + headers: x-rate-limit: 100 x-rate-remaining: 96 x-rate-reset: 10/12/1990 - response_type: application/json - response_body: + body: count: 2 data: - id: 1 diff --git a/src/cli/config_file.rs b/src/cli/config_file.rs index 7723ae5..1718df1 100644 --- a/src/cli/config_file.rs +++ b/src/cli/config_file.rs @@ -7,6 +7,8 @@ use std::default::Default; use serde::{Deserialize, Deserializer, de}; use std::fmt; use serde_yaml as yaml; +use std::collections::HashMap; +use cli; #[derive(Debug, Copy, Clone)] pub enum HandlerMethod { @@ -52,6 +54,8 @@ pub struct SwerveConfig { pub file_handling: HandlerMethod, #[serde(default)] pub server: ServerOptions, + #[serde(default="get_empty_routes")] + pub routes: Vec<cli::RouteHandler>, } #[derive(Deserialize, Debug, Clone)] @@ -74,12 +78,15 @@ fn get_default_address() -> String { String::from("localhost") } fn get_default_quiet_attr() -> bool { false } fn get_default_index_attr() -> bool { false } +fn get_empty_routes() -> Vec<cli::RouteHandler> { vec![] } + impl Default for SwerveConfig { fn default() -> Self { SwerveConfig { field_handling: HandlerMethod::Log, file_handling: HandlerMethod::Log, server: ServerOptions::default(), + routes: get_empty_routes(), } } } diff --git a/src/cli/config_routes.rs b/src/cli/config_routes.rs new file mode 100644 index 0000000..62cf89d --- /dev/null +++ b/src/cli/config_routes.rs @@ -0,0 +1,17 @@ +use std::collections::HashMap; + +#[derive(Clone, Debug, Deserialize)] +pub struct RouteHandler { + route: String, + response: Option<ResponseHandler>, + script: Option<String>, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct ResponseHandler { + failure_rate: Option<u32>, + #[serde(default="get_default_headers")] + headers: HashMap<String, String>, +} + +fn get_default_headers() -> HashMap<String, String> { HashMap::new() } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 4993a2f..2ac3861 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,7 +1,9 @@ mod cli; mod config_file; +mod config_routes; pub mod gpl; pub use self::cli::{Args, USAGE}; -pub use self::config_file::{HandlerMethod, SwerveConfig}; \ No newline at end of file +pub use self::config_file::{HandlerMethod, SwerveConfig}; +pub use self::config_routes::RouteHandler; \ No newline at end of file diff --git a/src/routing/request.rs b/src/routing/request.rs index 643abe5..d1deefe 100644 --- a/src/routing/request.rs +++ b/src/routing/request.rs @@ -2,7 +2,7 @@ use rocket::{self, Outcome, http, Response}; use rocket::request::{FromRequest, Request}; use rocket::http::ContentType; use hyper::header::Headers; -use std::path::{Path, PathBuf}; +use std::path::{Path, PathBuf, Component}; use std::io::BufReader; use std::fs::File; @@ -57,3 +57,74 @@ impl rocket::response::Responder<'static> for TypedFile { Ok(response) } } + +pub struct RequestPath(pub String); +impl <'a, 'req>FromRequest<'a, 'req> for RequestPath { + type Error = (); + + fn from_request(request: &'a Request<'req>) -> Outcome<Self, (http::Status, ()), ()> { + let uri = request.uri(); + Outcome::Success(RequestPath(String::from(uri.path()))) + } +} + +pub mod path { + use std::path as std_path; + use std::option::Option::*; + + pub struct MatchablePath(pub String); + pub type PathMatch = (String, String); + pub type MatchList = Vec<PathMatch>; + pub type MatchResult = Option<MatchList>; + + impl MatchablePath { + pub fn from<T>(src: T) -> Self where T: ToString { + MatchablePath(src.to_string()) + } + + fn path_to_vec<T: ToString>(string: T) -> Vec<String> { + std_path::PathBuf::from(string.to_string()) + .components() + .filter_map(|c| match c { + std_path::Component::Normal(cmp) => cmp.to_str() + .and_then(|s| Some(String::from(s))), + _ => None, + }) + .collect() + } + + pub fn matches<T>(&self, other: T) -> MatchResult where T: ToString { + let this_path = MatchablePath::path_to_vec(&self.0); + let other_path = MatchablePath::path_to_vec(other); + + if this_path.len() == other_path.len() { + let parts_match = this_path.iter() + .zip(other_path.iter()) + .fold(true, |acc, (this, other)| { + acc && (this.starts_with("@") || this == other) + }); + + if parts_match { + Some(this_path.iter() + .zip(other_path.iter()) + .filter_map(|(this, other)| { + if this.starts_with("@") { + Some(( + this.chars().skip(1).collect::<String>(), + other.clone() + )) + } else { + None + } + }) + .collect() + ) + } else { + None + } + } else { + None + } + } + } +} diff --git a/src/routing/scripting.rs b/src/routing/scripting.rs index 165c007..02ff44d 100644 --- a/src/routing/scripting.rs +++ b/src/routing/scripting.rs @@ -1,8 +1,16 @@ use scripting::run_script; use std::path::PathBuf; +use routing::request; +use server::LuaRuntime; +use rlua::{Lua}; #[get("/__testing__/run-script")] -pub fn route_script() -> String { +pub fn route_script(path: request::RequestPath, runtime: LuaRuntime) -> String { + let lua: Lua = runtime.into(); + let doowap = path.0; + let foo = request::path::MatchablePath(String::from("/inspection/@id")); + let matches = foo.matches(String::from("/inspection/123")); + println!("{:?}", matches); let path = PathBuf::from("example/.swerve/get_user_by_id.rhai"); run_script(path).unwrap_or(String::from("No script")) } \ No newline at end of file diff --git a/src/server/lua.rs b/src/server/lua.rs index 08cd875..eff9e5b 100644 --- a/src/server/lua.rs +++ b/src/server/lua.rs @@ -1,6 +1,34 @@ use rlua::{Lua}; +use rocket::{self, Outcome, http, Response}; +use rocket::request::{FromRequest, Request}; +use std::convert::{Into, AsRef, AsMut}; -pub fn create_runtime(with_debug: bool) -> Lua { +pub struct LuaRuntime(Lua); +impl Into<Lua> for LuaRuntime { + fn into(self) -> Lua { + self.0 + } +} +impl AsRef<Lua> for LuaRuntime { + fn as_ref(&self) -> &Lua { + &self.0 + } +} +impl AsMut<Lua> for LuaRuntime { + fn as_mut(&mut self) -> &mut Lua { + &mut self.0 + } +} + +impl <'a, 'req>FromRequest<'a, 'req> for LuaRuntime { + type Error = (); + + fn from_request(_request: &'a Request<'req>) -> Outcome<Self, (http::Status, ()), ()> { + Outcome::Success(create_runtime(false)) + } +} + +pub fn create_runtime(with_debug: bool) -> LuaRuntime { let runtime = if with_debug { unsafe { Lua::new_with_debug() } } else { @@ -9,5 +37,5 @@ pub fn create_runtime(with_debug: bool) -> Lua { // Customise runtime here - runtime + LuaRuntime(runtime) } \ No newline at end of file diff --git a/src/server/mod.rs b/src/server/mod.rs index 6fc1851..21e4c64 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -2,4 +2,4 @@ mod server; mod lua; pub use self::server::create_server; -pub use self::lua::create_runtime; \ No newline at end of file +pub use self::lua::{LuaRuntime, create_runtime}; \ No newline at end of file diff --git a/src/server/server.rs b/src/server/server.rs index 5cdcd85..37a1b94 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -1,7 +1,6 @@ use rocket::{self, Rocket, Config}; use cli::{Args, SwerveConfig}; use routing; -use server; pub fn create_server(args: Args, config: SwerveConfig) -> Rocket { let server_config = server_config_from_input(args.clone(), config.clone()); @@ -37,9 +36,6 @@ pub fn create_server(args: Args, config: SwerveConfig) -> Rocket { })); } - let lua_runtime = server::create_runtime(false); - server = server.manage(lua_runtime); - server } -- GitLab