diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5812140 Binary files /dev/null and b/.DS_Store differ diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..7095040 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,104 @@ +use std::{fs::File, io, path::PathBuf, str::FromStr, sync::Arc}; + +use zip::ZipArchive; + +use crate::{logger, plugin::loader::PluginLoader, server::Server}; + +logger!(LOGGER "CLI"); + +pub fn parse_args(input: &str) -> Vec { + let mut args = Vec::new(); + let mut current = String::new(); + + let mut in_dq = false; + let mut in_q = false; + let mut escape = false; + + for c in input.chars() { + if escape { + current.push(c); + escape = false; + continue; + } + + match c { + '\\' => { + escape = true; + } + '"' if !in_q && !escape => { + in_dq = !in_dq; + } + '\'' if !in_dq && !escape => { + in_q = !in_q; + } + ' ' if !in_dq && !in_q => { + if !current.is_empty() { + args.push(current.clone()); + current.clear(); + } + } + _ => { + current.push(c); + } + } + } + + if escape { + current.push('\\'); + } + + if !current.is_empty() { + args.push(current); + } + + args +} + +pub fn require_args(args: &[String], required: &[&str]) -> bool { + if required.len() + 1 > args.len() { + LOGGER.error(format!("Required arguments: {}", required.join(" "))); + return false; + } + + true +} + +pub fn start_cli(server: Arc, plugin_loader: PluginLoader) { + std::thread::spawn(move || { + loop { + let mut buf = String::new(); + io::stdin().read_line(&mut buf).unwrap(); + let args = parse_args(buf.trim()); + if args.len() == 0 { + continue; + } + + match args[0].as_str() { + "install" => { + if require_args(&args, &[""]) { + let path = PathBuf::from_str(&args[1]).unwrap(); + if path.extension().and_then(|s| s.to_str()) == Some("vxp") { + LOGGER.info(format!("Installing {:?}", path)); + let d = path.with_extension(""); + if !d.exists() { + let file = File::open(&path).unwrap(); + let mut archive = ZipArchive::new(file).unwrap(); + archive.extract(&d).unwrap(); + } + } else { + LOGGER.error("File must be .vxp"); + } + } + } + "load" => { + if require_args(&args, &[""]) { + plugin_loader.load(&server.root.join("plugins").join(&args[1])); + } + } + _ => { + LOGGER.error(format!("Command not found ({})", args[0])); + } + } + } + }); +} diff --git a/src/main.rs b/src/main.rs index 9134b2f..c5d1570 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod cli; mod macros; mod plugin; mod requests; diff --git a/src/server.rs b/src/server.rs index 78827e9..3f285b4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,16 +1,14 @@ use std::{ collections::HashSet, - fs::{self, File}, + fs::{self}, net::{TcpListener, TcpStream}, path::{Path, PathBuf}, sync::{Arc, Mutex}, }; -use zip::ZipArchive; - use crate::{ - logger, - plugin::{self, Plugin, loader::PluginLoader, types::LoaderMessage}, + cli, logger, + plugin::{Plugin, loader::PluginLoader, types::LoaderMessage}, types, utils::{self, client::Client}, }; @@ -80,22 +78,8 @@ impl Server { let entry = entry?; let path = entry.path(); - let p = if path.extension().and_then(|s| s.to_str()) == Some("vxp") { - plugin::loader::LOGGER.info(format!("Installing {:?}", path)); - let d = path.with_extension(""); - if !d.exists() { - let file = File::open(&path)?; - let mut archive = ZipArchive::new(file)?; - archive.extract(&d)?; - } - - d - } else { - path - }; - - if p.is_dir() { - let mut p = plugin_loader.load(&p); + if path.is_dir() { + let mut p = plugin_loader.load(&path); let s = self.clone(); self.plugins.lock().unwrap().push(p.clone()); std::thread::spawn(move || p.run(&s)); @@ -106,6 +90,10 @@ impl Server { // Initialize plugins Self::LOGGER.info("Initializing plugins"); + // Initialize CLI + Self::LOGGER.info("Initializing CLI"); + cli::start_cli(self.clone(), plugin_loader); + // Start server let listener = TcpListener::bind(format!("0.0.0.0:{}", self.config.port))?; Self::LOGGER.info(format!("Server listening at 0.0.0.0:{}", self.config.port)); @@ -223,7 +211,7 @@ impl Server { res } - pub fn send_plugin_message(&self, msg: &LoaderMessage) -> crate::Result<()> { + pub fn send_plugin_message(self: &Arc, msg: &LoaderMessage) -> crate::Result<()> { for p in self.plugins.lock().unwrap().iter_mut() { p.send(msg)?; }