From 6460ccee378e15408768337dcdc1bc77da07da53 Mon Sep 17 00:00:00 2001 From: pfg Date: Sun, 12 Mar 2017 09:29:17 -0700 Subject: Custom Command Syntax --- ShiftOS_TheReturn/CommandParser.cs | 366 ++++++++++++++++++++++++++++++++ ShiftOS_TheReturn/Commands.cs | 1 + ShiftOS_TheReturn/ShiftOS.Engine.csproj | 1 + ShiftOS_TheReturn/TerminalBackend.cs | 213 +++++++++---------- 4 files changed, 465 insertions(+), 116 deletions(-) create mode 100644 ShiftOS_TheReturn/CommandParser.cs (limited to 'ShiftOS_TheReturn') diff --git a/ShiftOS_TheReturn/CommandParser.cs b/ShiftOS_TheReturn/CommandParser.cs new file mode 100644 index 0000000..182ff53 --- /dev/null +++ b/ShiftOS_TheReturn/CommandParser.cs @@ -0,0 +1,366 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ShiftOS.Engine { + public static class CurrentCommandParser { + public static CommandParser parser; + } + + public class CommandParser { + public IList parts = new List(); + + public void AddPart(CommandFormat part) { + parts.Add(part); + } + + public void ImportPart(IList parts) { + this.parts = parts; + } + + public string Save() { + JArray data = new JArray(); + foreach(CommandFormat part in parts) { + CFValue val = new CFValue(part); + JObject obj = new JObject(); + obj["type"] = new JValue(val.type); + obj["text"] = new JValue(val.text); + data.Add(obj); + } + + return data.ToString(); + } + + public static CommandParser Load(string val) { + CommandParser parser = new CommandParser(); + JArray data = JArray.Parse(val); + + IList values = data.Select(obj => new CFValue ( + (string)obj["type"], + (string)obj["text"] + )).ToList(); + + foreach(CFValue value in values) { + parser.AddPart(value.GetCommandFormat()); + } + + return parser; + } + + public KeyValuePair, Dictionary> ParseCommand(string cdd) { + string command = ""; + string ns = ""; + Dictionary arguments = new Dictionary(); + + string text = cdd; + int position = 0; + + int commandPos; + int firstValuePos = -1; + int lastValuePos = -1; + + string syntaxError = ""; + + for (int ii = 0; ii < parts.Count; ii++) { + CommandFormat part = parts[ii]; + if (part is CommandFormatMarker) { + if (part is CommandFormatCommand) { + commandPos = ii; + } else if (part is CommandFormatValue) { + if (firstValuePos > -1) + lastValuePos = ii; + else + firstValuePos = ii; + } + } + } + + int i = 0; + string currentArgument = ""; + int help = -1; + + while (position < text.Length) { + + if (i >= parts.Count) { + position = text.Length; + command = "+FALSE+"; + i = 0; + } + + CommandFormat part = parts[i]; + string res = part.CheckValidity(text.Substring(position)); + + // ok so: + + // example + // COMMAND text[ --] ARGUMENT VALUE text[ --] ARGUMENT VALUE + // COMMAND text[{] ARGUMENT text[=] VALUE text[, ] ARGUMENT text[=] VALUE text[}] + + if (part is CommandFormatMarker) { + if (part is CommandFormatNamespace) { + ns = res; + help = -1; + }else if (part is CommandFormatCommand) { + command = res; + help = -1; + } else if (part is CommandFormatArgument) { + currentArgument = res; + help = -1; + } else if (part is CommandFormatValue) { + arguments[currentArgument] = string.Join("", res.Split('"')); + + if (i == firstValuePos) + help = lastValuePos; + if (i == lastValuePos) + help = firstValuePos; + } + } + + if (res == "+FALSE+") { + if (help > -1) { + i = help; + if (i >= parts.Count) { + position = text.Length; + command = "+FALSE+"; + } + } else { + position = text.Length; + syntaxError = "Syntax Error"; + command = "+FALSE+"; + } + help = -1; + } else { + position += res.Length; + } + + i++; + } + + if (command == "+FALSE+") { + //lblExampleCommand.Text = "Syntax Error"; + return new KeyValuePair, Dictionary>(); + } else { + /*string argvs = "{"; + + foreach (KeyValuePair entry in arguments) { + argvs += entry.Key + "=" + entry.Value + ", "; + } + + argvs += "}"; + + lblExampleCommand.Text = command + argvs;*/ + return new KeyValuePair, Dictionary> (new KeyValuePair(ns, command), arguments); + } + } + } + + public class CFValue { + public string type { get; set; } + public string text { get; set; } + + public CFValue(string type, string text) { + this.type = type; + this.text = text; + } + + public CFValue(CommandFormat format) { + type = ""; + text = ""; + if(format is CommandFormatText) { + text = ((CommandFormatText) format).str; + if(format is CommandFormatOptionalText) { + type = "optionalText"; + }else if (format is CommandFormatRegex) { + type = "regexText"; + }else { + type = "text"; + } + }else if (format is CommandFormatMarker) { + if (format is CommandFormatNamespace) { + type = "namespace"; + } else if (format is CommandFormatCommand) { + type = "command"; + } else if (format is CommandFormatArgument) { + type = "argument"; + } else if (format is CommandFormatValue) { + type = "value"; + } + } + } + + public CommandFormat GetCommandFormat() { // TODO update with better code + switch (type) { + case "text": + return new CommandFormatText(text); + case "optionalText": + return new CommandFormatOptionalText(text); + case "regexText": + return new CommandFormatRegex(text); + case "namespace": + return new CommandFormatNamespace(); + case "command": + return new CommandFormatCommand(); + case "argument": + return new CommandFormatArgument(); + case "value": + return new CommandFormatValue(); + case "color": + throw new NotImplementedException(); // fix this (make it not a notimplementedexception) + } + return new CommandFormatMarker(); + } + } + + + public interface CommandFormat { + string CheckValidity(string check); + Control Draw(); + } + public class CommandFormatText : CommandFormat { + public string str = ""; + TextBox textBox; + + public CommandFormatText() { + + } + + public CommandFormatText(string str) { + this.str = str; + } + + public virtual string CheckValidity(string check) { + return check.StartsWith(str) ? str : "+FALSE+"; + } + + public Control Draw() { + textBox = new TextBox(); + textBox.TextChanged += new EventHandler(TextChanged); + textBox.Location = new Point(0, 0); + textBox.Text = str; + + return textBox; + } + + void TextChanged(object sender, EventArgs e) { + str = textBox.Text; + } + } + + public class CommandFormatOptionalText : CommandFormatText { + public CommandFormatOptionalText() : base() { + } + public CommandFormatOptionalText(string str) : base(str) { + } + + public override string CheckValidity(string check) { + return check.StartsWith(str) ? str : ""; + } + } + + public class CommandFormatRegex : CommandFormatText { + public CommandFormatRegex() : base() { + } + public CommandFormatRegex(string str) : base(str) { + } + + public override string CheckValidity(string check) { + Match match = (new Regex("^" + str)).Match(check); + return match.Success ? match.Value : "+FALSE+"; + } + } + + public class CommandFormatMarker : CommandFormat { + protected string str; + Button button; + + public CommandFormatMarker() { + } + + public virtual string CheckValidity(string check) { + string res = string.Empty; + string alphanumeric = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; // not using regex for performance reasons + + foreach (char c in check) { + if (alphanumeric.IndexOf(c) > -1) { + res += c; + } else { + break; + } + } + + return res; + } + + public virtual Control Draw() { + button = new Button(); + button.Location = new Point(0, 0); + button.Text = "Marker"; + + return button; + } + } + + public class CommandFormatCommand : CommandFormatMarker { + public override Control Draw() { + Button draw = (Button)base.Draw(); + draw.Text = "Command"; + return draw; + } + } + + public class CommandFormatNamespace : CommandFormatMarker { + public override Control Draw() { + Button draw = (Button)base.Draw(); + draw.Text = "Namespace"; + return draw; + } + } + + public class CommandFormatArgument : CommandFormatMarker { + public override Control Draw() { + Button draw = (Button)base.Draw(); + draw.Text = "Argument"; + return draw; + } + } + + public class CommandFormatValue : CommandFormatMarker { + public override string CheckValidity(string cd) { + string res = string.Empty; + var check = ""; + bool done = false; + + if (cd.StartsWith("\"")) { + check = cd.Substring(1); + + foreach (char c in check) { + if (c != '"') { + res += c; + } else { + done = true; + res = "\"" + res + "\""; + break; + } + } + } else{ + res = base.CheckValidity(cd); + done = true; + } + return done ? res : "+FALSE+"; + } + + public override Control Draw() { + Button draw = (Button)base.Draw(); + draw.Text = "\"Value\""; + return draw; + } + } +} diff --git a/ShiftOS_TheReturn/Commands.cs b/ShiftOS_TheReturn/Commands.cs index 0ea00e5..779c616 100644 --- a/ShiftOS_TheReturn/Commands.cs +++ b/ShiftOS_TheReturn/Commands.cs @@ -305,6 +305,7 @@ namespace ShiftOS.Engine [RequiresArgument("type")] public static bool MultArg(Dictionary args) { + Console.WriteLine("Success! "+args.ToString()); return true; } diff --git a/ShiftOS_TheReturn/ShiftOS.Engine.csproj b/ShiftOS_TheReturn/ShiftOS.Engine.csproj index 20ca879..5521f49 100644 --- a/ShiftOS_TheReturn/ShiftOS.Engine.csproj +++ b/ShiftOS_TheReturn/ShiftOS.Engine.csproj @@ -97,6 +97,7 @@ + diff --git a/ShiftOS_TheReturn/TerminalBackend.cs b/ShiftOS_TheReturn/TerminalBackend.cs index 8be54d0..fd2524f 100644 --- a/ShiftOS_TheReturn/TerminalBackend.cs +++ b/ShiftOS_TheReturn/TerminalBackend.cs @@ -32,26 +32,21 @@ using System.Threading.Tasks; using Newtonsoft.Json; using static ShiftOS.Engine.SaveSystem; -namespace ShiftOS.Engine -{ - public static class TerminalBackend - { +namespace ShiftOS.Engine { + public static class TerminalBackend { public static event Action CommandProcessed; public static bool Elevated { get; set; } - public static Dictionary GetArgs(ref string text) - { + public static Dictionary GetArgs(ref string text) { bool shouldParse = false; int argStart = 0; - if (text.Contains("{")) - { + if (text.Contains("{")) { shouldParse = true; argStart = text.IndexOf('{'); } - if (shouldParse == false) - { + if (shouldParse == false) { string replacement = Regex.Replace(text, @"\t|\n|\r", ""); text = replacement + "{}"; shouldParse = true; @@ -61,15 +56,47 @@ namespace ShiftOS.Engine string args = text.Substring(argStart, text.Length - argStart); text = text.Remove(argStart, text.Length - argStart).Replace(" ", ""); - return JsonConvert.DeserializeObject>(args); + return JsonConvert.DeserializeObject>(args); } public static string LastCommand = ""; - public static void InvokeCommand(string text, bool isRemote = false) - { - try - { + public static void InvokeCommand(string ns, string command, Dictionary arguments, bool isRemote = false) { + try { + if (string.IsNullOrWhiteSpace(ns)) + return; + + + bool commandWasClient = RunClient(ns, command, arguments, isRemote); + + if (!commandWasClient && !string.IsNullOrWhiteSpace(ns)) { + PrefixEnabled = false; + + ServerManager.SendMessage("script", $@"{{ + user: ""{ns}"", + script: ""{command}"", + args: ""{GetSentArgs(arguments)}"" +}}"); + } + + CommandProcessed?.Invoke(ns + "." + command, JsonConvert.SerializeObject(arguments)); + } catch (Exception ex) { + Console.WriteLine($"Command parse error: {ex.Message}"); // This shouldn't ever be called now + PrefixEnabled = true; + + } + } + + public static string GetSentArgs(Dictionary argss) { + Dictionary args = new Dictionary(); + foreach (KeyValuePair arg in argss) { + args[arg.Key] = arg.Value; + } + return JsonConvert.SerializeObject(args); + } + + public static void InvokeCommand(string text, bool isRemote = false) { + try { if (string.IsNullOrWhiteSpace(text)) return; @@ -77,19 +104,17 @@ namespace ShiftOS.Engine bool commandWasClient = RunClient(text, args, isRemote); - if (!commandWasClient && !string.IsNullOrWhiteSpace(text)) - { + if (!commandWasClient) { PrefixEnabled = false; + ServerManager.SendMessage("script", $@"{{ user: ""{text.Split('.')[0]}"", script: ""{text.Split('.')[1]}"", - args: ""{JsonConvert.SerializeObject(args)}"" + args: ""{GetSentArgs(args)}"" }}"); } - CommandProcessed?.Invoke(text, JsonConvert.SerializeObject(args)); - } - catch (Exception ex) - { + CommandProcessed?.Invoke(text, GetSentArgs(args)); + } catch (Exception ex) { Console.WriteLine($"Command parse error: {ex.Message}"); PrefixEnabled = true; @@ -104,18 +129,15 @@ namespace ShiftOS.Engine public static event EmptyEventHandler TerminalRequested; - internal static void OpenTerminal() - { + internal static void OpenTerminal() { TerminalRequested?.Invoke(); } - public static bool CanRunRemotely(MethodInfo mth, bool isRemote) - { + public static bool CanRunRemotely(MethodInfo mth, bool isRemote) { if (!isRemote) return true; - foreach(var attr in mth.GetCustomAttributes(false)) - { + foreach (var attr in mth.GetCustomAttributes(false)) { if (attr is RemoteLockAttribute) return false; } @@ -123,60 +145,45 @@ namespace ShiftOS.Engine return true; } - public static bool RunClient(string text, Dictionary args, bool isRemote = false) - { + public static bool RunClient(string ns, string cmd, Dictionary args, bool isRemote = false) { + return RunClient(ns + "." + cmd, args, isRemote); + } + + public static bool RunClient(string text, Dictionary args, bool isRemote = false) { latestCommmand = text; - foreach (var asmExec in System.IO.Directory.GetFiles(Environment.CurrentDirectory)) - { - try - { + foreach (var asmExec in System.IO.Directory.GetFiles(Environment.CurrentDirectory)) { + try { var asm = Assembly.LoadFile(asmExec); var types = asm.GetTypes(); - foreach (var type in types) - { - if (Shiftorium.UpgradeAttributesUnlocked(type)) - { - if (KernelWatchdog.IsSafe(type)) - { - foreach (var a in type.GetCustomAttributes(false)) - { - if (a is Namespace) - { + foreach (var type in types) { + if (Shiftorium.UpgradeAttributesUnlocked(type)) { + if (KernelWatchdog.IsSafe(type)) { + foreach (var a in type.GetCustomAttributes(false)) { + if (a is Namespace) { var ns = a as Namespace; - if (text.Split('.')[0] == ns.name) - { - foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) - { - if (Shiftorium.UpgradeAttributesUnlocked(method)) - { - if (KernelWatchdog.IsSafe(method)) - { - if (CanRunRemotely(method, isRemote)) - { - foreach (var ma in method.GetCustomAttributes(false)) - { - if (ma is Command) - { + if (text.Split('.')[0] == ns.name) { + foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) { + if (Shiftorium.UpgradeAttributesUnlocked(method)) { + if (KernelWatchdog.IsSafe(method)) { + if (CanRunRemotely(method, isRemote)) { + foreach (var ma in method.GetCustomAttributes(false)) { + if (ma is Command) { var cmd = ma as Command; - if (text.Split('.')[1] == cmd.name) - { + if (text.Split('.')[1] == cmd.name) { var attr = method.GetCustomAttribute(); - if (attr != null) - { + if (attr != null) { string newcommand = attr.newcommand; - if (attr.warn) - { + if (attr.warn) { Console.WriteLine(Localization.Parse((newcommand == "" ? "{ERROR}" : "{WARN}") + attr.reason, new Dictionary() { {"%newcommand", newcommand} })); } - if (newcommand != "") - { + if (newcommand != "") { // redo the entire process running newcommand return RunClient(newcommand, args); @@ -188,13 +195,10 @@ namespace ShiftOS.Engine bool error = false; bool providedusage = false; - foreach (RequiresArgument argument in requiresArgs) - { - if (!args.ContainsKey(argument.argument)) - { + foreach (RequiresArgument argument in requiresArgs) { + if (!args.ContainsKey(argument.argument)) { - if (!providedusage) - { + if (!providedusage) { string usageparse = "{COMMAND_" + ns.name.ToUpper() + "_" + cmd.name.ToUpper() + "_USAGE}"; if (usageparse == Localization.Parse(usageparse)) usageparse = ""; @@ -209,14 +213,11 @@ namespace ShiftOS.Engine providedusage = true; } - if (Shiftorium.UpgradeInstalled("help_usage")) - { + if (Shiftorium.UpgradeInstalled("help_usage")) { Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED}", new Dictionary() { {"%argument", argument.argument} })); - } - else - { + } else { Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED_NO_USAGE}")); } @@ -224,89 +225,69 @@ namespace ShiftOS.Engine } } - if (error) - { + if (error) { throw new Exception("{ERROR_COMMAND_WRONG}"); } - try - { + try { return (bool)method.Invoke(null, new[] { args }); - } - catch (TargetInvocationException e) - { + } catch (TargetInvocationException e) { Console.WriteLine(Localization.Parse("{ERROR_EXCEPTION_THROWN_IN_METHOD}")); Console.WriteLine(e.InnerException.Message); Console.WriteLine(e.InnerException.StackTrace); return true; - } - catch - { + } catch { return (bool)method.Invoke(null, new object[] { }); } } } } - } - else - { + } else { Console.WriteLine(text + " cannot be ran in a remote session"); return true; } } - + } } } } } } - + } } - } - catch { } + } catch { } } return false; } - - static TerminalBackend() - { - ServerMessageReceived onMessageReceived = (msg) => - { - if (msg.Name == "trm_invokecommand") - { + + static TerminalBackend() { + ServerMessageReceived onMessageReceived = (msg) => { + if (msg.Name == "trm_invokecommand") { string text3 = ""; string text4 = msg.Contents; - if (TerminalBackend.PrefixEnabled) - { + if (TerminalBackend.PrefixEnabled) { text3 = text4.Remove(0, $"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ".Length); } IsForwardingConsoleWrites = true; - if (TerminalBackend.InStory == false) - { + if (TerminalBackend.InStory == false) { TerminalBackend.InvokeCommand(text3, true); } - if (TerminalBackend.PrefixEnabled) - { + if (TerminalBackend.PrefixEnabled) { Console.Write($"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ "); } IsForwardingConsoleWrites = false; - } - else if (msg.Name == "pleasewrite") - { + } else if (msg.Name == "pleasewrite") { Console.Write(msg.Contents); - } - else if(msg.Name == "handshake_from") - { + } else if (msg.Name == "handshake_from") { var a = JsonConvert.DeserializeObject>(msg.Contents); string uName = a["username"] as string; string pass = a["password"] as string; string sys = a["sysname"] as string; string guid = msg.GUID; - if(SaveSystem.CurrentSave.Username == uName && SaveSystem.CurrentSave.Password == pass && CurrentSave.SystemName == sys) - { + if (SaveSystem.CurrentSave.Username == uName && SaveSystem.CurrentSave.Password == pass && CurrentSave.SystemName == sys) { ForwardGUID = guid; ServerManager.SendMessage("trm_handshake_accept", $@"{{ guid: ""{ServerManager.thisGuid}"", @@ -326,6 +307,6 @@ namespace ShiftOS.Engine public static bool IsForwardingConsoleWrites { get; internal set; } public static string ForwardGUID { get; internal set; } - + } } -- cgit v1.2.3