private void ExecutionThread_DoWork(object obj) { try { CancellationToken token = (CancellationToken)obj; while (!token.IsCancellationRequested) { if (Command == null) { Debug.WriteLine("EecutionThread " + Thread.CurrentThread.GetHashCode() + ": Execution Signal, wait for next..."); ExecutionSignal.WaitOne(); Debug.WriteLine("EecutionThread " + Thread.CurrentThread.GetHashCode() + ": Execution Signal received."); } else { Debug.WriteLine("EecutionThread " + Thread.CurrentThread.GetHashCode() + ": Processing command..."); Command?.ExecuteCallback(); Command = null; ExecutionWatchDog.Set(); //Notify Watch dog execution completed. Debug.WriteLine("EecutionThread " + Thread.CurrentThread.GetHashCode() + ": Completed."); } } if (token.IsCancellationRequested) { Trace.WriteLine("EecutionThread " + Thread.CurrentThread.GetHashCode() + ": Thread Cancel and Terminated!"); } } catch (Exception ex) { Trace.WriteLine("[ERROR] ExecutionThread Crahsed: " + ex.Message); } }
private void VerifyUserSignedIn(TcpAppInputCommand command) { if (command.AppClient.SignedIn) { return; } throw new InvalidOperationException("Client not signed in!"); }
private void WriteResultToClient(TcpServerConnection client, TcpAppInputCommand input) { string returnMsg = "#TCP# " + input.Command.Keyword + " " + input.Status.ToString(); if (!string.IsNullOrEmpty(input.OutputMessage)) { returnMsg += " " + input.OutputMessage; } client.WriteLineToClient(returnMsg); }
private void WriteResultToClient(TcpAppServerConnection client, TcpAppInputCommand input) { string returnMsg = input.Status.ToString() + " "; if (!string.IsNullOrEmpty(input.OutputMessage)) { returnMsg += input.OutputMessage; } Debug.WriteLine("AppServer[" + client.Name + "]-TX: " + returnMsg); client.Connection.WriteLineToClient(returnMsg); }
private void WriteResultToClient(TcpServerConnection client, TcpAppInputCommand input) { string returnMsg = input.Command.Keyword + " " + input.Status.ToString(); if (!string.IsNullOrEmpty(input.OutputMessage)) { returnMsg += " " + input.OutputMessage; } System.Diagnostics.Trace.WriteLine("Write To Client: " + returnMsg); client.WriteLineToClient(returnMsg); }
public static TcpAppInputCommand CreateInputCommand(List <TcpAppCommand> commandList, string[] commandArguments) { TcpAppInputCommand result = null; //Process Command Keyword TcpAppCommand cmdHandler = commandList.FirstOrDefault(x => x.Keyword.Equals(commandArguments[0], StringComparison.InvariantCultureIgnoreCase)); if (cmdHandler == null) { return(null); } result = new TcpAppInputCommand() { Command = cmdHandler.Clone() as TcpAppCommand }; result.Arguments = commandArguments.Skip(1).ToArray(); //Arguments exclude command keyword //Process Parameters cmdHandler.ResetParametersValue(); int argID = 0; //First Parameter foreach (TcpAppParameter item in cmdHandler.Parameters) { if (argID >= result.Arguments.Length) { //Argument with no input if (!item.IsOptional) { //Error - Missing required parameter throw new ArgumentException("Missing required parameter: " + item.Name + "!"); } } else if (item.IsArray) { item.Values.Clear(); //Parameter Array is last parameters consume all arguments in command for (int m = argID; m < result.Arguments.Length; m++) { item.Values.Add(result.Arguments[m]); } break; } else { item.Value = result.Arguments[argID]; //Assign parameter value } argID++; } return(result); }
internal void Client_MessageReceived(object sender, MessageReceivedEventArgs e) { //Process incoming message from Client if (!e.ReceivedMessage.StartsWith("#TCP#")) { return; //Drop message which is not using defined format. } //Parse and Execute Commands string[] cmdArg = e.ReceivedMessage.Trim().Split(' '); TcpAppCommand cmdHandler = GetCommand(cmdArg[1]); if (cmdHandler == null) { //Error - Unrecognized command. e.Client.WriteLineToClient(string.Format("#TCP# {0} {1} Invalid Command!", cmdArg[1], TcpAppCommandStatus.ERR.ToString())); return; } TcpAppInputCommand cmdInput = new TcpAppInputCommand() { Command = cmdHandler }; cmdHandler.ResetArgumentsValue(); int argID = 2; //First Argument foreach (TcpAppArgument item in cmdHandler.Arguments) { if (argID >= cmdArg.Length) { //Argument with no input if (!item.IsOptional) { //Error - Missing required argument cmdInput.OutputMessage = "Missing required argument: " + item.Name + "!"; WriteResultToClient(e.Client, cmdInput); return; } } else { item.Value = cmdArg[argID]; //Assign argument value } argID++; } cmdInput.Command.ExecuteCallback(cmdInput); //Send result back to client. WriteResultToClient(e.Client, cmdInput); }
/// <summary> /// Execute Plugin Callback. Call by ITcpAppServerPlugin /// </summary> /// <param name="commandArguments">Command keyword and arguments in string array.</param> public TcpAppInputCommand GetPluginCommand(string [] commandArguments) { if (commandArguments == null) { throw new ArgumentNullException(nameof(commandArguments), "Invalid command / empty string!"); } TcpAppInputCommand command = TcpAppCommon.CreateInputCommand(Commands, commandArguments); if (command == null) { throw new ArgumentException("Unknown command: " + commandArguments.FirstOrDefault()); } return(command); }
/// <summary> /// /// </summary> /// <param name="disposing"></param> protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { Command = null; StopExecutionThread(); ExecutionSignal.Dispose(); ExecutionWatchDog.Dispose(); } // free unmanaged resources (unmanaged objects) and override finalizer // set large fields to null disposedValue = true; } }
/// <summary> /// Execute Plugin Callback. Call by ITcpAppServerPlugin /// </summary> /// <param name="sender"></param> public void ExecutePluginCommand(TcpAppInputCommand sender) { sender.Status = TcpAppCommandStatus.ERR; string[] cmdArg = sender.Arguments.Skip(1).ToArray(); //Process Command Keyword TcpAppCommand cmdHandler = GetCommand(cmdArg[0]); if (cmdHandler == null) { //Error - Unrecognized command. sender.OutputMessage = string.Format("Invalid Command: {0}!", cmdArg[0]); return; } sender.Command = cmdHandler; //Process Parameters cmdHandler.ResetParametersValue(); int argID = 1; //First Parameter foreach (TcpAppParameter item in cmdHandler.Parameters) { if (argID >= cmdArg.Length) { //Argument with no input if (!item.IsOptional) { //Error - Missing required parameter sender.OutputMessage = "Missing required parameter: " + item.Name + "!"; return; } } else { item.Value = cmdArg[argID]; //Assign parameter value } argID++; } //Execute Command. //Note: Error handling not required. Will handle by TcpAppServer class. sender.Command.ExecuteCallback(sender); }
private void ShowHelp(TcpAppInputCommand sender) { string aliasName = sender.Command.Parameter("Alias").Value; List <string> lines = null; if (aliasName == "-") { //Print Help Screen - Write to sender.OutputMessage lines = new List <string> { "TCP Aplication Server Version " + Version.ToString(), " ", "==== USAGE ====", " SEND: <Command> [Param0] ... [ParamN]", " RECV: <Command> <Status> [Return Message]", " ", " Notes:", " <> = Required parameters", " [] = Optional parameters", " ", }; lines.AddRange(TcpAppCommon.PrintCommandHelpContents(Commands)); sender.OutputMessage = string.Join("\r\n", lines.ToArray()); sender.Status = TcpAppCommandStatus.OK; } else { //Get Help Content for selected object. ITcpAppServerPlugin plugin = Plugins.FirstOrDefault(x => string.Compare(x.Alias, sender.Command.Parameter("Alias").Value, true) == 0); if (plugin == null) { sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = "Object [" + aliasName + "] not exist!"; } else { plugin.ShowHelp(sender); } } }
/// <summary> /// Execute command with timeout handling /// </summary> /// <param name="command"></param> /// <param name="timeout_ms"></param> internal void ExecuteCommandAsync(TcpAppInputCommand command, int timeout_ms) { Command = command; Debug.WriteLine("ExecuteCommandAsync: Start"); ExecutionWatchDog.Reset(); ExecutionSignal.Set(); bool done = ExecutionWatchDog.WaitOne(timeout_ms); if (!done) { Debug.WriteLine("[ERROR]AppServer-ExecuteCommandAsync: Timeout! Recreate execution thread!"); StopExecutionThread(); Command.OutputMessage = "Server Timeout"; Command.Status = TcpAppCommandStatus.ERR; Command = null; CreateAndStartExecutionThread(); } else { Debug.WriteLine("ExecuteCommandAsync: Completed"); } }
private void ShowHelp(TcpAppInputCommand sender) { //Print Help Screen - Write to sender.OutputMessage List <string> lines = new List <string>(); lines.Add("TCP Aplication Server Version " + Version.ToString()); lines.Add(" "); lines.Add("== USAGE =="); lines.Add(" SEND: #TCP# <Command> [Param0] ... [ParamN]"); lines.Add(" RECV: #TCP# <Command> <Status> [Return Message]"); lines.Add(" "); lines.Add("== COMMAND =="); foreach (TcpAppCommand cmd in Commands) { lines.Add(String.Format(" {0,-20} {1}", cmd.Keyword, cmd.Description)); foreach (TcpAppArgument arg in cmd.Arguments) { lines.Add(String.Format(" {0,-10} {1,-10} {2}", " ", "<" + arg.Name + ">", arg.Description)); } } sender.OutputMessage = string.Join("\r\n", lines.ToArray()); sender.Status = TcpAppCommandStatus.OK; }
/// <summary> /// Print help screen for selected plugin components. /// </summary> /// <param name="sender"></param> public void ShowHelp(TcpAppInputCommand sender) { sender.OutputMessage = string.Join("\r\n", TcpAppCommon.PrintCommandHelpContents(Commands)); sender.Status = TcpAppCommandStatus.OK; }
private void ShowHelp(TcpAppInputCommand sender) { string aliasName = sender.Command.Parameter("Plugin").Value; List <string> lines = null; if (aliasName == "-") { lines = new List <string> { "[ TCP Aplication Server V" + Version.ToString() + " ]", " ", "==== USAGE ====", " Execute Tcp App Server Command:", " SEND: <Command> [Param0] ... [ParamN]", " RECV: <Status> [Return Message]", " ", " Execute plugin Command:", " SEND: <Alias> <Command> [Param0] ... [ParamN]", " RECV: <Status> [Return Message]", " ", " Notes:", " Command are not case sensitive.", " <> = Required parameters", " [] = Optional parameters", " ", }; //Insert Application Header if defined. string header = OnShowHelpGetApplicationHeader(); if (!string.IsNullOrEmpty(header)) { lines.Insert(0, header); } lines.AddRange(TcpAppCommon.PrintCommandHelpContents(Commands)); //Print registered plugins if (PluginTypes.Count > 0) { lines.Add("[ PLUGINS ]"); lines.AddRange(PluginTypes.Select(x => string.Format(" {0, -20} {1}", x.Name, x.Description)).ToArray()); lines.Add(" "); } if (_Plugins.Count > 0) { lines.Add("[ OBJECTS ]"); lines.AddRange(_Plugins.Select(x => string.Format(" {0, -20} {1}", x.Alias, "(" + PluginTypes.FirstOrDefault(n => n.Type == x.GetType())?.Name + ")")).ToArray()); } sender.OutputMessage = string.Join(TcpAppCommon.NewLine, lines.ToArray()); sender.Status = TcpAppCommandStatus.OK; } else { //Get Help Content for selected object. string pluginName = sender.Command.Parameter("Plugin").Value; ITcpAppServerPlugin plugin = null; TcpAppServerPluginType ptrType = PluginTypes.FirstOrDefault(x => x.Name.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase)); if (ptrType != null) { //Get help by type Type pluginType = ptrType.Type; plugin = _Plugins.FirstOrDefault(x => x.GetType() == pluginType); if (plugin != null) { //Show Help using existing object plugin.ShowHelp(sender); return; } //Create instance and show help, dispose after use plugin = Activator.CreateInstance(pluginType) as ITcpAppServerPlugin; plugin.ShowHelp(sender); plugin.DisposeRequest(); plugin = null; return; } else { //Get help by alias name plugin = _Plugins.FirstOrDefault(x => string.Compare(x.Alias, pluginName, true) == 0); if (plugin != null) { plugin.ShowHelp(sender); return; } } sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = "Object [" + aliasName + "] not exist!"; } }
private void Client_ProcessReceivedMessage(TcpServerConnection client, string message, byte[] messageBytes) { //Parse and Execute Commands string[] cmdArg = TcpAppCommon.ParseCommand(message.Trim()); try { //Register Client Connection TcpAppServerConnection ptrClient = AppClients.FirstOrDefault(x => x.Connection == client); if (ptrClient == null) { //Reconstruct device which had already signed out ptrClient = AddClientToAppClientsList(client); } Debug.WriteLine("AppServer[" + ptrClient.Name + "]-RX: " + message); TcpAppInputCommand inputCommand = TcpAppCommon.CreateInputCommand(Commands, cmdArg); if (inputCommand != null) { inputCommand.AppClient = ptrClient; } else//Command keyword not exist { //Check if command keyword is alias name ITcpAppServerPlugin plugin = _Plugins.FirstOrDefault(x => string.Compare(x.Alias, cmdArg[0], true) == 0); if (plugin != null) { //Execute plugin command inputCommand = plugin.GetPluginCommand(cmdArg.Skip(1).ToArray()); inputCommand.AppClient = ptrClient; BeforeExecutePluginCommand?.Invoke(this, new TcpAppServerExEventArgs(ptrClient) { Plugin = plugin }); } else { //Error - Unrecognized command. inputCommand = new TcpAppInputCommand() { Status = TcpAppCommandStatus.ERR, OutputMessage = "Invalid Command " + cmdArg[0] }; WriteResultToClient(ptrClient, inputCommand); return; } } //Verify Client had signed in. if (!inputCommand.AppClient.SignedIn && !inputCommand.Command.IsSystemCommand) { throw new Exception("Client not signed in! Execute SignIn first."); } if (inputCommand.Command.UseMessageQueue && !inputCommand.Command.IsSystemCommand) { //Single thread execution, post message to message queue. lock (CommandQueue) { inputCommand.ID = inputCommand.GetHashCode(); if (ptrClient.NextQueuedCommand == null) { ptrClient.NextQueuedCommand = inputCommand; //Set pointer to next queued command. } //Add Command to Queue CommandQueue.Add(inputCommand); CommandQueueWaitSignal?.Set(); inputCommand.OutputMessage = inputCommand.ID.ToString(); inputCommand.Status = TcpAppCommandStatus.QUEUED; } } else if (inputCommand.Command.IsSystemCommand) { inputCommand.ExecuteCallback(); } else { //Execute command, wait until return if (ExecutionTimeout == 0) { inputCommand.ExecuteCallback(); } //Execute command, terminate on timeout else { ptrClient.ExecuteCommandAsync(inputCommand, ExecutionTimeout); } } WriteResultToClient(ptrClient, inputCommand); //Send result back to client. } catch (Exception ex) { WriteExceptionErrorToClient(client, ex); } }
/// <summary> /// Constructor /// </summary> public TcpAppServer() : base() { MessageDelimiter = Convert.ToByte(Convert.ToChar(TcpAppCommon.Delimiter)); base.ClientConnected += TcpAppServer_ClientConnected; base.ClientDisconnected += TcpAppServer_ClientDisconnected; base.ServerStopped += TcpAppServer_ServerStopped; CommandQueueThread = new Thread(ExecuteQueuedCommandsAsync); AbortCommandQueueThread = false; CommandQueueThread.Start(); //TcpAppServer Format: // TX: TCP: <Command> [-Param0] [-Param1] ... [-ParamN] // RX: TCP: <Status> [Return Message] // Source - [email protected]:23 // Command - Registered Command. //Register System Commands //--- INIT (Commands used by TcpAppClient) --- RegisterSystemCommand("Help", "Show help screen. Include plugin type or object alias name to show commands for selected plugin.", ShowHelp, TcpAppParameter.CreateOptionalParameter("Plugin", "Plugin type or Alias", "-")); RegisterSystemCommand("SignIn", "Sign in to TcpAppServer. Server will verify connection id and return unique ID.", delegate(TcpAppInputCommand sender) { //Assign Name string machineName = sender.Command.Parameter("ConnectionID").Value?.Replace(" ", "_"); if (string.IsNullOrEmpty(machineName)) { machineName = sender.AppClient.Connection.ClientIPAddress.ToString(); } if (sender.AppClient.SignedIn) { //Client already signed in, verify connection ID. if (sender.AppClient.Name.Equals(machineName, StringComparison.InvariantCultureIgnoreCase)) { sender.OutputMessage = sender.AppClient.Name; sender.Status = TcpAppCommandStatus.OK; return; } else { sender.AppClient.SignedIn = false; } } TcpAppServerExEventArgs signInArg = new TcpAppServerExEventArgs(sender.AppClient) { Value = machineName }; ClientSigningIn?.Invoke(this, signInArg); if (signInArg.Cancel == true) { sender.OutputMessage = signInArg.Reason; if (string.IsNullOrEmpty(sender.OutputMessage)) { sender.OutputMessage = "Access Denied!"; } sender.Status = TcpAppCommandStatus.ERR; return; } string uniqueName = machineName; lock (AppClients) { //Cleanup instance with same name but already disconnected without signout if (AppClients.FirstOrDefault(x => x.Name == uniqueName) != null) { for (int x = 0; x < AppClients.Count;) { if (!AppClients[x].Connection.Connected && AppClients[x].Name.StartsWith(uniqueName)) { AppClients[x].Dispose(); AppClients.RemoveAt(x); } else { x++; } } } while (AppClients.FirstOrDefault(x => x.Name == uniqueName) != null) { uniqueName = machineName + "_" + (++Counter).ToString(); } sender.AppClient.Name = uniqueName; sender.OutputMessage = uniqueName; sender.Status = TcpAppCommandStatus.OK; sender.AppClient.SignedIn = true; ClientSignedIn?.Invoke(this, new TcpAppServerEventArgs(sender.AppClient)); //Event } }, TcpAppParameter.CreateParameter("ConnectionID", "Connection ID. If already exist, server will return an updated unique ID.")); RegisterSystemCommand("SignOut", "Signout TcpAppClient.", delegate(TcpAppInputCommand sender) { ClientSigningOut?.Invoke(this, new TcpAppServerEventArgs(sender.AppClient)); sender.AppClient.Dispose(); lock (AppClients) { AppClients.Remove(sender.AppClient); } sender.AppClient.SignedIn = false; sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("Version?", "Get TcpAppServer Library Version", delegate(TcpAppInputCommand sender) { sender.OutputMessage = Version.ToString(); sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("Terminate", "Terminate Application. Command only valid after client Signin. Default Exit Code = -99", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); int exitCode = -99; try { exitCode = Convert.ToInt32(sender.Command.Parameter("ExitCode").Value); } catch { } sender.Status = TcpAppCommandStatus.OK; Environment.ExitCode = exitCode; Thread ptrThread = new Thread(TerminateApplication); ptrThread.Start(); }, TcpAppParameter.CreateOptionalParameter("ExitCode", "Assign Exit Code for application termination.", "-99")); //--- Execution --- RegisterSystemCommand("FunctionList?", "Get list of registered functions.", delegate(TcpAppInputCommand sender) { foreach (TcpAppCommand x in Commands) { sender.OutputMessage += x.Keyword; sender.OutputMessage += " "; } sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("Execute", "Execute plugin's command. Command only valid after client Signin.", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); ITcpAppServerPlugin plugin = _Plugins.FirstOrDefault(x => string.Compare(x.Alias, sender.Command.Parameter("Alias").Value, true) == 0); if (plugin == null) { throw new ArgumentException("Plugin not exists!"); } TcpAppInputCommand pluginCommand = plugin.GetPluginCommand(sender.Arguments.Skip(1).ToArray()); TcpAppServerExEventArgs pluginExecuteEventArgs = new TcpAppServerExEventArgs(sender.AppClient) { Plugin = plugin }; BeforeExecutePluginCommand?.Invoke(this, pluginExecuteEventArgs); if (pluginExecuteEventArgs.Cancel) { //Command execution cancelled by server, return error with reason. sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = pluginExecuteEventArgs.Reason; } else { //Proceed with execution. pluginCommand.ExecuteCallback(); sender.Status = pluginCommand.Status; sender.OutputMessage = pluginCommand.OutputMessage; } }, TcpAppParameter.CreateParameter("Alias", "Plugin Alias Name.")); RegisterSystemCommand("CheckStatus", "Check execution status for queued command. RETURN: Command status if executed, else BUSY. ERR if no queued message.", delegate(TcpAppInputCommand sender) { int queueID = Convert.ToInt32(sender.Command.Parameter("QueueID").Value); if (queueID == 0) { //ID not specified, get status for next queued command. if (sender.AppClient.NextQueuedCommand == null) { sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = "No queued message!"; return; } sender.Status = sender.AppClient.NextQueuedCommand.Status; switch (sender.AppClient.NextQueuedCommand.Status) { case TcpAppCommandStatus.BUSY: case TcpAppCommandStatus.QUEUED: sender.OutputMessage = string.Empty; break; default: lock (CommandQueue) { //Return result for all queued message except executing one. TcpAppInputCommand[] results = ResultQueue.Where(x => x.AppClient == sender.AppClient).ToArray(); TcpAppInputCommand nextQueue = null; foreach (TcpAppInputCommand cmd in results) { if (cmd.Status == TcpAppCommandStatus.BUSY || cmd.Status == TcpAppCommandStatus.QUEUED) { nextQueue = cmd; break; } if (cmd.Status == TcpAppCommandStatus.ERR) { cmd.Status = sender.Status; cmd.OutputMessage += "! "; //Prefix for command with error status. } ResultQueue.Remove(cmd); sender.OutputMessage += cmd.OutputMessage + "\n"; } //Return number of remaining queued commands sender.OutputMessage += CommandQueue.Where(x => x.AppClient == sender.AppClient).Count().ToString(); sender.AppClient.NextQueuedCommand = nextQueue; } break; } } else { //Return status of specific message. TcpAppInputCommand ptrCmd = CommandQueue.FirstOrDefault(x => x.AppClient == sender.AppClient && x.ID == queueID); if (ptrCmd == null) { ptrCmd = ResultQueue.FirstOrDefault(x => x.AppClient == sender.AppClient); if (ptrCmd != null) { ResultQueue.Remove(ptrCmd); } else { sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = "Invalid ID: " + queueID.ToString(); return; } } sender.OutputMessage = ptrCmd.OutputMessage; sender.Status = ptrCmd.Status; } }, TcpAppParameter.CreateOptionalParameter("QueueID", "Get status of specific message.", "0")); RegisterSystemCommand("Abort", "Abort last queued command.", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); if (sender.AppClient.NextQueuedCommand != null) { lock (CommandQueue) { CommandQueue.Remove(sender.AppClient.NextQueuedCommand); ResultQueue.Remove(sender.AppClient.NextQueuedCommand); sender.AppClient.NextQueuedCommand = null; } } sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("FlushQueue", "Flush message queue for calling client.", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); lock (CommandQueue) { CommandQueue.RemoveAll(x => x.AppClient == sender.AppClient); ResultQueue.RemoveAll(x => x.AppClient == sender.AppClient); sender.AppClient.NextQueuedCommand = null; } sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("FlushAllQueue", "Flush message queue for all clients.", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); lock (CommandQueue) { CommandQueue.Clear(); ResultQueue.Clear(); lock (AppClients) { foreach (TcpAppServerConnection client in AppClients) { client.NextQueuedCommand = null; } } } sender.Status = TcpAppCommandStatus.OK; }); //--- PLUGIN --- RegisterSystemCommand("PluginTypes?", "Get list of plugin class type. Use CreatePlugins command to instantiate type.", delegate(TcpAppInputCommand sender) { if (PluginTypes.Count == 0) { sender.OutputMessage = "-NONE-"; } else { sender.OutputMessage = string.Join(" ", PluginTypes.Select(x => x.Name).ToArray()); } sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("CreatePlugin", "Create an plugin object from listed plugin types. Command only valid after client Signin.", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); string typeName = sender.Command.Parameter("TypeName").Value; //Sanity Check - Type Name if (PluginTypes.FirstOrDefault(x => x.Name.Equals(typeName, StringComparison.InvariantCultureIgnoreCase)) == null) { throw new ArgumentException("Unknown plugin type: " + typeName); } Type pluginType = PluginTypes.FirstOrDefault(x => x.Name.Equals(typeName, StringComparison.InvariantCultureIgnoreCase)).Type; string aliasName; sender.OutputMessage = "Plugin created:"; foreach (string value in sender.Command.Parameter("Alias").Values) { aliasName = value; if (Commands.FirstOrDefault(x => string.Compare(x.Keyword, aliasName, true) == 0) != null) { throw new ArgumentException("Unable to create plugin with alias '" + aliasName + "'. Name already registered as command!"); } //Sanity Check - Verify alias name is not plugin type name if (PluginTypes.FirstOrDefault(x => string.Compare(x.Name, aliasName, true) == 0) != null) { throw new ArgumentException("Unable to create plugin with alias '" + aliasName + "'. Name already registered plugin type!"); } //Sanity Check - Alias Name if (_Plugins.FirstOrDefault(x => string.Compare(x.Alias, aliasName, true) == 0) != null) { throw new ArgumentException("Unable to create plugin with alias '" + aliasName + "'. Plugin already exists!"); } ITcpAppServerPlugin pluginInstance = Activator.CreateInstance(pluginType) as ITcpAppServerPlugin; pluginInstance.Alias = aliasName; _Plugins.Add(pluginInstance); PluginCreated?.Invoke(this, new TcpAppServerEventArgs(sender.AppClient) { Plugin = pluginInstance }); sender.OutputMessage += " " + aliasName; } sender.Status = TcpAppCommandStatus.OK; }, TcpAppParameter.CreateParameter("TypeName", "Plugin type name."), TcpAppParameter.CreateParameterArray("Alias", "Plugin object name, case insensitive.", false)); RegisterSystemCommand("Plugins?", "Return plugins list by alias name.", delegate(TcpAppInputCommand sender) { if (_Plugins.Count == 0) { sender.OutputMessage = "-NONE-"; } else { sender.OutputMessage = string.Join(TcpAppCommon.NewLine, _Plugins.Select(x => x.Alias + "(" + PluginTypes.FirstOrDefault(n => n.Type == x.GetType())?.Name + ")").ToArray()); } sender.Status = TcpAppCommandStatus.OK; }); RegisterSystemCommand("DisposePlugin", "Delete plugin by alias name. Command only valid after client Signin.", delegate(TcpAppInputCommand sender) { VerifyUserSignedIn(sender); string alias = sender.Command.Parameter("Alias").Value; ITcpAppServerPlugin item = _Plugins.FirstOrDefault(x => string.Compare(x.Alias, alias, true) == 0); if (item == null) { sender.OutputMessage = "Plugin [" + alias + "] not found / disposed."; sender.Status = TcpAppCommandStatus.OK; return; } else { if (item.DisposeRequest() == true) { _Plugins.Remove(item); PluginDisposed?.Invoke(this, new TcpAppServerEventArgs(sender.AppClient) { Plugin = item }); sender.OutputMessage = alias + " disposed."; sender.Status = TcpAppCommandStatus.OK; } else { sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = "Unable to dispose " + alias; } } }, TcpAppParameter.CreateParameter("Alias", "Plugin alias name.")); }
private void Client_ProcessReceivedMessage(TcpServerConnection client, string message, byte[] messageBytes) { //Parse and Execute Commands string[] cmdArg = TcpAppCommon.ParseCommand(message.Trim()); //Process Command Keyword TcpAppCommand cmdHandler = GetCommand(cmdArg[0]); if (cmdHandler == null) { //Error - Unrecognized command. client.WriteLineToClient(string.Format("{0} {1} Invalid Command!", cmdArg[0], TcpAppCommandStatus.ERR.ToString())); return; } TcpAppInputCommand cmdInput = new TcpAppInputCommand() { Command = cmdHandler }; cmdInput.Arguments = cmdArg.Skip(1).ToArray(); //Move to TcpAppInputCommand //Process Parameters cmdHandler.ResetParametersValue(); int argID = 1; //First Parameter foreach (TcpAppParameter item in cmdHandler.Parameters) { if (argID >= cmdArg.Length) { //Argument with no input if (!item.IsOptional) { //Error - Missing required parameter cmdInput.OutputMessage = "Missing required parameter: " + item.Name + "!"; WriteResultToClient(client, cmdInput); return; } } else { item.Value = cmdArg[argID]; //Assign parameter value } argID++; } //Execute Commands try { cmdInput.Command.ExecuteCallback(cmdInput); } catch (Exception ex) { //Catch and report all execution error cmdInput.OutputMessage = "Exception Raised! " + ex.Message; cmdInput.Status = TcpAppCommandStatus.ERR; //Force status to error, make sure no surprise. } finally { WriteResultToClient(client, cmdInput); //Send result back to client. } }
/// <summary> /// Constructor /// </summary> /// <param name="mainForm">Main Form Handle</param> public TcpAppServer(Form mainForm) : base() { MainForm = mainForm; MessageDelimiter = Convert.ToByte(Convert.ToChar(TcpAppCommon.Delimiter)); base.ClientConnected += TcpAppServer_ClientConnected; base.ClientDisconnected += TcpAppServer_ClientDisconnected; //TcpAppServer Format: // TX: TCP: <Command> [-Param0] [-Param1] ... [-ParamN] // RX: TCP: <Command> <Status> [Return Message] // Source - [email protected]:23 // Command - Registered Command. //Register System Commands //--- INIT (Commands used by TcpAppClient) --- RegisterCommand("TcpAppInit", "Initialize TCP Application.", delegate(TcpAppInputCommand sender) { sender.OutputMessage = string.IsNullOrEmpty(WelcomeMessage) ? Application.ProductName + " " + Application.ProductVersion : WelcomeMessage; sender.Status = TcpAppCommandStatus.OK; }); RegisterCommand("TcpAppVersion?", "Get TcpAppServer Library Version", delegate(TcpAppInputCommand sender) { sender.OutputMessage = Version.ToString(); sender.Status = TcpAppCommandStatus.OK; }); RegisterCommand("FunctionList?", "Get list of registered functions.", delegate(TcpAppInputCommand sender) { foreach (TcpAppCommand x in Commands) { sender.OutputMessage += x.Keyword; sender.OutputMessage += " "; } sender.Status = TcpAppCommandStatus.OK; }); //-- APP INFO -- RegisterCommand("ApplicationName?", "Get Application Name.", delegate(TcpAppInputCommand sender) { sender.OutputMessage = Application.ProductName; sender.Status = TcpAppCommandStatus.OK; }); RegisterCommand("ApplicationVersion?", "Get Application Version.", delegate(TcpAppInputCommand sender) { sender.OutputMessage = Application.ProductVersion; sender.Status = TcpAppCommandStatus.OK; }); //--- PLUGIN --- RegisterCommand("PluginTypes?", "Get list of plugin class type. Use CreateObject command to instantiate type.", delegate(TcpAppInputCommand sender) { if (PluginTypes.Count == 0) { sender.OutputMessage = "-NONE-"; } else { sender.OutputMessage = string.Join(" ", PluginTypes.Keys.ToArray()); } sender.Status = TcpAppCommandStatus.OK; }); RegisterCommand("CreateObject", "Create an object from listed plugin types.", delegate(TcpAppInputCommand sender) { string typeName = sender.Command.Parameter("TypeName").Value; string aliasName = sender.Command.Parameter("Alias").Value; //Sanity Check - Type Name Type pluginType = PluginTypes[PluginTypes.Keys.FirstOrDefault(x => string.Compare(x, typeName, true) == 0)]; if (!PluginTypes.Keys.Contains(typeName, StringComparer.InvariantCultureIgnoreCase)) { throw new ArgumentException("Unknown plugin type: " + typeName); } //Sanity Check - Alias Name if (Plugins.FirstOrDefault(x => string.Compare(x.Alias, aliasName, true) == 0) != null) { throw new ArgumentException("Unable to create object with alias '" + aliasName + "'. Object already exists!"); } ITcpAppServerPlugin pluginInstance = Activator.CreateInstance(pluginType) as ITcpAppServerPlugin; pluginInstance.Alias = aliasName; Plugins.Add(pluginInstance); sender.OutputMessage = "Object created " + aliasName; sender.Status = TcpAppCommandStatus.OK; }, new TcpAppParameter("TypeName", "Plugin type name."), new TcpAppParameter("Alias", "Plugin object Alias Name. Alias name is case insensitive")); RegisterCommand("Objects?", "Return object list by alias name.", delegate(TcpAppInputCommand sender) { if (Plugins.Count == 0) { sender.OutputMessage = "-NONE-"; } else { sender.OutputMessage = string.Join(" ", Plugins.Select(x => x.Alias).ToArray()); } sender.Status = TcpAppCommandStatus.OK; }); RegisterCommand("Execute", "Exceute plugin's command.", delegate(TcpAppInputCommand sender) { ITcpAppServerPlugin plugin = Plugins.FirstOrDefault(x => string.Compare(x.Alias, sender.Command.Parameter("Alias").Value, true) == 0); if (plugin == null) { throw new ArgumentNullException("Plugin not exists!"); } TcpAppInputCommand pluginCommand = new TcpAppInputCommand() { Arguments = sender.Arguments }; plugin.ExecutePluginCommand(pluginCommand); sender.Status = pluginCommand.Status; sender.OutputMessage = pluginCommand.OutputMessage; }, new TcpAppParameter("Alias", "Plugin object Alias Name.")); RegisterCommand("DisposeObject", "Delete object by alias name.", delegate(TcpAppInputCommand sender) { string alias = sender.Command.Parameter("Alias").Value; ITcpAppServerPlugin item = Plugins.FirstOrDefault(x => string.Compare(x.Alias, alias, true) == 0); if (item == null) { sender.OutputMessage = "Object [" + alias + "] not found / disposed."; sender.Status = TcpAppCommandStatus.OK; return; } else { if (item.DisposeRequest() == true) { Plugins.Remove(item); sender.OutputMessage = alias + " disposed."; sender.Status = TcpAppCommandStatus.OK; } else { sender.Status = TcpAppCommandStatus.ERR; sender.OutputMessage = "Unable to dispose " + alias; } } }, new TcpAppParameter("Alias", "Object alias name.")); //-- GUI Control -- string ErrMainFormNull = "Main Form not assigned!"; RegisterCommand("MaximizeWindow", "Maximize Application Window.", delegate(TcpAppInputCommand sender) { if (MainForm != null) { MainForm.WindowState = FormWindowState.Maximized; sender.Status = TcpAppCommandStatus.OK; } else { sender.OutputMessage = ErrMainFormNull; } }); RegisterCommand("MinimizeWindow", "Minimize Application Window.", delegate(TcpAppInputCommand sender) { if (MainForm != null) { MainForm.WindowState = FormWindowState.Minimized; sender.Status = TcpAppCommandStatus.OK; } else { sender.OutputMessage = ErrMainFormNull; } }); RegisterCommand("RestoreWindow", "Restore Application Window.", delegate(TcpAppInputCommand sender) { if (MainForm != null) { MainForm.WindowState = FormWindowState.Normal; sender.Status = TcpAppCommandStatus.OK; } else { sender.OutputMessage = ErrMainFormNull; } }); RegisterCommand("BringToFront", "Set Application Window as Top Most.", delegate(TcpAppInputCommand sender) { if (MainForm != null) { MainForm.BringToFront(); sender.Status = TcpAppCommandStatus.OK; } else { sender.OutputMessage = ErrMainFormNull; } }); RegisterCommand("SetWindowPosition", "Set Window Position.", delegate(TcpAppInputCommand sender) { if (MainForm != null) { MainForm.Location = new System.Drawing.Point( Convert.ToInt16(sender.Command.Parameter("X").Value), Convert.ToInt16(sender.Command.Parameter("Y").Value)); sender.Status = TcpAppCommandStatus.OK; } else { sender.OutputMessage = ErrMainFormNull; } }, new TcpAppParameter("X", "Upper left X coordinate of main form."), new TcpAppParameter("Y", "Upper left Y coordinate of main form.")); RegisterCommand("Terminate", "Terminate Application. Default Exit Code = -99", delegate(TcpAppInputCommand sender) { int exitCode = -99; try { exitCode = Convert.ToInt32(sender.Command.Parameter("ExitCode").Value); } catch { } sender.Status = TcpAppCommandStatus.OK; Environment.ExitCode = exitCode; System.Threading.Thread ptrThread = new System.Threading.Thread(TerminateApplication); ptrThread.Start(); }, new TcpAppParameter("ExitCode", "Assign Exit Code for application termination.", "-99")); //-- User Interaction -- RegisterCommand("Help", "Show help screen.", ShowHelp, new TcpAppParameter("Alias", "Object Alias Name", "-")); }