diff --git a/.gitignore b/.gitignore index c1d3494b4ed75bc891ce2f3470b4b2792d1ba44e..b42e7781b5ec6692ed144add72cd31f6724fcaad 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ test.html # bin bin todo.md +.script config.toml # fleet diff --git a/Cargo.lock b/Cargo.lock index 2b21ae974ce2aa6cc99b949f9f9831e129dcd0be..905b2101946fd4acc54c10838c0b1a87c7b2950e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -614,6 +614,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "bitvec" @@ -743,7 +746,10 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", + "serde", + "wasm-bindgen", "windows-targets 0.52.6", ] @@ -776,6 +782,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + [[package]] name = "const-random" version = "0.1.18" @@ -1233,6 +1252,15 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "global_placeholders" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d70af3f3fd800923fa445d6fa562e054d8abaf06df926f77dd6dbead1fefb275" +dependencies = [ + "parking_lot", +] + [[package]] name = "gloo-timers" version = "0.2.6" @@ -1838,6 +1866,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1982,6 +2011,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "pest_meta" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pickledb" version = "0.5.1" @@ -2079,6 +2153,22 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "unarray", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2130,6 +2220,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "redis" version = "0.24.0" @@ -2307,6 +2406,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2427,19 +2538,26 @@ dependencies = [ "actix-web", "anyhow", "askama", + "chrono", "colored", + "const-hex", "fancy-regex", + "global_placeholders", "home", "macros-rs", + "md-5", "mime", "mongodb", "peg", + "pest", + "pest_derive", "pickledb", "redis", "reqwest", "rhai", "rhai-fs", "rhai-url", + "ron", "serde", "serde_json", "smartstring", @@ -3195,6 +3313,18 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicase" version = "2.7.0" diff --git a/Cargo.toml b/Cargo.toml index d0793b57a00079d63860cc6af942103a8ffa76c8..4bd0cf541abbceff6391a3c1ae385ecf5b82d223 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,13 @@ smartstring = "1.0.1" serde_json = "1.0.127" tracing-subscriber = "0.3.18" tracing-bunyan-formatter = "0.3.9" +global_placeholders = "0.1.0" +ron = "0.8.1" +chrono = { version = "0.4.38", features = ["serde"] } +pest = "2.7.11" +pest_derive = "2.7.11" +md-5 = "0.10.6" +const-hex = "1.12.0" [dependencies.mongodb] default-features = false diff --git a/app.routes b/app.routes index 2d6f4bc21e778dae657c041960e2e0dd9d89ef2b..63614a01cea0e87255d016f6f6ac5b30a75340af 100644 --- a/app.routes +++ b/app.routes @@ -2,7 +2,7 @@ index { text(":3\nwelcome to the root") } -hello() { +hello { response("Hello World!", "text", 200) } @@ -91,10 +91,10 @@ name(id, name) { #[route("/proxy/{arg}")] fetch_proxy(arg) { - proxy(`https://www.google.com/search?q=$(arg)`) + proxy(`https://www.google.com/search?q=${arg}`) } -example/json() { +example/json { let res = http::get("https://httpbin.org/json"); let body = #{ response: res.json(), @@ -109,7 +109,7 @@ example/json() { json(body) } -example/post/bin() { +example/post/bin { let body = #{ hello: "world", url: request.url, @@ -118,7 +118,7 @@ example/post/bin() { json(http::post("https://httpbin.org/post", body).raw()) } -test.json() { +test.json { let res = #{ hello: "world", info: #{ @@ -132,7 +132,7 @@ test.json() { json(res) } -test/loadfile() { +test/loadfile { let file = open_file("test.html"); html(file.read_string()) } @@ -143,5 +143,5 @@ test/loadfile() { } 404 { - text("404 page") -} \ No newline at end of file + text("404 page"); +} diff --git a/src/config.rs b/src/config.rs index 873a3fed08b33dc4f24321a74c2324b9b5158f50..6db4520060f99c9ac0896114402d6a156d003152 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,6 +18,7 @@ pub fn read() -> Config { database: None, workers: vec!["app.routes".into()], settings: Settings { + cache: string!(".script/cache"), address: string!("127.0.0.1"), port: 3500, }, diff --git a/src/globals.rs b/src/globals.rs new file mode 100644 index 0000000000000000000000000000000000000000..b45ac1e76c2b06fec1b577b99d15c47869d948c0 --- /dev/null +++ b/src/globals.rs @@ -0,0 +1,15 @@ +use crate::config; +use global_placeholders::init; +use macros_rs::fs::folder_exists; +use std::fs::create_dir_all; + +pub fn init() { + let config = config::read(); + + if !folder_exists!(&config.settings.cache) { + create_dir_all(&config.settings.cache).unwrap(); + tracing::info!("created cached dir"); + } + + init!("dirs.cache", format!("{}{{}}.route", config.settings.cache)); +} diff --git a/src/main.rs b/src/main.rs index 5b4e66afa431007fa55342defec854f2cd4e2e53..46692e98915d00bed0f8efda4dac8421480a3462 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod config; mod database; +mod globals; mod helpers; mod modules; mod routes; @@ -264,6 +265,8 @@ async fn handler(req: HttpRequest, config: Data) -> impl Responder { Err(err) => crashln!("Error reading script file: {}\n{}", filename.to_string_lossy(), err), }; + routes::parse::try_parse(&contents); + let has_error_page = R_ERR.as_ref().unwrap().is_match(&contents).unwrap(); let has_wildcard = R_WILD.as_ref().unwrap().is_match(&contents).unwrap(); let has_index = R_INDEX.as_ref().unwrap().is_match(&contents).unwrap(); @@ -282,30 +285,6 @@ async fn handler(req: HttpRequest, config: Data) -> impl Responder { .collect() } - fn extract_route(input: &str, route_name: Option<&str>) -> Vec { - let re = Regex::new(r"(?m)^\s*#\[route\(([^)]+)\)(?:,\s*cfg\(([^)]+)\))?\]\s*([^\(]+)\([^)]*\)\s*\{([^}]+)\}").unwrap(); - - re.captures_iter(input) - .filter_map(|captures| { - let cap = captures.unwrap(); - - let route = helpers::rm_first(cap[1].trim().trim_matches('"')).to_string(); - if route_name.map_or(true, |name| route == name) { - let cfg = cap.get(2).map(|m| parse_cfg(m.as_str())); - let fn_name = cap[3].trim().to_string(); - let fn_body = cap[4].trim().to_string(); - let fn_fmt = "".to_string(); - - Some(routes::Route { route, cfg, fn_name, fn_body, fn_fmt }) - } else { - None - } - }) - .collect() - } - - let route_data = extract_route(&contents, None); - let contents = { let pattern = r#"\{([^{}\s]+)\}"#; let pattern_rm_config = r#",?\s*cfg\([^)]*\)"#; @@ -453,35 +432,35 @@ async fn handler(req: HttpRequest, config: Data) -> impl Responder { } } - for data in route_data { - let name = data.route; - - let cfg = match data.cfg { - Some(cfg) => cfg, - None => HashMap::new(), - }; - - for (item, val) in cfg { - match item.as_str() { - "wildcard" => { - if url.splitn(2, '/').next().unwrap_or(&url) == name && parse_bool(&val) { - match engine.call_fn::<(String, ContentType, StatusCode)>(&mut scope, &ast, helpers::convert_to_format(&name), ()) { - Ok(response) => send!(response), - Err(err) => { - let body = ServerError { - error: err.to_string().replace("\n", "
"), - context: extract_context(contents, err.to_string()), - }; - - return HttpResponse::build(StatusCode::INTERNAL_SERVER_ERROR).content_type(ContentType::html()).body(body.render().unwrap()); - } - } - } - } - _ => {} - } - } - } + // for data in route_data { + // let name = data.route; + // + // let cfg = match data.cfg { + // Some(cfg) => cfg, + // None => HashMap::new(), + // }; + // + // for (item, val) in cfg { + // match item.as_str() { + // "wildcard" => { + // if url.splitn(2, '/').next().unwrap_or(&url) == name && parse_bool(&val) { + // match engine.call_fn::<(String, ContentType, StatusCode)>(&mut scope, &ast, helpers::convert_to_format(&name), ()) { + // Ok(response) => send!(response), + // Err(err) => { + // let body = ServerError { + // error: err.to_string().replace("\n", "
"), + // context: extract_context(contents, err.to_string()), + // }; + // + // return HttpResponse::build(StatusCode::INTERNAL_SERVER_ERROR).content_type(ContentType::html()).body(body.render().unwrap()); + // } + // } + // } + // } + // _ => {} + // } + // } + // } if has_wildcard || has_error_page { let (body, content_type, status_code) = engine @@ -504,6 +483,7 @@ async fn handler(req: HttpRequest, config: Data) -> impl Responder { #[actix_web::main] async fn main() -> std::io::Result<()> { set_env_sync!(RUST_LOG = "info"); + globals::init(); let config = config::read(); let app = || App::new().app_data(Data::new(config::read())).default_service(web::to(handler)); diff --git a/src/routes.rs b/src/routes.rs index 84ed0c2b0da5b8e5a24776337541c1198f808edd..9cd58ca018ee8cbf7b67dd2049e9ba071cedb288 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,16 +1,140 @@ -use std::collections::HashMap; +pub mod parse; -type Config = Option>; +use chrono::{DateTime, Duration, Utc}; +use global_placeholders::global; +use macros_rs::fmt::string; +use md5::{Digest, Md5}; +use serde::{Deserialize, Serialize}; +use smartstring::{LazyCompact, SmartString}; -#[derive(Debug, Default)] +use std::{ + collections::HashMap, + fs::{create_dir_all, read, write}, + path::{Path, PathBuf}, +}; + +pub type RtData = SmartString; +pub type RtArgs = Option>; +pub type RtConfig = Option>; +pub type RtTime = DateTime; + +pub enum RtKind { + Index, + Wildcard, + NotFound, + Normal, +} + +#[derive(Debug, Default, PartialEq, Eq, Deserialize, Serialize)] pub struct Route { - pub cfg: Config, - pub route: String, - pub fn_name: String, - pub fn_body: String, - pub fn_fmt: String, + pub cfg: RtConfig, + pub args: RtArgs, + pub hash: String, + pub expires: RtTime, + pub created: RtTime, + pub cache: PathBuf, + pub route: RtData, + pub fn_name: RtData, + pub fn_body: RtData, + pub start_pos: usize, + pub end_pos: usize, } impl Route { - pub fn new() -> Self { Default::default() } + pub fn default() -> Self { Default::default() } + + pub fn cache(&mut self, kind: RtKind) -> &Self { + let mut md5 = Md5::new(); + + let route_name = match kind { + RtKind::Index => "/index", + RtKind::Wildcard => "/wildcard", + RtKind::NotFound => "/not_found", + RtKind::Normal => self.route.as_str(), + }; + + let fn_name = match kind { + RtKind::Index => "index", + RtKind::Wildcard => "wildcard", + RtKind::NotFound => "not_found", + RtKind::Normal => self.fn_name.as_str(), + }; + + let now = Utc::now(); + let cache_key = global!("dirs.cache", route_name); + + self.route = route_name.into(); + self.fn_name = fn_name.into(); + + md5.update(&self.route); + md5.update(&self.fn_name); + md5.update(&self.fn_body); + + self.created = now; + self.expires = now + Duration::hours(3); + self.cache = Path::new(&cache_key).to_owned(); + self.hash = const_hex::encode(md5.finalize()); + + return self; + } + + pub fn save(&mut self, kind: RtKind) { + self.cache(kind); + + if let Some(parent) = self.cache.parent() { + if !parent.exists() { + // add error handling + create_dir_all(parent).unwrap(); + } + } + + let encoded = match ron::ser::to_string(&self) { + Ok(contents) => contents, + Err(err) => { + tracing::error!(err = string!(err), "Cannot encode route"); + std::process::exit(1); + } + }; + + if let Err(err) = write(self.cache.to_owned(), encoded) { + tracing::error!(err = string!(err), "Error writing route"); + std::process::exit(1); + } + } + + pub fn get(key: &str) -> String { + let bytes = match read(&key) { + Ok(contents) => contents, + Err(err) => { + tracing::error!(err = string!(err), "Error reading route"); + std::process::exit(1); + } + }; + + let data: Route = match ron::de::from_bytes(&bytes) { + Ok(parsed) => parsed, + Err(err) => { + tracing::error!(err = string!(err), "Error reading route"); + std::process::exit(1); + } + }; + + let args = match data.args { + Some(args) => match args.len() { + 0 => String::new(), + 1 => args[0].to_string(), + _ => args.join(", "), + }, + None => "".into(), + }; + + format!("fn {}({args}){{{}", data.fn_name, data.fn_body) + } +} + +pub mod prelude { + pub use super::Route; + pub use super::RtConfig; + pub use super::RtData; + pub use super::RtKind; } diff --git a/src/routes/grammar.peg b/src/routes/grammar.peg new file mode 100644 index 0000000000000000000000000000000000000000..bb8bd2fb82df3aa68e1efd27ddee7bb78783c793 --- /dev/null +++ b/src/routes/grammar.peg @@ -0,0 +1,158 @@ +grammar = { SOI ~ (route_definition | function_def | index | not_found | wildcard)* ~ EOI } + +route_definition = { + route_attr? ~ function_def +} + +function_def = { + route_name ~ ("(" ~ parameters? ~ ")")? ~ block +} + +index = { + "index" ~ block +} + +wildcard = { + "*" ~ block +} + +not_found = { + "404" ~ block +} + +route_attr = { + "#" ~ "[" ~ "route" ~ "(" ~ string_literal ~ ")" ~ + ("," ~ cfg_block)? ~ + "]" +} + +cfg_block = { + "cfg" ~ "(" ~ cfg_entries ~ ")" +} + +cfg_entries = { + cfg_entry ~ ("," ~ cfg_entry)* ~ ","? +} + +cfg_entry = { + identifier ~ "=" ~ (boolean | string_literal | number) +} + +route_name = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_" | "/" | ".")* } + +parameters = { parameter ~ ("," ~ parameter)* ~ ","? } + +parameter = @{ identifier } + +block = { + "{" ~ statement* ~ "}" +} + +statement = { + let_statement | + expression_statement | + assignment | + if_statement | + for_statement | + while_statement | + return_statement | + block +} + +let_statement = { + "let" ~ identifier ~ ("=" ~ expression)? ~ ";" +} + +expression_statement = { + expression ~ ";"? +} + +assignment = { + identifier ~ "=" ~ expression ~ ";" +} + +if_statement = { + "if" ~ expression ~ block ~ ("else" ~ (if_statement | block))? +} + +for_statement = { + "for" ~ identifier ~ "in" ~ expression ~ block +} + +while_statement = { + "while" ~ expression ~ block +} + +return_statement = { + "return" ~ expression? ~ ";"? +} + +expression = { + logical_expr +} + +logical_expr = { + comparison_expr ~ (("&&" | "||") ~ comparison_expr)* +} + +comparison_expr = { + arithmetic_expr ~ (("==" | "!=" | "<" | ">" | "<=" | ">=") ~ arithmetic_expr)* +} + +arithmetic_expr = { + term ~ (("+" | "-") ~ term)* +} + +term = { + factor ~ (("*" | "/" | "%") ~ factor)* +} + +factor = { + unary_expr | + "(" ~ expression ~ ")" | + call_chain | + object | + array | + literal +} + +unary_expr = { + ("-" | "!") ~ factor +} + +call_chain = { + (identifier | literal) ~ + ( + "::" ~ identifier | + "." ~ identifier | + arguments + )* ~ + arguments? +} + +arguments = { + "(" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ ")" +} + +object = { + "#{" ~ (object_entry ~ ("," ~ object_entry)*)? ~ ","? ~ "}" +} + +object_entry = { (identifier | string_literal) ~ ":" ~ expression } + +array = { + "[" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ "]" +} + +literal = { number | string_literal | boolean | object | array } + +number = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? ~ ("e" ~ "-"? ~ ASCII_DIGIT+)? } + +string_literal = @{ ("\"" ~ (!"\"" ~ ANY)* ~ "\"") | ("`" ~ (!"`" ~ ANY)* ~ "`") } + +boolean = { "true" | "false" } + +identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } + +WHITESPACE = _{ " " | "\t" | "\n" | "\r" } +COMMENT = _{ "//" ~ (!"\n" ~ ANY)* | "/*" ~ (!"*/" ~ ANY)* ~ "*/" } \ No newline at end of file diff --git a/src/routes/parse.rs b/src/routes/parse.rs new file mode 100644 index 0000000000000000000000000000000000000000..634accf14e737ed9c363a9ae9ac7ab2672e97b00 --- /dev/null +++ b/src/routes/parse.rs @@ -0,0 +1,120 @@ +use pest::iterators::Pair; +use pest::Parser; +use pest_derive::Parser; +use std::collections::HashMap; + +#[derive(Parser)] +#[grammar = "routes/grammar.peg"] +struct RouteParser; + +fn extract_cfg(pair: Pair) -> HashMap { + let mut cfg = HashMap::new(); + for entry in pair.into_inner().flat_map(|p| p.into_inner()) { + if let (Some(key), Some(value)) = (entry.clone().into_inner().next(), entry.into_inner().nth(1)) { + cfg.insert(key.as_str().to_string(), value.as_str().trim_matches('"').to_string()); + } + } + cfg +} + +fn extract_block_content(block: &str) -> String { + let lines: Vec<&str> = block.lines().collect(); + if lines.len() < 3 { + return block.trim().trim_matches('{').trim_matches('}').trim().to_string(); + } + + let indent = lines[1].chars().take_while(|c| c.is_whitespace()).count(); + lines[1..lines.len() - 1] + .iter() + .map(|line| if line.len() > indent { &line[indent..] } else { line.trim() }) + .collect::>() + .join("\n") +} + +fn extract_route_info(pair: Pair, input: &str) -> super::Route { + let mut route_info = super::Route::default(); + + for inner_pair in pair.into_inner() { + match inner_pair.as_rule() { + Rule::route_attr => { + for attr_pair in inner_pair.into_inner() { + match attr_pair.as_rule() { + Rule::string_literal => { + route_info.route = attr_pair.as_str().trim_matches('"').into(); + } + Rule::cfg_block => { + route_info.cfg = Some(extract_cfg(attr_pair)); + } + _ => {} + } + } + } + Rule::function_def => { + for func_pair in inner_pair.into_inner() { + match func_pair.as_rule() { + Rule::route_name => { + route_info.fn_name = func_pair.as_str().into(); + + if route_info.route.is_empty() { + route_info.route = format!("/{}", func_pair.as_str()).into(); + } + } + Rule::parameters => { + route_info.args = Some(func_pair.into_inner().map(|p| p.as_str().into()).collect()); + } + Rule::block => { + route_info.fn_body = extract_block_content(func_pair.as_str()).into(); + + let start_pos = func_pair.as_span().start(); + let end_pos = func_pair.as_span().end(); + let file_lines: Vec<&str> = input.lines().collect(); + + route_info.start_pos = file_lines.iter().take_while(|line| input.find(line.to_owned()).unwrap() < start_pos).count() - 1; + route_info.end_pos = file_lines.iter().take_while(|line| input.find(line.to_owned()).unwrap() <= end_pos).count() - 1; + } + _ => {} + } + } + } + Rule::block => { + route_info.fn_body = extract_block_content(inner_pair.as_str()).into(); + + let start_pos = inner_pair.as_span().start(); + let end_pos = inner_pair.as_span().end(); + let file_lines: Vec<&str> = input.lines().collect(); + + route_info.start_pos = file_lines.iter().take_while(|line| input.find(line.to_owned()).unwrap() < start_pos).count() - 1; + route_info.end_pos = file_lines.iter().take_while(|line| input.find(line.to_owned()).unwrap() <= end_pos).count() - 1; + } + _ => {} + } + } + + route_info +} + +fn process_pair(pair: Pair, input: &str) { + match pair.as_rule() { + Rule::index => extract_route_info(pair, input).save(super::RtKind::Index), + Rule::route_definition => extract_route_info(pair, input).save(super::RtKind::Normal), + Rule::not_found => extract_route_info(pair, input).save(super::RtKind::NotFound), + Rule::wildcard => extract_route_info(pair, input).save(super::RtKind::Wildcard), + + _ => { + for inner_pair in pair.into_inner() { + process_pair(inner_pair, input); + } + } + } +} + +pub fn try_parse(input: &str) { + match RouteParser::parse(Rule::grammar, input) { + Ok(pairs) => { + for pair in pairs { + process_pair(pair, input); + } + } + Err(e) => println!("Error: {}", e), + } +} diff --git a/src/structs/config.rs b/src/structs/config.rs index 26d0ee1529fa7ac4c6a2ddd70e4dfd98c07c96f7..8a47b3bd8ebe5696de090b6cb75677f39889de16 100644 --- a/src/structs/config.rs +++ b/src/structs/config.rs @@ -12,6 +12,7 @@ pub struct Config { #[derive(Clone, Serialize, Deserialize)] pub struct Settings { + pub cache: String, pub address: String, pub port: u16, }