From fddff14780c240943755897d36ecbb4a952aacfd Mon Sep 17 00:00:00 2001 From: panovo Date: Fri, 17 May 2024 00:15:52 +0300 Subject: [PATCH 1/7] Improved server raising process, deleted db/create_db.rs with 'blaze create' and made 'blaze init' instead --- .gitignore | 1 + Cargo.lock | 126 +++++++++++++++++-- Cargo.toml | 3 +- src/db/create_db.rs | 56 --------- src/db/mod.rs | 1 - src/lib.rs | 1 - src/main.rs | 2 +- src/scripting/ast/functional_return.rs | 6 +- src/scripting/ast/loop_control.rs | 6 +- src/scripting/ast/mod.rs | 6 +- src/scripting/ast/while_loop.rs | 4 +- src/scripting/parser.rs | 18 ++- src/server/{headers.rs => header_parsing.rs} | 0 src/server/management.rs | 102 +++++++++++++++ src/server/mod.rs | 6 +- src/server/{config.rs => runtime_config.rs} | 22 ++-- src/server/server_bz.rs | 45 ------- src/shell/handling.rs | 100 +++++++++++---- 18 files changed, 327 insertions(+), 178 deletions(-) delete mode 100644 src/db/create_db.rs delete mode 100644 src/db/mod.rs rename src/server/{headers.rs => header_parsing.rs} (100%) create mode 100644 src/server/management.rs rename src/server/{config.rs => runtime_config.rs} (78%) delete mode 100644 src/server/server_bz.rs diff --git a/.gitignore b/.gitignore index d6e3ba0..d2a4146 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /db/ .vim .vscode +*.blz diff --git a/Cargo.lock b/Cargo.lock index 6552256..1cac559 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "bitvec" version = "1.0.1" @@ -48,6 +54,7 @@ version = "0.1.0" dependencies = [ "bson", "colored", + "ctrlc", "dotenvy", "rand", "regex", @@ -88,6 +95,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "colored" version = "2.1.0" @@ -95,7 +108,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ "lazy_static", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ctrlc" +version = "3.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" +dependencies = [ + "nix", + "windows-sys 0.52.0", ] [[package]] @@ -203,6 +226,18 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -518,7 +553,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", ] [[package]] @@ -527,13 +571,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -542,42 +602,90 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index e8c5397..6bae8c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,9 @@ edition = "2021" [dependencies] regex = "1.10" bson = "2.10" +ctrlc = "3.4.4" rand = "0.8" strum = "0.26" colored = "2.1.0" strum_macros = "0.26" -dotenvy = "0.15" \ No newline at end of file +dotenvy = "0.15" diff --git a/src/db/create_db.rs b/src/db/create_db.rs deleted file mode 100644 index 21931ad..0000000 --- a/src/db/create_db.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::fs::{self, File}; -use std::io::{Result, Write}; -use std::path::{Path, PathBuf}; - -pub const OFFICIAL_REPOSITORY: &str = "https://github.com/Reeliks/blaze"; - -pub fn create_db_structure(path_to_db: &str) -> Result<()> { - let mut db_workdir_path_buf = PathBuf::from(&path_to_db); - db_workdir_path_buf.push("datablaze"); - create_db_folders(&db_workdir_path_buf)?; - - let is_manage_file_created: bool = create_manage_file(&db_workdir_path_buf)?; - if is_manage_file_created { - println!("manage.blz has been created") - } else { - println!("manage.blz already exists; skipping..."); - } - println!("\nA new datablaze has been structured. Use 'blaze --help' to see the commands.\nTo contribute the development process, check out the official repository:\n{}", OFFICIAL_REPOSITORY); - - Ok(()) -} - -fn create_db_folders(db_path_buf: &Path) -> Result<()> { - for folder in ["data", "model"] { - let mut cloned_db_path_buf = db_path_buf.to_path_buf(); - cloned_db_path_buf.push(folder); - fs::create_dir_all(cloned_db_path_buf)?; - } - Ok(()) -} - -fn create_manage_file(path_to_db_buf: &Path) -> Result { - let mut managing_file_path_buf = path_to_db_buf.to_path_buf(); - let manage_file_content = br#"manage ( - tmax_connections = 3, - work_dir = "/", - backups_dir = "backups/" -); - -attach "/data/main;"#; - - managing_file_path_buf.push("manage.blz"); - if let Err(e) = fs::metadata(managing_file_path_buf.to_str().unwrap()) { - match e.kind() { - std::io::ErrorKind::NotFound => { - let mut managing_file = File::create(&mut managing_file_path_buf)?; - managing_file.write_all(manage_file_content)?; - return Ok(true); - } - _ => { - panic!("{}", e); - } - }; - }; - Ok(false) -} diff --git a/src/db/mod.rs b/src/db/mod.rs deleted file mode 100644 index 2db1a55..0000000 --- a/src/db/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod create_db; diff --git a/src/lib.rs b/src/lib.rs index d86f926..19e9e15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -pub mod db; pub mod scripting; pub mod server; pub mod shell; diff --git a/src/main.rs b/src/main.rs index 5427807..95d4773 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,6 @@ use std::io::Result; use blaze::shell; fn main() -> Result<()> { - shell::handling::handle_command_arguments()?; + shell::handling::handle_command()?; Ok(()) } diff --git a/src/scripting/ast/functional_return.rs b/src/scripting/ast/functional_return.rs index 4d6ea13..91e9ec6 100644 --- a/src/scripting/ast/functional_return.rs +++ b/src/scripting/ast/functional_return.rs @@ -1,7 +1,7 @@ use super::expression::ExpressionNode; pub struct FunctionalReturnNode { - _value: Option> + _value: Option>, } impl ExpressionNode for FunctionalReturnNode { @@ -12,8 +12,6 @@ impl ExpressionNode for FunctionalReturnNode { impl FunctionalReturnNode { pub fn new(value: Option>) -> Self { - FunctionalReturnNode { - _value: value - } + FunctionalReturnNode { _value: value } } } diff --git a/src/scripting/ast/loop_control.rs b/src/scripting/ast/loop_control.rs index 08c9500..3882a22 100644 --- a/src/scripting/ast/loop_control.rs +++ b/src/scripting/ast/loop_control.rs @@ -2,11 +2,11 @@ use super::expression::ExpressionNode; pub enum LoopControlType { Continue, - Break + Break, } pub struct LoopControlNode { - _control_type: LoopControlType + _control_type: LoopControlType, } impl ExpressionNode for LoopControlNode { @@ -18,7 +18,7 @@ impl ExpressionNode for LoopControlNode { impl LoopControlNode { pub fn new(control_type: LoopControlType) -> Self { LoopControlNode { - _control_type: control_type + _control_type: control_type, } } } diff --git a/src/scripting/ast/mod.rs b/src/scripting/ast/mod.rs index 87478f5..b905bb8 100644 --- a/src/scripting/ast/mod.rs +++ b/src/scripting/ast/mod.rs @@ -5,14 +5,14 @@ pub mod call; pub mod conditional_tree; pub mod expression; pub mod function_declaration; -pub mod identifier; -pub mod member; pub mod functional_return; -pub mod while_loop; +pub mod identifier; pub mod loop_control; +pub mod member; pub mod null; pub mod number; pub mod parameter; pub mod string; pub mod unary_operator; pub mod variable_declaration; +pub mod while_loop; diff --git a/src/scripting/ast/while_loop.rs b/src/scripting/ast/while_loop.rs index a1f63d8..0065675 100644 --- a/src/scripting/ast/while_loop.rs +++ b/src/scripting/ast/while_loop.rs @@ -2,7 +2,7 @@ use super::{body::BodyNode, expression::ExpressionNode}; pub struct WhileLoopNode { _condition: Box, - _body: BodyNode + _body: BodyNode, } impl ExpressionNode for WhileLoopNode { @@ -15,7 +15,7 @@ impl WhileLoopNode { pub fn new(condition: Box, body: BodyNode) -> Self { WhileLoopNode { _condition: condition, - _body: body + _body: body, } } } diff --git a/src/scripting/parser.rs b/src/scripting/parser.rs index 0de2db8..7869ac6 100644 --- a/src/scripting/parser.rs +++ b/src/scripting/parser.rs @@ -274,11 +274,9 @@ impl Parser { ))) } TokenType::Return => { - let returned_formula_node - = if self.move_if_next_token_is(FORMULA_TOKENS.to_vec()) { + let returned_formula_node = if self.move_if_next_token_is(FORMULA_TOKENS.to_vec()) { Some(self.require_formula()?) - } - else { + } else { None }; Ok(Box::new(FunctionalReturnNode::new(returned_formula_node))) @@ -289,15 +287,11 @@ impl Parser { self.move_position(); Ok(Box::new(WhileLoopNode::new( condition_node, - self.require_body()? + self.require_body()?, ))) } - TokenType::Continue => { - Ok(Box::new(LoopControlNode::new(LoopControlType::Continue))) - } - TokenType::Break => { - Ok(Box::new(LoopControlNode::new(LoopControlType::Break))) - } + TokenType::Continue => Ok(Box::new(LoopControlNode::new(LoopControlType::Continue))), + TokenType::Break => Ok(Box::new(LoopControlNode::new(LoopControlType::Break))), _ => Err(io::Error::new( io::ErrorKind::Other, format!( @@ -465,6 +459,7 @@ impl Parser { Ok(object_node) } + fn parse_formula(&mut self) -> Result>> { let mut unary_operator_tokens: Vec = vec![]; let mut prohibited_unary_operator_types: Vec = vec![]; @@ -490,6 +485,7 @@ impl Parser { Ok(()) }; + if self.get_current_token().is_err() || !FORMULA_TOKENS.contains(&self.get_current_token()?.token_type) { diff --git a/src/server/headers.rs b/src/server/header_parsing.rs similarity index 100% rename from src/server/headers.rs rename to src/server/header_parsing.rs diff --git a/src/server/management.rs b/src/server/management.rs new file mode 100644 index 0000000..1c9c882 --- /dev/null +++ b/src/server/management.rs @@ -0,0 +1,102 @@ +use colored::Colorize; +use ctrlc; + +use crate::{ + server::{runtime_config::RuntimeConfig, header_parsing}, + shell::handling::analyze_syntatically, +}; +use std::{ + sync::mpsc, + net::{TcpListener, TcpStream}, + process::exit, + io::{self, Result, Read}, + path::Path +}; + +pub fn run_server(args: Vec, info_channel: mpsc::Sender) -> Result<()> { + let config = RuntimeConfig::parse_arguments(args).unwrap(); + if !RuntimeConfig::blz_exists(&config.manage_file) { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!("{}: {}\n{}\n{}\n{}", + "Runtime Error".bright_red(), + "manage.blz not found; couldn't raise a server", + format_hint_string("Only able to automatically find the management file with a name 'manage.blz'"), + format_hint_string("Try to specify a path to the management file with '-m ' or rename it"), + format_hint_string("Perhaps the management file doesn't exist?"), + ))); + } + + info_channel.send(format!( + "Executing {}", + Path::new(&config.manage_file) + .file_name() + .unwrap() + .to_string_lossy() + .yellow() + )).unwrap(); + + let address = format!("{}:{}", config.host, config.port); + let listener = loop { + match TcpListener::bind(&address) { + Ok(success) => { + info_channel.send(format!("Gateway opened on {}", address.yellow())).unwrap(); + break success + }, + Err(error) => { + if error.kind() == std::io::ErrorKind::AddrInUse { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!("{}: {}", + "Runtime Error".bright_red(), + "The address is already taken; couldn't raise a server" + ))) + } + else { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("{}: {}", + "Runtime Error".bright_red(), + error + ))) + } + } + }}; + + ctrlc::set_handler(move || { + info_channel.send("Shutting down on ctrl+c...".to_string()).unwrap(); + exit(0); + }).expect("Error occured while setting ctrl+c handler"); + + for stream in listener.incoming() { + let stream = stream?; + let password = std::mem::take(&mut config.password.clone()); + + std::thread::spawn(move || handle_connection(stream, password)); + } + + Ok(()) +} + +fn format_hint_string(hint: &str) -> String { + format!( + " * {}", + hint.bright_blue() + ) +} + +fn handle_connection(mut stream: TcpStream, password: String) -> Result<()> { + let mut buffer = [0; 1024]; + let mut request = String::new(); + let bytes_read = stream.read(&mut buffer)?; + request.push_str(&String::from_utf8_lossy(&buffer[..bytes_read])); + + let header = header_parsing::parse_header(request.clone()).unwrap(); + if let Some(value) = header.get("Password") { + if password == *value { + analyze_syntatically(header_parsing::remove_empty_line(request).unwrap())? + }; + }; + + Ok(()) +} diff --git a/src/server/mod.rs b/src/server/mod.rs index 910fab1..48a8a66 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,3 +1,3 @@ -pub mod config; -pub mod headers; -pub mod server_bz; +pub mod runtime_config; +pub mod header_parsing; +pub mod management; diff --git a/src/server/config.rs b/src/server/runtime_config.rs similarity index 78% rename from src/server/config.rs rename to src/server/runtime_config.rs index 2517488..3e45e61 100644 --- a/src/server/config.rs +++ b/src/server/runtime_config.rs @@ -2,16 +2,16 @@ use dotenvy::dotenv; use regex::Regex; use std::{env, ffi::OsStr, path::Path}; -pub struct Config { +pub struct RuntimeConfig { pub host: String, pub port: String, - pub manager_file: String, + pub manage_file: String, pub password: String, } -impl Config { +impl RuntimeConfig { fn value(user_key: String) -> Option { - dotenv().expect(".env file not found"); + dotenv().expect("Environment file couldn't be found"); let user_key = Regex::new(r"env\.(\w+)") .unwrap() @@ -38,7 +38,7 @@ impl Config { let default = Self::default(); let mut host = default.host; let mut port = default.port; - let mut manager_file = default.manager_file; + let mut manage_file = default.manage_file; let mut password = default.password; for arg in 0..args.len() { @@ -48,7 +48,7 @@ impl Config { } let arg = args.get(arg + 1)?; - let value = if let Some(parse_value) = Config::value(arg.to_string()) { + let value = if let Some(parse_value) = RuntimeConfig::value(arg.to_string()) { parse_value } else { arg.to_string() @@ -57,24 +57,24 @@ impl Config { match str.as_str() { "-host" => host.clone_from(&value), "-port" => port.clone_from(&value), - "-blz_file" => manager_file.clone_from(&value), + "-m" => manage_file.clone_from(&value), "-password" => password.clone_from(&value), _ => (), } } - Some(Config { + Some(RuntimeConfig { host, port, - manager_file, + manage_file, password, }) } fn default() -> Self { - Config { + RuntimeConfig { host: "localhost".to_string(), port: "3306".to_string(), - manager_file: "./db/datablaze/manage.blz".to_string(), + manage_file: "./manage.blz".to_string(), password: "password".to_string(), } } diff --git a/src/server/server_bz.rs b/src/server/server_bz.rs deleted file mode 100644 index b5bdb9b..0000000 --- a/src/server/server_bz.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::{ - server::{config::Config, headers}, - shell::handling::analyze_syntatically, -}; -use std::io::{self, Read}; -use std::net::{TcpListener, TcpStream}; - -pub fn server_run(args: Vec) -> io::Result<()> { - let config = Config::parse_arguments(args).unwrap(); - - if !Config::blz_exists(&config.manager_file) { - return Err(io::Error::new( - io::ErrorKind::NotFound, - "blz_file not found", - )); - } - - let host = format!("{}:{}", config.host, config.port); - let listener = TcpListener::bind(host)?; - - for stream in listener.incoming() { - let stream = stream?; - let password = std::mem::take(&mut config.password.clone()); - - std::thread::spawn(move || handle_connection(stream, password)); - } - - Ok(()) -} - -fn handle_connection(mut stream: TcpStream, password: String) -> io::Result<()> { - let mut buffer = [0; 1024]; - let mut request = String::new(); - let bytes_read = stream.read(&mut buffer)?; - request.push_str(&String::from_utf8_lossy(&buffer[..bytes_read])); - - let header = headers::parse_header(request.clone()).unwrap(); - if let Some(value) = header.get("Password") { - if password == *value { - analyze_syntatically(headers::remove_empty_line(request).unwrap())? - }; - }; - - Ok(()) -} diff --git a/src/shell/handling.rs b/src/shell/handling.rs index d7ac0eb..3274a10 100644 --- a/src/shell/handling.rs +++ b/src/shell/handling.rs @@ -1,18 +1,35 @@ -use crate::db::create_db; +use colored::Colorize; + use crate::scripting::tokens::Token; use crate::scripting::{lexer, parser}; -use crate::server::server_bz; -use std::io::{self, Result}; +use crate::server::management; +use std::fs::{self, File}; +use std::io::Write; +use std::sync::mpsc; +use std::{ + io::{self, Result}, + thread +}; + +pub const OFFICIAL_REPOSITORY: &str = "https://github.com/Reeliks/blaze"; -pub fn handle_command_arguments() -> Result<()> { - let args: Vec = std::env::args().collect(); +pub fn handle_command() -> Result<()> { + let mut args: Vec = std::env::args().collect(); if args.len() < 2 { - print_help_section(); - return Ok(()); + args.push("help".to_string()); }; - match args[1].as_str() { - "create" => create_db_with_console()?, - "run" => server_bz::server_run(args)?, + let command = args[1].as_str(); + match command { + "init" => { + if create_management_file() { + println!("Thanks for using {}!", "Blaze Database".yellow()); + println!(" * To contribute the development process, check out the official repository:\n {}", OFFICIAL_REPOSITORY); + } + else { + println!("{}: The file/folder with a name 'manage.blz' already exists, couldn't initialize", "Init Error".bright_red()); + } + }, + "run" | "raise" => run_server_with_console_output(args)?, "lexer" => { let text = input_text()?; analyze_lexically(text)?; @@ -21,33 +38,62 @@ pub fn handle_command_arguments() -> Result<()> { let text = input_text()?; analyze_syntatically(text)?; } + "--help" | "help" => { + print_help_section() + } _ => { - eprintln!("Invalid arguments"); + eprintln!("'{}' is not a blaze commmand. See 'blaze --help'", command); std::process::exit(1); } } Ok(()) } +fn run_server_with_console_output(args: Vec) -> Result<()> { + let (info_channel_tx, info_channel_rx) = mpsc::channel::(); + thread::spawn(move || { + loop { + if let Ok(received) = info_channel_rx.try_recv() { + println!("{}", received); + } + } + }); + + if let Err(error) = management::run_server(args, info_channel_tx) { + eprintln!("{}", error); + }; + Ok(()) +} + fn print_help_section() { - let help_list = r#"Blaze Db 0.0.1a - available commands: - Database management - create - create a new datablaze - Blaze Language - lexer - get to see how the code is subjected to lexical analysis under the hood - parser - try the first version of a parser - run - start server"#; + let help_list = r#">> Blaze Database 0.0.1a - available commands: +Datablaze Management + init - create a new datablaze template to start working blazingly fast | create + run - raise a datablaze configurated in manage.blz | raise + +Blaze Language (Dev) + lexer - tokens parsing + parser - nodes parsing (lexing included) +"#; println!("{}", help_list); } -pub fn create_db_with_console() -> Result<()> { - let mut path = String::new(); - println!("Specify a path to a datablaze"); - io::stdin().read_line(&mut path)?; - create_db::create_db_structure(path.trim())?; +pub fn create_management_file() -> bool { + let manage_file_content = br#"manage ( + // port = "3305", + // host = "127.0.0.1", + // connections_limit = 10, +); - Ok(()) +attach "data";"#; + if fs::metadata("manage.blz").is_err() { + let mut managing_file = File::create(&mut "manage.blz").unwrap(); + managing_file.write_all(manage_file_content).unwrap(); + return true; + }; + false + } fn analyze_lexically(code_to_parse: String) -> Result> { @@ -75,7 +121,7 @@ pub fn analyze_syntatically(code: String) -> Result<()> { } fn input_text() -> io::Result { - let mut code_to_parse = String::new(); - std::io::stdin().read_line(&mut code_to_parse)?; - Ok(code_to_parse) + let mut text = String::new(); + std::io::stdin().read_line(&mut text)?; + Ok(text) } From 86d86dedae45992d6a24d301e21c2e0fc3a65fa5 Mon Sep 17 00:00:00 2001 From: panovo Date: Tue, 21 May 2024 00:19:58 +0300 Subject: [PATCH 2/7] Info Channel, ServerInstance, Connections handling, CommandHandler --- .gitignore | 1 + Cargo.lock | 717 --------------------------- Cargo.toml | 8 +- README.md | 110 ++-- src/{fs => db}/filesystem.rs | 5 +- src/{fs => db}/mod.rs | 0 src/lib.rs | 4 +- src/main.rs | 10 +- src/prelude.rs | 1 + src/routine/formatting.rs | 11 + src/routine/info_channel.rs | 39 ++ src/routine/mod.rs | 2 + src/scripting/ast/binary_operator.rs | 4 +- src/scripting/ast/boolean.rs | 4 +- src/scripting/ast/mod.rs | 2 + src/scripting/{ => ast}/tokens.rs | 6 + src/scripting/ast/unary_operator.rs | 7 +- src/scripting/context.rs | 2 +- src/scripting/executor.rs | 19 +- src/scripting/lexer.rs | 42 +- src/scripting/mod.rs | 1 - src/scripting/parser.rs | 66 +-- src/server/client_connection.rs | 43 ++ src/server/instance.rs | 176 +++++++ src/server/management.rs | 102 ---- src/server/mod.rs | 5 +- src/server/runtime_config.rs | 111 +++-- src/shell/command_handler.rs | 158 ++++++ src/shell/handling.rs | 127 ----- src/shell/mod.rs | 2 +- test.bson | Bin 205 -> 206 bytes tests/test.rs | 24 +- 32 files changed, 690 insertions(+), 1119 deletions(-) delete mode 100644 Cargo.lock rename src/{fs => db}/filesystem.rs (93%) rename src/{fs => db}/mod.rs (100%) create mode 100644 src/prelude.rs create mode 100644 src/routine/formatting.rs create mode 100644 src/routine/info_channel.rs create mode 100644 src/routine/mod.rs rename src/scripting/{ => ast}/tokens.rs (96%) create mode 100644 src/server/client_connection.rs create mode 100644 src/server/instance.rs delete mode 100644 src/server/management.rs create mode 100644 src/shell/command_handler.rs delete mode 100644 src/shell/handling.rs diff --git a/.gitignore b/.gitignore index d2a4146..df77090 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .vim .vscode *.blz +Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 0f09ef9..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,717 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blaze" -version = "0.1.0" -dependencies = [ - "bson", - "colored", - "ctrlc", - "dotenvy", - "rand", - "regex", - "serde", - "strum", - "strum_macros", -] - -[[package]] -name = "bson" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d43b38e074cc0de2957f10947e376a1d88b9c4dbab340b590800cc1b2e066b2" -dependencies = [ - "ahash", - "base64", - "bitvec", - "hex", - "indexmap", - "js-sys", - "once_cell", - "rand", - "serde", - "serde_bytes", - "serde_json", - "time", - "uuid", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] -name = "colored" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" -dependencies = [ - "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "ctrlc" -version = "3.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" -dependencies = [ - "nix", - "windows-sys 0.52.0", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "rustversion" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "serde" -version = "1.0.200" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.200" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.116" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "strum" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" - -[[package]] -name = "strum_macros" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "syn" -version = "2.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "zerocopy" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index 717f0b1..f6db798 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,16 @@ edition = "2021" [dependencies] regex = "1.10" bson = "2.10" +uuid = "1.8.0" ctrlc = "3.4.4" rand = "0.8" strum = "0.26" +chrono = "0.4.38" colored = "2.1.0" strum_macros = "0.26" dotenvy = "0.15" -serde = { version = "1.0", features = ["derive"] } +crossbeam = "0.8.4" +http-body-util = "0.1" +hyper = { version = "1", features = ["full"] } +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } diff --git a/README.md b/README.md index fc02ba4..c71b2e5 100644 --- a/README.md +++ b/README.md @@ -5,87 +5,99 @@ And of course it's blazingly fast ## ✨ Blaze Language Syntax (currently uncompleted) -1. Manager.blz (used to raise the database with packages, settings and ispects included) +1. Manage file (configuration and attaching to a datafile are only available in this type of files) ```ruby manage ( - packages = "./packages", - max_connections = 8, - port = "6980", - host = "127.0.0.1" + address = "127.0.0.1:3306", + cons_limit = 250, + con_lifetime = 120 ); -import users:all, animals:species; - -inspect all; - -attach "./data"; +import scheme[target]; +attach()"./data.dblz"; ``` -2. Basic Scheme and some declarations +2. A package with functions, events, enums, plans, and tables ```ruby package scheme; -enum Gender: str { - Male, - Female, - Other, - Unspecified +// Enum Members have their own IDs +// so you can access them without any changes but here. +enum Gender { + Unspecified = [ 0, "unknown" ], + Male = [ 1, "boy" ], + Female = [ 2, "girl" ], + Other = [ 3, "other" ], }; -enum TargetAudience: str { - Kids, - Everyone, - Adults, - Elderly +// Snake_case is the standard +mut str = Gender.Male; // "boy" +fin best_gender: str = Gender[0]; // "unknown" + +enum TargetAudience { + Kids = [ 0, lower(self [0]) ], + Everyone = [ 1, lower(self [1]) ], + Adults = [ 2, lower(self [2]) ], + Elderly = [ 3, lower(self [3]) ], }; +// Plan is a data structure that can be used for instances creation, +// and tables & lanes implementation +plan Geo { + x: float, y: float +} + +// Table ID's are created without explicit declaration, +// Exclamation mark means the field value must be unique table countries { - name: str <=50, - alpha2: str 2, - alpha3: str 3, - geolocation: geo; + name: !str[ <50 ], + alpha2: !str[ =2 ], + alpha3: !str[ =2 ], + geolocation: Geo; }; +// db.something is a call to a database table accounts: uuid { - name: str <=30 = format("User{}", self.id), - bio: str <=200, - password: str, - gender: Gender = Gender.Unspecified, - age: int >0 <100, - country: &countries?, - created_at: datetime = "now"; + name: str[ <=30 ] = format("User{}", id), + bio: str[ <=200 ], + password: str[ >8 ], + age: int[ >0 <100 ], + gender: Gender = Gender.Unspecified, + created_at: datetime = "now"; + country: db.countries?, }; - -table products: uuid { - title: str = "product", - seller: &accounts, - price: float >= 0, +plan Products { + title: str = "product", + created_at: datetime = "now", + seller: db.accounts, + price: float[>=0], description: str, - created_at: datetime = "now", - sales_count: int >=0 , - audience: TargetAudience = TargetAudience.Everyone; + sales_count: int[>-1], + audience: TargetAudience = TargetAudience.Everyone; } +table products(Products): uuid; table shopping_cart { - account: &account!, - added_products: &products[], - last_update: datetime = "now"; + account: !db.accounts, + added_products: !arr[db.products], + last_update: timestamp[local] = "now"; }; -event shopping_cart_update (&shopping_cart.added_products, "change") { - &shopping_cart.last_update = "now"; +// Should be considered +event shopping_cart_updated("update", db.shopping_cart): x { + x.last_update = "now"; }; function get_population_of(country_name: str): int { - fin country_id = &countries.{self.name=country_name}.id; - count(&accounts.{self.country=country_id}) + fin country_id = db.countries.(name=country_name).id; + count(db.accounts.(country=country_id)) }; -function get_total_cart_price(products: &products[]): float { +function get_total_cart_price(products: Products): float { mut total: float = 0; product of products { total += product.price; }; total -} \ No newline at end of file +} diff --git a/src/fs/filesystem.rs b/src/db/filesystem.rs similarity index 93% rename from src/fs/filesystem.rs rename to src/db/filesystem.rs index 97e9e44..2156997 100644 --- a/src/fs/filesystem.rs +++ b/src/db/filesystem.rs @@ -53,7 +53,10 @@ impl Fs { if *key == table_name { value.push(data.clone()); } else { - doc.insert(table_name.clone(), Bson::Array(vec![Bson::from(data.clone())])); + doc.insert( + table_name.clone(), + Bson::Array(vec![Bson::from(data.clone())]), + ); } } diff --git a/src/fs/mod.rs b/src/db/mod.rs similarity index 100% rename from src/fs/mod.rs rename to src/db/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 33deefd..48ecf0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ -pub mod fs; +pub mod db; +pub mod prelude; +pub mod routine; pub mod scripting; pub mod server; pub mod shell; diff --git a/src/main.rs b/src/main.rs index 95d4773..17f997b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,6 @@ -use std::io::Result; +use blaze::shell::command_handler::ShellCommandHandler; -use blaze::shell; - -fn main() -> Result<()> { - shell::handling::handle_command()?; - Ok(()) +#[tokio::main] +async fn main() { + ShellCommandHandler::new().handle_command().await.unwrap(); } diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..0f1c9b2 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1 @@ +pub use std::io::ErrorKind; diff --git a/src/routine/formatting.rs b/src/routine/formatting.rs new file mode 100644 index 0000000..62e6e97 --- /dev/null +++ b/src/routine/formatting.rs @@ -0,0 +1,11 @@ +use colored::Colorize; + +pub trait MessagesFormatting { + fn into_hint(self) -> String; +} + +impl MessagesFormatting for String { + fn into_hint(self) -> String { + format!(" * {}", self.bright_blue()) + } +} diff --git a/src/routine/info_channel.rs b/src/routine/info_channel.rs new file mode 100644 index 0000000..18f6258 --- /dev/null +++ b/src/routine/info_channel.rs @@ -0,0 +1,39 @@ +use crossbeam::channel::{bounded, Sender}; +use std::thread; + +use std::io::Result; + +pub struct InfoChannel { + sender: Option>, +} + +impl InfoChannel { + pub fn new(sender: Option>) -> Self { + InfoChannel { sender } + } + + pub fn send(self, message: String) -> Result<()> { + if let Some(channel) = self.sender { + channel.send(message).unwrap(); + } + Ok(()) + } +} + +impl Clone for InfoChannel { + fn clone(&self) -> Self { + InfoChannel { + sender: self.sender.clone(), + } + } +} + +pub fn get_console_info_channel() -> InfoChannel { + let (tx, rx) = bounded(100); + thread::spawn(move || loop { + if let Ok(received) = rx.try_recv() { + println!("{}", received); + } + }); + InfoChannel::new(Some(tx)) +} diff --git a/src/routine/mod.rs b/src/routine/mod.rs new file mode 100644 index 0000000..cedbbb9 --- /dev/null +++ b/src/routine/mod.rs @@ -0,0 +1,2 @@ +pub mod formatting; +pub mod info_channel; diff --git a/src/scripting/ast/binary_operator.rs b/src/scripting/ast/binary_operator.rs index a65a2ab..dce655b 100644 --- a/src/scripting/ast/binary_operator.rs +++ b/src/scripting/ast/binary_operator.rs @@ -1,6 +1,4 @@ -use crate::scripting::tokens::TokenType; - -use super::expression::ExpressionNode; +use super::{expression::ExpressionNode, tokens::TokenType}; pub struct BinaryOperatorNode { _operator: TokenType, diff --git a/src/scripting/ast/boolean.rs b/src/scripting/ast/boolean.rs index 696a1d4..c9a2733 100644 --- a/src/scripting/ast/boolean.rs +++ b/src/scripting/ast/boolean.rs @@ -1,8 +1,6 @@ use std::io; -use crate::scripting::tokens::TokenType; - -use super::expression::ExpressionNode; +use super::{expression::ExpressionNode, tokens::TokenType}; pub struct BooleanNode { _state: bool, diff --git a/src/scripting/ast/mod.rs b/src/scripting/ast/mod.rs index b905bb8..d2edd18 100644 --- a/src/scripting/ast/mod.rs +++ b/src/scripting/ast/mod.rs @@ -1,3 +1,5 @@ +pub mod tokens; + pub mod binary_operator; pub mod body; pub mod boolean; diff --git a/src/scripting/tokens.rs b/src/scripting/ast/tokens.rs similarity index 96% rename from src/scripting/tokens.rs rename to src/scripting/ast/tokens.rs index 8fa5486..d10d87d 100644 --- a/src/scripting/tokens.rs +++ b/src/scripting/ast/tokens.rs @@ -61,6 +61,9 @@ pub enum TokenType { Fin, Function, Enum, + Table, + Lane, + Plan, // Brackets LPar, RPar, @@ -95,6 +98,9 @@ impl TokenType { TokenType::Mut => r"mut\b", TokenType::Fin => r"fin\b", TokenType::Enum => r"enum\b", + TokenType::Lane => r"lane\b", + TokenType::Table => r"table\b", + TokenType::Plan => r"plan\b", TokenType::True => r"true\b", TokenType::False => r"false\b", TokenType::Null => r"null\b", diff --git a/src/scripting/ast/unary_operator.rs b/src/scripting/ast/unary_operator.rs index a67e343..8d99dcf 100644 --- a/src/scripting/ast/unary_operator.rs +++ b/src/scripting/ast/unary_operator.rs @@ -1,6 +1,7 @@ -use crate::scripting::tokens::{TokenSide, TokenType}; - -use super::expression::ExpressionNode; +use super::{ + expression::ExpressionNode, + tokens::{TokenSide, TokenType}, +}; pub struct UnaryOperatorNode { _operator: TokenType, diff --git a/src/scripting/context.rs b/src/scripting/context.rs index 8360fc3..ee1b6ac 100644 --- a/src/scripting/context.rs +++ b/src/scripting/context.rs @@ -5,7 +5,7 @@ pub struct Context { } impl Context { - fn new(code_source: String) -> Self { + pub fn new(code_source: String) -> Self { Context { code_source, position: 0, diff --git a/src/scripting/executor.rs b/src/scripting/executor.rs index 06e6693..a17274f 100644 --- a/src/scripting/executor.rs +++ b/src/scripting/executor.rs @@ -1,13 +1,16 @@ -pub struct Executor {} +use super::{ast::body::BodyNode, context::Context}; +use std::io::Result; -impl Executor { - pub fn new() -> Self { - Executor {} - } +pub struct Executor<'a> { + _context: &'a mut Context, } -impl Default for Executor { - fn default() -> Self { - Self::new() +impl<'a> Executor<'a> { + pub fn new(context: &'a mut Context) -> Self { + Executor { _context: context } + } + + pub fn execute(self, _nodes: BodyNode) -> Result<()> { + Ok(()) } } diff --git a/src/scripting/lexer.rs b/src/scripting/lexer.rs index 4c9673c..7a47aad 100644 --- a/src/scripting/lexer.rs +++ b/src/scripting/lexer.rs @@ -3,21 +3,26 @@ use regex::Regex; use std::io; use strum::IntoEnumIterator; +use crate::routine::info_channel::InfoChannel; + +use crate::prelude::*; +use super::ast::tokens::{Token, TokenType, WHITESPACE_TOKENS}; use super::context::Context; -use super::tokens::{Token, TokenType, WHITESPACE_TOKENS}; pub struct Lexer { pub context: Context, code: String, tokens: Vec, + info_channel: InfoChannel, // Connect it only on debugging } impl Lexer { - pub fn new(code: String) -> Self { - Lexer { + pub fn new(code: String, info_channel: InfoChannel) -> Self { + Self { code, context: Context::default(), tokens: vec![], + info_channel, } } @@ -31,20 +36,23 @@ impl Lexer { Ok(proceed_parsing) => { if !proceed_parsing { self.tokens.retain(|token| !token.is_type(TokenType::Space)); - return Ok(self.tokens); + return Ok(self.tokens.clone()); } let last_token = self.tokens.last().unwrap(); if !WHITESPACE_TOKENS.contains(&last_token.token_type) { let start_position = 1 + self.context.position - last_token.value.len() as u64; - println!( - "{}:{} = {}", - start_position, last_token.value, last_token.token_type - ); + self.info_channel + .clone() + .send(format!( + "{}:{} = {}", + start_position, last_token.value, last_token.token_type + )) + .unwrap(); } } Err(err) => { - eprintln!("{}", err); + self.info_channel.send(err.to_string()).unwrap(); break; } }; @@ -61,7 +69,11 @@ impl Lexer { let token_regex_string = TokenType::regex_str(&token_type); let token_regex = Regex::new(&format!(r#"^{}"#, token_regex_string)).unwrap(); if let Some(matches) = token_regex.find(positioned_code) { - let matched_str = matches.as_str(); + let matched_str = if token_type == TokenType::Number { + matches.as_str().replace('_', "") + } else { + matches.as_str().to_string() + }; self.tokens.push(Token { token_type, start: self.context.position, @@ -78,7 +90,7 @@ impl Lexer { } } Err(io::Error::new( - io::ErrorKind::Other, + ErrorKind::Other, format!( "{}: '{}' {} <-= at {}:{}:{}", "Lexical Error".bright_red(), @@ -106,7 +118,7 @@ impl Lexer { let last_token_is_number = last_token.is_type(TokenType::Number); if last_token_is_number && current_token_is_alphanumeric { return Err(io::Error::new( - io::ErrorKind::Other, + ErrorKind::Other, format!( "{}: numbers cannot end with alphanumeric <-= at {}:{}:{}", "Lexical Error".bright_red(), @@ -142,9 +154,9 @@ impl Lexer { || left_side_unresolved_chars_regex.is_match(char_before) { return Err(io::Error::new( - io::ErrorKind::Other, + ErrorKind::Other, format!( - "{}: \"{}\" near a string with no space between <-= at {}:{}:{}", + "{}: \"{}\" before a string with no space between <-= at {}:{}:{}", "Lexical Error".bright_red(), char_before, self.context.code_source, @@ -163,7 +175,7 @@ impl Lexer { .to_string(); if both_sides_unresolved_chars_regex.is_match(char_after) { return Err(io::Error::new( - io::ErrorKind::Other, + ErrorKind::Other, format!( "{}: \"{}\" after a string with no space between <-= at {}:{}:{}", "Lexical Error".bright_red(), diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 604a387..c9fc292 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -3,4 +3,3 @@ pub mod context; pub mod executor; pub mod lexer; pub mod parser; -pub mod tokens; diff --git a/src/scripting/parser.rs b/src/scripting/parser.rs index 7869ac6..5334792 100644 --- a/src/scripting/parser.rs +++ b/src/scripting/parser.rs @@ -1,26 +1,30 @@ -use super::ast::binary_operator::BinaryOperatorNode; -use super::ast::body::BodyNode; -use super::ast::boolean::BooleanNode; -use super::ast::call::CallNode; -use super::ast::conditional_tree::{ConditionalTreeNode, Conditions}; -use super::ast::expression::ExpressionNode; -use super::ast::function_declaration::FunctionDeclarationNode; -use super::ast::functional_return::FunctionalReturnNode; -use super::ast::identifier::IdentifierNode; -use super::ast::loop_control::{LoopControlNode, LoopControlType}; -use super::ast::member::MemberNode; -use super::ast::null::NullNode; -use super::ast::number::NumberNode; -use super::ast::parameter::{Parameter, ParameterType, Parameters}; -use super::ast::string::StringNode; -use super::ast::unary_operator::UnaryOperatorNode; -use super::ast::variable_declaration::VariableDeclaration; -use super::ast::while_loop::WhileLoopNode; -use super::context::Context; -use super::tokens::{ - Token, TokenSide, TokenType, BINARY_OPERATOR_TOKENS, FORMULA_TOKENS, UNARY_OPERATOR_TOKENS, - VARIABLE_ASSIGNMENT_TOKENS, +use super::ast::{ + binary_operator::BinaryOperatorNode, + body::BodyNode, + boolean::BooleanNode, + call::CallNode, + conditional_tree::{ConditionalTreeNode, Conditions}, + expression::ExpressionNode, + function_declaration::FunctionDeclarationNode, + functional_return::FunctionalReturnNode, + identifier::IdentifierNode, + loop_control::{LoopControlNode, LoopControlType}, + member::MemberNode, + null::NullNode, + number::NumberNode, + parameter::{Parameter, ParameterType, Parameters}, + string::StringNode, + tokens::{ + Token, TokenSide, TokenType, BINARY_OPERATOR_TOKENS, FORMULA_TOKENS, UNARY_OPERATOR_TOKENS, + VARIABLE_ASSIGNMENT_TOKENS, + }, + unary_operator::UnaryOperatorNode, + variable_declaration::VariableDeclaration, + while_loop::WhileLoopNode, }; +use super::context::Context; +use crate::routine::info_channel::InfoChannel; + use colored::*; use rand::seq::SliceRandom; use std::io::{self, Result}; @@ -30,16 +34,21 @@ pub struct Parser { context: Context, parser_position: u64, + _info_channel: InfoChannel, syntax_error_marking: ColoredString, } impl Parser { - pub fn new(tokens: Vec) -> Self { + pub fn new( + tokens: Vec, + info_channel: InfoChannel, // Connect it only on debugging + ) -> Self { Parser { context: Context::default(), tokens, parser_position: 0, + _info_channel: info_channel, syntax_error_marking: "Syntax Error".bright_red(), } } @@ -422,12 +431,11 @@ impl Parser { )); } }; - self.move_position(); - if self.get_current_token().is_ok() - && self.get_current_token()?.is_type(TokenType::Comma) - { - self.move_position(); + if !self.move_if_next_token_is(vec![TokenType::Comma]) { + break; } + self.move_position(); + continue; } Ok(arguments) } @@ -459,7 +467,6 @@ impl Parser { Ok(object_node) } - fn parse_formula(&mut self) -> Result>> { let mut unary_operator_tokens: Vec = vec![]; let mut prohibited_unary_operator_types: Vec = vec![]; @@ -485,7 +492,6 @@ impl Parser { Ok(()) }; - if self.get_current_token().is_err() || !FORMULA_TOKENS.contains(&self.get_current_token()?.token_type) { diff --git a/src/server/client_connection.rs b/src/server/client_connection.rs new file mode 100644 index 0000000..6139511 --- /dev/null +++ b/src/server/client_connection.rs @@ -0,0 +1,43 @@ +use std::time::Duration; + +use chrono::{DateTime, Local}; +use tokio::{task::JoinHandle, time}; +use uuid::Uuid; + +// A client connection works like a session +pub struct ClientConnection { + pub id: Uuid, + pub closed: bool, + _creation_time: DateTime, + lifetime: Duration, + expiration_timeout: Option>, +} + +impl ClientConnection { + pub async fn create(creation_time: DateTime, lifetime: Duration) -> Self { + let mut new_session = Self { + id: Uuid::new_v4(), + _creation_time: creation_time, + lifetime, + expiration_timeout: None, + closed: false, + }; + + new_session.reset_expiration_timeout(); + new_session + } + + fn reset_expiration_timeout(&mut self) { + if let Some(expiration_timeout) = &self.expiration_timeout { + expiration_timeout.abort(); + }; + unsafe { + let this = &mut *(self as *mut Self); + let timeout_duration = self.lifetime; + self.expiration_timeout = Some(tokio::spawn(async move { + time::sleep(timeout_duration).await; + this.closed = true; + })); + }; + } +} diff --git a/src/server/instance.rs b/src/server/instance.rs new file mode 100644 index 0000000..7fad7e6 --- /dev/null +++ b/src/server/instance.rs @@ -0,0 +1,176 @@ +use chrono::Local; +use colored::Colorize; +use ctrlc; + +use crate::prelude::*; +use super::{ + client_connection::ClientConnection, + header_parsing, + runtime_config::RuntimeConfig +}; +use crate::routine::{ + formatting::MessagesFormatting, + info_channel::InfoChannel +}; +use std::{ + io::{self, Read, Result, Write}, + net::TcpListener, + path::Path, + process::exit, + thread, + time::Duration, +}; + +pub struct ServerInstance { + info_channel: InfoChannel, + connections: Vec, + config: RuntimeConfig, +} + +impl ServerInstance { + pub fn new(info_channel: InfoChannel) -> Self { + Self { + info_channel, + connections: vec![], + config: RuntimeConfig::default(), + } + } + + pub async fn launch(&mut self, args: &[String]) -> Result<()> { + self.config = RuntimeConfig::parse_arguments(args.to_vec()).unwrap(); + let error_marking = "Server Error".bright_red(); + if !RuntimeConfig::blz_exists(&self.config.manage_file) { + let error_message = format!( + "{}: {} not found; couldn't raise a server{}", + error_marking, + &self.config.manage_file, + if args.is_empty() && self.config.manage_file == "main.manage.blz" { + "\n".to_owned()+&String::from("Try to specify a path to the management file").into_hint() + } else { + "".to_string() + }, + ); + return Err(io::Error::new(ErrorKind::NotFound, error_message)); + } + let listener = match TcpListener::bind(&self.config.address) { + Ok(success) => { + self.info_channel + .clone() + .send(format!( + "Gateway opened on {}", + self.config.address.yellow() + )) + .unwrap(); + success + } + Err(error) => { + return Err(io::Error::new( + error.kind(), + format!( + "{}: {}; could not start", + error_marking, + match error.kind() { + ErrorKind::AddrInUse => { + "The address is already taken".to_string() + } + ErrorKind::PermissionDenied => { + "An attempt to bind the port was refused".to_string() + } + ErrorKind::InvalidInput => { + format!("{}: Invalid socket address", error_marking) + } + _ => { + format!("{}: {}", error_marking, error) + } + } + ), + )); + } + }; + + let info_channel = self.info_channel.clone(); + + info_channel + .clone() + .send(format!( + "Executing {}", + Path::new(&self.config.manage_file) + .file_name() + .unwrap() + .to_string_lossy() + .yellow() + )) + .unwrap(); + + ctrlc::set_handler(move || { + info_channel + .clone() + .send("\nInterrupted with ^C, shutdown".to_string()) + .unwrap(); + exit(0); + }) + .expect("Error occured while setting ctrl+c handler"); + + self.start_closed_connections_cleaner().await; + self.handle_connections(listener).await?; + Ok(()) + } + + async fn start_closed_connections_cleaner(&mut self) -> tokio::task::JoinHandle<()> { + unsafe { + let this = &mut *(self as *mut Self); + tokio::spawn(async move { + loop { + thread::sleep(Duration::from_secs(10)); + this.connections + .retain(|connection: &ClientConnection| !connection.closed); + } + }) + } + } + + async fn handle_connections(&mut self, listener: TcpListener) -> Result<()> { + for stream in listener.incoming() { + let mut stream = stream.unwrap(); + let correct_password = &self.config.password; + + let mut buffer = [0; 1024]; + let mut request = String::new(); + + let bytesize = stream.read(&mut buffer).unwrap(); + request.push_str(&String::from_utf8_lossy(&buffer[..bytesize])); + + let header = header_parsing::parse_header(request.clone()).unwrap(); + + let client_password = header.get("password"); + if client_password.is_none() || correct_password != client_password.unwrap() { + stream.write_all(b"HTTP/1.1 401 Unauthorized - Incorrect password\r\n\n")?; + continue; + } else if self.connections.len() + 1 > self.config.cons_limit as usize { + stream.write_all(b"HTTP/1.1 503 Sessions Limit\r\n\n")?; + } + let new_session = + ClientConnection::create(Local::now(), self.config.con_lifetime).await; + let session_id = new_session.id; + self.connections.push(new_session); + let response_content = format!("{}", session_id); + + self.info_channel + .clone() + .send("A new connection's been created".to_string()) + .unwrap(); + + stream + .write_all( + format!( + "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nContent-Length: {}\r\n\n{}", + response_content.len(), + response_content + ) + .as_bytes(), + ) + .unwrap(); + } + Ok(()) + } +} diff --git a/src/server/management.rs b/src/server/management.rs deleted file mode 100644 index 1c9c882..0000000 --- a/src/server/management.rs +++ /dev/null @@ -1,102 +0,0 @@ -use colored::Colorize; -use ctrlc; - -use crate::{ - server::{runtime_config::RuntimeConfig, header_parsing}, - shell::handling::analyze_syntatically, -}; -use std::{ - sync::mpsc, - net::{TcpListener, TcpStream}, - process::exit, - io::{self, Result, Read}, - path::Path -}; - -pub fn run_server(args: Vec, info_channel: mpsc::Sender) -> Result<()> { - let config = RuntimeConfig::parse_arguments(args).unwrap(); - if !RuntimeConfig::blz_exists(&config.manage_file) { - return Err(io::Error::new( - io::ErrorKind::NotFound, - format!("{}: {}\n{}\n{}\n{}", - "Runtime Error".bright_red(), - "manage.blz not found; couldn't raise a server", - format_hint_string("Only able to automatically find the management file with a name 'manage.blz'"), - format_hint_string("Try to specify a path to the management file with '-m ' or rename it"), - format_hint_string("Perhaps the management file doesn't exist?"), - ))); - } - - info_channel.send(format!( - "Executing {}", - Path::new(&config.manage_file) - .file_name() - .unwrap() - .to_string_lossy() - .yellow() - )).unwrap(); - - let address = format!("{}:{}", config.host, config.port); - let listener = loop { - match TcpListener::bind(&address) { - Ok(success) => { - info_channel.send(format!("Gateway opened on {}", address.yellow())).unwrap(); - break success - }, - Err(error) => { - if error.kind() == std::io::ErrorKind::AddrInUse { - return Err(io::Error::new( - io::ErrorKind::NotFound, - format!("{}: {}", - "Runtime Error".bright_red(), - "The address is already taken; couldn't raise a server" - ))) - } - else { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("{}: {}", - "Runtime Error".bright_red(), - error - ))) - } - } - }}; - - ctrlc::set_handler(move || { - info_channel.send("Shutting down on ctrl+c...".to_string()).unwrap(); - exit(0); - }).expect("Error occured while setting ctrl+c handler"); - - for stream in listener.incoming() { - let stream = stream?; - let password = std::mem::take(&mut config.password.clone()); - - std::thread::spawn(move || handle_connection(stream, password)); - } - - Ok(()) -} - -fn format_hint_string(hint: &str) -> String { - format!( - " * {}", - hint.bright_blue() - ) -} - -fn handle_connection(mut stream: TcpStream, password: String) -> Result<()> { - let mut buffer = [0; 1024]; - let mut request = String::new(); - let bytes_read = stream.read(&mut buffer)?; - request.push_str(&String::from_utf8_lossy(&buffer[..bytes_read])); - - let header = header_parsing::parse_header(request.clone()).unwrap(); - if let Some(value) = header.get("Password") { - if password == *value { - analyze_syntatically(header_parsing::remove_empty_line(request).unwrap())? - }; - }; - - Ok(()) -} diff --git a/src/server/mod.rs b/src/server/mod.rs index 48a8a66..b6c4c2b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,3 +1,4 @@ -pub mod runtime_config; +pub mod client_connection; pub mod header_parsing; -pub mod management; +pub mod instance; +pub mod runtime_config; diff --git a/src/server/runtime_config.rs b/src/server/runtime_config.rs index 3e45e61..85f9a41 100644 --- a/src/server/runtime_config.rs +++ b/src/server/runtime_config.rs @@ -1,16 +1,36 @@ +use colored::Colorize; use dotenvy::dotenv; use regex::Regex; -use std::{env, ffi::OsStr, path::Path}; +use std::{ + env, + ffi::OsStr, + io::{self, Result}, + path::Path, + time::Duration, +}; pub struct RuntimeConfig { - pub host: String, - pub port: String, + pub address: String, pub manage_file: String, pub password: String, + pub cons_limit: u32, + pub con_lifetime: Duration, +} + +impl Default for RuntimeConfig { + fn default() -> Self { + Self { + address: "localhost:3306".to_string(), + manage_file: "./main.manage.blz".to_string(), + password: "password".to_string(), + cons_limit: 100, + con_lifetime: Duration::from_secs(30), + } + } } impl RuntimeConfig { - fn value(user_key: String) -> Option { + fn get_env_value(user_key: String) -> Option { dotenv().expect("Environment file couldn't be found"); let user_key = Regex::new(r"env\.(\w+)") @@ -34,48 +54,73 @@ impl RuntimeConfig { true } - pub fn parse_arguments(args: Vec) -> Option { + pub fn parse_arguments(console_args: Vec) -> Result { let default = Self::default(); - let mut host = default.host; - let mut port = default.port; - let mut manage_file = default.manage_file; + let mut address = default.address; let mut password = default.password; + let mut manage_file: String = "main.manage.blz".to_string(); + let mut cons_limit: u32 = default.cons_limit; + let mut con_lifetime: Duration = default.con_lifetime; - for arg in 0..args.len() { - let str = &args[arg]; - if str.chars().nth(0)? != '-' { + let manage_file_fullname_regex = Regex::new(r".*\.manage\.blz$").unwrap(); + + for console_arg_index in 0..console_args.len() { + let argument_keyword = &console_args[console_arg_index]; + if argument_keyword.chars().nth(0).unwrap() != '-' { + if console_arg_index == 0 { + manage_file = if !manage_file_fullname_regex.is_match(argument_keyword) { + format!("{}.manage.blz", argument_keyword) + } else { + argument_keyword.to_string() + }; + }; continue; } - let arg = args.get(arg + 1)?; - let value = if let Some(parse_value) = RuntimeConfig::value(arg.to_string()) { - parse_value - } else { - arg.to_string() + let argument_value = match console_args.get(console_arg_index + 1) { + Some(value) => { + if let Some(env_value) = + RuntimeConfig::get_env_value(argument_keyword.to_string()) + { + env_value + } else { + value.to_string() + } + } + None => { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!( + "{}: The value for '{}' argument isn't provided", + "Input Error".bright_red(), + &argument_keyword[1..argument_keyword.len()] + ), + )); + } }; - match str.as_str() { - "-host" => host.clone_from(&value), - "-port" => port.clone_from(&value), - "-m" => manage_file.clone_from(&value), - "-password" => password.clone_from(&value), + match argument_keyword.as_str() { + "-address" => address.clone_from(&argument_value), + "-password" => password.clone_from(&argument_value), + "-session_lifetime" => con_lifetime.clone_from(&Duration::from_secs( + argument_value + .parse() + .expect("Provide the right amount of seconds a session lives"), + )), + "-sessions_limit" => cons_limit.clone_from( + &argument_value + .parse() + .expect("Unable to parse 'sessions_limit' field due to the incorrect type"), + ), _ => (), } } - Some(RuntimeConfig { - host, - port, + Ok(RuntimeConfig { + address, manage_file, password, + cons_limit, + con_lifetime, }) } - - fn default() -> Self { - RuntimeConfig { - host: "localhost".to_string(), - port: "3306".to_string(), - manage_file: "./manage.blz".to_string(), - password: "password".to_string(), - } - } } diff --git a/src/shell/command_handler.rs b/src/shell/command_handler.rs new file mode 100644 index 0000000..eb5fa14 --- /dev/null +++ b/src/shell/command_handler.rs @@ -0,0 +1,158 @@ +use crate::routine::formatting::MessagesFormatting; +use crate::routine::info_channel::{get_console_info_channel, InfoChannel}; +use crate::scripting::{ast::tokens::Token, lexer, parser}; +use crate::server::instance::ServerInstance; +use colored::Colorize; +use std::fs::{self, File}; +use std::io::{self, Result, Write}; + +pub const OFFICIAL_REPOSITORY: &str = "https://github.com/Reeliks/blaze"; + +pub struct ShellCommandHandler { + info_channel: InfoChannel, +} + +impl Default for ShellCommandHandler { + fn default() -> Self { + Self { + info_channel: get_console_info_channel(), + } + } +} + +impl ShellCommandHandler { + pub fn new() -> Self { + Self::default() + } + + pub async fn handle_command(&mut self) -> Result<()> { + let mut args: Vec = std::env::args().collect::>()[1..].to_vec(); + if args.is_empty() { + args.push("help".to_string()); + }; + let command = args[0].as_str(); + match command { + "init" => { + let mut manage_file_name = "main"; + if let Some(first_arg) = args.get(1) { + if !first_arg.starts_with('-') { + manage_file_name = first_arg + } + } + + if Self::create_management_file(manage_file_name) { + println!("Thanks for using {}!", "Blaze Database".yellow()); + println!(" * To contribute the development process, check out the official repository:\n {}", OFFICIAL_REPOSITORY); + } else { + println!( + "{}: The file/folder with a name '{}' already exists\n{}", + "Init Error".bright_red(), + manage_file_name, + String::from("Try specifying another name").into_hint() + ); + } + } + "run" | "raise" => self.run_server(args).await?, + "lexer" => { + let text = Self::read_console_input()?; + self.run_lexer(text, true)?; + } + "parser" => { + let text = Self::read_console_input()?; + self.run_parser(text)?; + } + "--help" | "help" => Self::print_help_section(), + _ => { + eprintln!("'{}' is not a blaze commmand. See 'blaze --help'", command); + std::process::exit(1); + } + } + Ok(()) + } + + async fn run_server(&mut self, args: Vec) -> Result<()> { + if let Err(error) = ServerInstance::new(self.info_channel.clone()) + .launch(&args[1..]) + .await + { + eprintln!("{}", error); + }; + Ok(()) + } + + // Do not indent raw strings below" + fn print_help_section() { + let help_list = r#">> Blaze Database 0.0.1a - available commands: +Datablaze Management + init - create a new datablaze template to start working blazingly fast + run - raise a datablaze configurated in manage.blz | raise + * manage_file_name, -cons_limit, con_lifetime (secs), -address, -password + +Blaze Language (Dev) + lexer - tokens parsing + parser - nodes parsing (lexing included) +"#; + + println!("{}", help_list); + } + + pub fn create_management_file(name: &str) -> bool { + let manage_file_content = br#"manage ( + // address = "localhost:3306", + // cons_limit = 100, + // con_lifetime = 60 +); + +attach "data";"#; + + let manage_file_fullname = &format!( + "{}.manage.blz", + if !name.is_empty() { name } else { "main" } + ); + if fs::metadata(manage_file_fullname).is_err() { + let mut manage_file = File::create(manage_file_fullname).unwrap(); + manage_file.write_all(manage_file_content).unwrap(); + return true; + }; + false + } + + pub fn run_lexer(&self, code_to_parse: String, show_final_message: bool) -> Result> { + let mut code_lexer = lexer::Lexer::new(code_to_parse, self.info_channel.clone()); + code_lexer + .get_context() + .set_code_source("Shell".to_string()); + let tokens = code_lexer.analyze()?; + + if !tokens.is_empty() && show_final_message { + self.info_channel.clone().send(format!( + "Lexiical Analysis successfully completed! Tokens count: {}", + tokens.len() + ))?; + } + Ok(tokens) + } + + pub fn run_parser(&self, code: String) -> Result<()> { + let tokens = self.run_lexer(code, false)?; + let mut code_parser = parser::Parser::new(tokens, self.info_channel.clone()); + code_parser + .get_context() + .set_code_source("Shell".to_string()); + let nodes = code_parser.parse()?.nodes; + if !nodes.is_empty() { + self.info_channel.clone().send(format!( + "Parsing successfully completed! Nodes Count: {}", + nodes.len() + ))?; + } + + Ok(()) + } + + fn read_console_input() -> io::Result { + let mut text = String::new(); + std::io::stdin().read_line(&mut text)?; + Ok(text.trim().to_string()) + } +} diff --git a/src/shell/handling.rs b/src/shell/handling.rs deleted file mode 100644 index 3274a10..0000000 --- a/src/shell/handling.rs +++ /dev/null @@ -1,127 +0,0 @@ -use colored::Colorize; - -use crate::scripting::tokens::Token; -use crate::scripting::{lexer, parser}; -use crate::server::management; -use std::fs::{self, File}; -use std::io::Write; -use std::sync::mpsc; -use std::{ - io::{self, Result}, - thread -}; - -pub const OFFICIAL_REPOSITORY: &str = "https://github.com/Reeliks/blaze"; - -pub fn handle_command() -> Result<()> { - let mut args: Vec = std::env::args().collect(); - if args.len() < 2 { - args.push("help".to_string()); - }; - let command = args[1].as_str(); - match command { - "init" => { - if create_management_file() { - println!("Thanks for using {}!", "Blaze Database".yellow()); - println!(" * To contribute the development process, check out the official repository:\n {}", OFFICIAL_REPOSITORY); - } - else { - println!("{}: The file/folder with a name 'manage.blz' already exists, couldn't initialize", "Init Error".bright_red()); - } - }, - "run" | "raise" => run_server_with_console_output(args)?, - "lexer" => { - let text = input_text()?; - analyze_lexically(text)?; - } - "parser" => { - let text = input_text()?; - analyze_syntatically(text)?; - } - "--help" | "help" => { - print_help_section() - } - _ => { - eprintln!("'{}' is not a blaze commmand. See 'blaze --help'", command); - std::process::exit(1); - } - } - Ok(()) -} - -fn run_server_with_console_output(args: Vec) -> Result<()> { - let (info_channel_tx, info_channel_rx) = mpsc::channel::(); - thread::spawn(move || { - loop { - if let Ok(received) = info_channel_rx.try_recv() { - println!("{}", received); - } - } - }); - - if let Err(error) = management::run_server(args, info_channel_tx) { - eprintln!("{}", error); - }; - Ok(()) -} - -fn print_help_section() { - let help_list = r#">> Blaze Database 0.0.1a - available commands: -Datablaze Management - init - create a new datablaze template to start working blazingly fast | create - run - raise a datablaze configurated in manage.blz | raise - -Blaze Language (Dev) - lexer - tokens parsing - parser - nodes parsing (lexing included) -"#; - - println!("{}", help_list); -} - -pub fn create_management_file() -> bool { - let manage_file_content = br#"manage ( - // port = "3305", - // host = "127.0.0.1", - // connections_limit = 10, -); - -attach "data";"#; - if fs::metadata("manage.blz").is_err() { - let mut managing_file = File::create(&mut "manage.blz").unwrap(); - managing_file.write_all(manage_file_content).unwrap(); - return true; - }; - false - -} - -fn analyze_lexically(code_to_parse: String) -> Result> { - let mut code_lexer = lexer::Lexer::new(code_to_parse); - code_lexer - .get_context() - .set_code_source("Shell".to_string()); - Ok(code_lexer.analyze().unwrap()) -} - -pub fn analyze_syntatically(code: String) -> Result<()> { - let tokens = analyze_lexically(code)?; - let mut code_parser = parser::Parser::new(tokens); - code_parser - .get_context() - .set_code_source("Shell".to_string()); - let nodes = code_parser.parse()?.nodes; - if !nodes.is_empty() { - println!( - "Parsing successfully completed! Nodes Count: {}", - nodes.len() - ); - } - Ok(()) -} - -fn input_text() -> io::Result { - let mut text = String::new(); - std::io::stdin().read_line(&mut text)?; - Ok(text) -} diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 17af089..d86bd4d 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1 +1 @@ -pub mod handling; +pub mod command_handler; diff --git a/test.bson b/test.bson index 057128e8f39aa2b6b26a2b26c4ba8c40f04a07d6..c796f81b6d9fdf2804854670f5d6b1d8008ae8b5 100644 GIT binary patch delta 8 PcmX@hc#d(xSw=1Z5Ca1S delta 6 NcmX@dc$RU(SpW(H0{Z{} diff --git a/tests/test.rs b/tests/test.rs index b510a2c..fe75d4c 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,8 +1,8 @@ -use blaze::db::create_db; -use blaze::scripting::lexer::Lexer; -use blaze::scripting::parser::Parser; -use blaze::scripting::tokens::TokenType; -use blaze::server::headers; +use blaze::{ + routine::info_channel::get_console_info_channel, + scripting::{ast::tokens::TokenType, lexer::Lexer, parser::Parser}, + server::header_parsing::parse_header, +}; #[test] fn test_lexer() { @@ -14,7 +14,7 @@ fn test_lexer() { TokenType::Else, ]; - let code_lexer = Lexer::new(code_to_parse); + let code_lexer = Lexer::new(code_to_parse, get_console_info_channel()); let tokens = code_lexer.analyze().unwrap(); let actual_token_types: Vec = tokens @@ -26,12 +26,12 @@ fn test_lexer() { } fn parser(code: &str) -> std::io::Result { - let mut code_lexer = Lexer::new(code.to_string()); + let mut code_lexer = Lexer::new(code.to_string(), get_console_info_channel()); let code_source = String::from("Tests"); code_lexer.get_context().code_source = code_source.clone(); let tokens = code_lexer.analyze()?; - let mut code_parser = Parser::new(tokens.clone()); + let mut code_parser = Parser::new(tokens.clone(), get_console_info_channel()); code_parser.get_context().code_source = code_source; let ast = code_parser.parse(); @@ -53,18 +53,12 @@ fn test_parser() { .unwrap()); } -#[test] -fn test_cteate_db() { - let is_create = create_db::create_db_structure("./db".trim()).is_ok(); - assert!(is_create); -} - #[test] fn test_header_parser() { let response = "POST / HTTP/1.1\nHost: localhost:3300\nUser-Agent: curl/8.7.1\nAccept: */*\nPassword: 1221\n" .to_string(); - let hashmap = headers::parse_header(response).unwrap(); + let hashmap = parse_header(response).unwrap(); if let Some(value) = hashmap.get("Password") { assert!(value == "1221"); } From b1b5d6c20fcaa53374daa1e79d2edd3668288816 Mon Sep 17 00:00:00 2001 From: Panovo <131530245+Reeliks@users.noreply.github.com> Date: Tue, 21 May 2024 00:46:00 +0300 Subject: [PATCH 3/7] Removing formatting test --- .github/workflows/code.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml index d688bf9..2e1ac19 100644 --- a/.github/workflows/code.yml +++ b/.github/workflows/code.yml @@ -22,8 +22,8 @@ jobs: override: true components: rustfmt, clippy - - name: Check formatting - run: cargo fmt -- --check +# - name: Check formatting +# run: cargo fmt -- --check - name: Run clippy run: cargo clippy --all-features -- -D warnings From 3d86e39eef86ca2afd3d8cdbbdfad795a8d5cd2e Mon Sep 17 00:00:00 2001 From: panovo Date: Tue, 21 May 2024 00:56:29 +0300 Subject: [PATCH 4/7] README.md small update --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c71b2e5..aaacb06 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ import scheme[target]; attach()"./data.dblz"; ``` -2. A package with functions, events, enums, plans, and tables +2. A package with functions, events, enums, plans, lanes, and tables ```ruby package scheme; @@ -31,7 +31,7 @@ enum Gender { }; // Snake_case is the standard -mut str = Gender.Male; // "boy" +mut variable_showcase = Gender.Male; // "boy" fin best_gender: str = Gender[0]; // "unknown" enum TargetAudience { @@ -56,7 +56,8 @@ table countries { geolocation: Geo; }; -// db.something is a call to a database +// db.countries is some sort of a foreign key, +// Question Mark means the country field can be null table accounts: uuid { name: str[ <=30 ] = format("User{}", id), bio: str[ <=200 ], @@ -90,7 +91,10 @@ event shopping_cart_updated("update", db.shopping_cart): x { }; function get_population_of(country_name: str): int { - fin country_id = db.countries.(name=country_name).id; + // db.contries.() is a call to a database, + // the condition inside parenthesis filters the "rows"; + // .id returns an array of all the IDs of the filtered rows + fin country_id = db.countries.(self.name==country_name).id; count(db.accounts.(country=country_id)) }; From 00147657f937c6a076c6d7e596eda3d15df6afc4 Mon Sep 17 00:00:00 2001 From: BlackSoulHub Date: Tue, 21 May 2024 08:34:26 +0000 Subject: [PATCH 5/7] fmt --- src/scripting/lexer.rs | 2 +- src/server/instance.rs | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/scripting/lexer.rs b/src/scripting/lexer.rs index 7a47aad..0e96f4b 100644 --- a/src/scripting/lexer.rs +++ b/src/scripting/lexer.rs @@ -5,9 +5,9 @@ use strum::IntoEnumIterator; use crate::routine::info_channel::InfoChannel; -use crate::prelude::*; use super::ast::tokens::{Token, TokenType, WHITESPACE_TOKENS}; use super::context::Context; +use crate::prelude::*; pub struct Lexer { pub context: Context, diff --git a/src/server/instance.rs b/src/server/instance.rs index 7fad7e6..4442b36 100644 --- a/src/server/instance.rs +++ b/src/server/instance.rs @@ -2,16 +2,9 @@ use chrono::Local; use colored::Colorize; use ctrlc; +use super::{client_connection::ClientConnection, header_parsing, runtime_config::RuntimeConfig}; use crate::prelude::*; -use super::{ - client_connection::ClientConnection, - header_parsing, - runtime_config::RuntimeConfig -}; -use crate::routine::{ - formatting::MessagesFormatting, - info_channel::InfoChannel -}; +use crate::routine::{formatting::MessagesFormatting, info_channel::InfoChannel}; use std::{ io::{self, Read, Result, Write}, net::TcpListener, @@ -45,7 +38,8 @@ impl ServerInstance { error_marking, &self.config.manage_file, if args.is_empty() && self.config.manage_file == "main.manage.blz" { - "\n".to_owned()+&String::from("Try to specify a path to the management file").into_hint() + "\n".to_owned() + + &String::from("Try to specify a path to the management file").into_hint() } else { "".to_string() }, From 08135c7fb16c2c0109de7f5a8c77b398e1ceafcc Mon Sep 17 00:00:00 2001 From: BlackSoulHub Date: Tue, 21 May 2024 08:49:21 +0000 Subject: [PATCH 6/7] uncomment fmt check --- .github/workflows/code.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml index 2e1ac19..d688bf9 100644 --- a/.github/workflows/code.yml +++ b/.github/workflows/code.yml @@ -22,8 +22,8 @@ jobs: override: true components: rustfmt, clippy -# - name: Check formatting -# run: cargo fmt -- --check + - name: Check formatting + run: cargo fmt -- --check - name: Run clippy run: cargo clippy --all-features -- -D warnings From 9adaabbecdd7e73c618b1f1326b650f588ac478d Mon Sep 17 00:00:00 2001 From: panovo Date: Tue, 21 May 2024 14:36:11 +0300 Subject: [PATCH 7/7] ClientConnection -> ClientSession, small rework --- README.md | 4 +-- src/scripting/executor.rs | 2 +- src/scripting/lexer.rs | 2 +- src/server/client_connection.rs | 43 --------------------------------- src/server/client_session.rs | 40 ++++++++++++++++++++++++++++++ src/server/instance.rs | 36 ++++++++++++--------------- src/server/mod.rs | 2 +- src/server/runtime_config.rs | 20 +++++++-------- src/shell/command_handler.rs | 4 +-- 9 files changed, 72 insertions(+), 81 deletions(-) delete mode 100644 src/server/client_connection.rs create mode 100644 src/server/client_session.rs diff --git a/README.md b/README.md index aaacb06..20bc612 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ And of course it's blazingly fast ```ruby manage ( address = "127.0.0.1:3306", - cons_limit = 250, - con_lifetime = 120 + sessions_limit = 250, + session_lifetime = 120 ); import scheme[target]; diff --git a/src/scripting/executor.rs b/src/scripting/executor.rs index a17274f..4f3fbef 100644 --- a/src/scripting/executor.rs +++ b/src/scripting/executor.rs @@ -7,7 +7,7 @@ pub struct Executor<'a> { impl<'a> Executor<'a> { pub fn new(context: &'a mut Context) -> Self { - Executor { _context: context } + Self { _context: context } } pub fn execute(self, _nodes: BodyNode) -> Result<()> { diff --git a/src/scripting/lexer.rs b/src/scripting/lexer.rs index 7a47aad..0e96f4b 100644 --- a/src/scripting/lexer.rs +++ b/src/scripting/lexer.rs @@ -5,9 +5,9 @@ use strum::IntoEnumIterator; use crate::routine::info_channel::InfoChannel; -use crate::prelude::*; use super::ast::tokens::{Token, TokenType, WHITESPACE_TOKENS}; use super::context::Context; +use crate::prelude::*; pub struct Lexer { pub context: Context, diff --git a/src/server/client_connection.rs b/src/server/client_connection.rs deleted file mode 100644 index 6139511..0000000 --- a/src/server/client_connection.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::time::Duration; - -use chrono::{DateTime, Local}; -use tokio::{task::JoinHandle, time}; -use uuid::Uuid; - -// A client connection works like a session -pub struct ClientConnection { - pub id: Uuid, - pub closed: bool, - _creation_time: DateTime, - lifetime: Duration, - expiration_timeout: Option>, -} - -impl ClientConnection { - pub async fn create(creation_time: DateTime, lifetime: Duration) -> Self { - let mut new_session = Self { - id: Uuid::new_v4(), - _creation_time: creation_time, - lifetime, - expiration_timeout: None, - closed: false, - }; - - new_session.reset_expiration_timeout(); - new_session - } - - fn reset_expiration_timeout(&mut self) { - if let Some(expiration_timeout) = &self.expiration_timeout { - expiration_timeout.abort(); - }; - unsafe { - let this = &mut *(self as *mut Self); - let timeout_duration = self.lifetime; - self.expiration_timeout = Some(tokio::spawn(async move { - time::sleep(timeout_duration).await; - this.closed = true; - })); - }; - } -} diff --git a/src/server/client_session.rs b/src/server/client_session.rs new file mode 100644 index 0000000..196c612 --- /dev/null +++ b/src/server/client_session.rs @@ -0,0 +1,40 @@ +use std::time::Duration; + +use chrono::{DateTime, Local}; +use uuid::Uuid; + +// A client connection works like a session +pub struct ClientSession { + pub id: Uuid, + pub _creation_time: DateTime, + pub expiration_time: Option>, +} + +impl ClientSession { + pub fn new(creation_time: DateTime) -> Self { + Self { + id: Uuid::new_v4(), + _creation_time: creation_time, + expiration_time: None, + } + } + + pub fn is_active(&self) -> bool { + if self.expiration_time.is_none() { + return true; + } + Local::now() < self.expiration_time.unwrap() + } + + pub fn activate_indefinitely(&mut self) { + self.expiration_time = None + } + + pub fn desactivate(&mut self) { + self.expiration_time = Some(Local::now()) + } + + pub fn activate_temporairly(&mut self, lifetime: Duration) { + self.expiration_time = Some(Local::now() + lifetime) + } +} diff --git a/src/server/instance.rs b/src/server/instance.rs index 7fad7e6..f10fc15 100644 --- a/src/server/instance.rs +++ b/src/server/instance.rs @@ -2,16 +2,9 @@ use chrono::Local; use colored::Colorize; use ctrlc; +use super::{client_session::ClientSession, header_parsing, runtime_config::RuntimeConfig}; use crate::prelude::*; -use super::{ - client_connection::ClientConnection, - header_parsing, - runtime_config::RuntimeConfig -}; -use crate::routine::{ - formatting::MessagesFormatting, - info_channel::InfoChannel -}; +use crate::routine::{formatting::MessagesFormatting, info_channel::InfoChannel}; use std::{ io::{self, Read, Result, Write}, net::TcpListener, @@ -23,7 +16,7 @@ use std::{ pub struct ServerInstance { info_channel: InfoChannel, - connections: Vec, + sessions: Vec, config: RuntimeConfig, } @@ -31,7 +24,7 @@ impl ServerInstance { pub fn new(info_channel: InfoChannel) -> Self { Self { info_channel, - connections: vec![], + sessions: vec![], config: RuntimeConfig::default(), } } @@ -45,7 +38,8 @@ impl ServerInstance { error_marking, &self.config.manage_file, if args.is_empty() && self.config.manage_file == "main.manage.blz" { - "\n".to_owned()+&String::from("Try to specify a path to the management file").into_hint() + "\n".to_owned() + + &String::from("Try to specify a path to the management file").into_hint() } else { "".to_string() }, @@ -111,19 +105,19 @@ impl ServerInstance { }) .expect("Error occured while setting ctrl+c handler"); - self.start_closed_connections_cleaner().await; + self.start_closed_sessions_cleaner().await; self.handle_connections(listener).await?; Ok(()) } - async fn start_closed_connections_cleaner(&mut self) -> tokio::task::JoinHandle<()> { + async fn start_closed_sessions_cleaner(&mut self) -> tokio::task::JoinHandle<()> { unsafe { let this = &mut *(self as *mut Self); tokio::spawn(async move { loop { thread::sleep(Duration::from_secs(10)); - this.connections - .retain(|connection: &ClientConnection| !connection.closed); + this.sessions + .retain(|session: &ClientSession| session.is_active()); } }) } @@ -146,18 +140,18 @@ impl ServerInstance { if client_password.is_none() || correct_password != client_password.unwrap() { stream.write_all(b"HTTP/1.1 401 Unauthorized - Incorrect password\r\n\n")?; continue; - } else if self.connections.len() + 1 > self.config.cons_limit as usize { + } else if self.sessions.len() + 1 > self.config.sessions_limit as usize { stream.write_all(b"HTTP/1.1 503 Sessions Limit\r\n\n")?; } - let new_session = - ClientConnection::create(Local::now(), self.config.con_lifetime).await; + let mut new_session = ClientSession::new(Local::now()); + new_session.activate_temporairly(self.config.session_lifetime); let session_id = new_session.id; - self.connections.push(new_session); + self.sessions.push(new_session); let response_content = format!("{}", session_id); self.info_channel .clone() - .send("A new connection's been created".to_string()) + .send("A new session been created".to_string()) .unwrap(); stream diff --git a/src/server/mod.rs b/src/server/mod.rs index b6c4c2b..bd33a96 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,4 +1,4 @@ -pub mod client_connection; +pub mod client_session; pub mod header_parsing; pub mod instance; pub mod runtime_config; diff --git a/src/server/runtime_config.rs b/src/server/runtime_config.rs index 85f9a41..2565b4e 100644 --- a/src/server/runtime_config.rs +++ b/src/server/runtime_config.rs @@ -13,8 +13,8 @@ pub struct RuntimeConfig { pub address: String, pub manage_file: String, pub password: String, - pub cons_limit: u32, - pub con_lifetime: Duration, + pub sessions_limit: u32, + pub session_lifetime: Duration, } impl Default for RuntimeConfig { @@ -23,8 +23,8 @@ impl Default for RuntimeConfig { address: "localhost:3306".to_string(), manage_file: "./main.manage.blz".to_string(), password: "password".to_string(), - cons_limit: 100, - con_lifetime: Duration::from_secs(30), + sessions_limit: 100, + session_lifetime: Duration::from_secs(30), } } } @@ -59,8 +59,8 @@ impl RuntimeConfig { let mut address = default.address; let mut password = default.password; let mut manage_file: String = "main.manage.blz".to_string(); - let mut cons_limit: u32 = default.cons_limit; - let mut con_lifetime: Duration = default.con_lifetime; + let mut sessions_limit: u32 = default.sessions_limit; + let mut session_lifetime: Duration = default.session_lifetime; let manage_file_fullname_regex = Regex::new(r".*\.manage\.blz$").unwrap(); @@ -102,12 +102,12 @@ impl RuntimeConfig { match argument_keyword.as_str() { "-address" => address.clone_from(&argument_value), "-password" => password.clone_from(&argument_value), - "-session_lifetime" => con_lifetime.clone_from(&Duration::from_secs( + "-session_lifetime" => session_lifetime.clone_from(&Duration::from_secs( argument_value .parse() .expect("Provide the right amount of seconds a session lives"), )), - "-sessions_limit" => cons_limit.clone_from( + "-sessions_limit" => sessions_limit.clone_from( &argument_value .parse() .expect("Unable to parse 'sessions_limit' field due to the incorrect type"), @@ -119,8 +119,8 @@ impl RuntimeConfig { address, manage_file, password, - cons_limit, - con_lifetime, + sessions_limit, + session_lifetime, }) } } diff --git a/src/shell/command_handler.rs b/src/shell/command_handler.rs index eb5fa14..6b8790c 100644 --- a/src/shell/command_handler.rs +++ b/src/shell/command_handler.rs @@ -99,8 +99,8 @@ Blaze Language (Dev) pub fn create_management_file(name: &str) -> bool { let manage_file_content = br#"manage ( // address = "localhost:3306", - // cons_limit = 100, - // con_lifetime = 60 + // sessions_limit = 100, + // session_lifetime = 60 ); attach "data";"#;