From 838b31cb1ffd62f5d2ea569a4c16fcd5d53fc259 Mon Sep 17 00:00:00 2001 From: "SnapixLP | Tim G." Date: Thu, 5 Jun 2025 09:33:01 +0200 Subject: [PATCH] updated CommandManager.cs to use attributes instead of Classes --- Server/CommandAttribute.cs | 12 +++++ Server/CommandException.cs | 10 +++++ Server/CommandLibrary.cs | 73 +++++++++++++++++++++++++++++++ Server/CommandManager.cs | 90 ++++++++++++++++++++++++++++---------- 4 files changed, 163 insertions(+), 22 deletions(-) create mode 100644 Server/CommandAttribute.cs create mode 100644 Server/CommandException.cs create mode 100644 Server/CommandLibrary.cs diff --git a/Server/CommandAttribute.cs b/Server/CommandAttribute.cs new file mode 100644 index 0000000..cd87618 --- /dev/null +++ b/Server/CommandAttribute.cs @@ -0,0 +1,12 @@ +namespace Server; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public sealed class CommandAttribute : Attribute +{ + public string Name { get; } + + public CommandAttribute(string name) + { + Name = name; + } +} \ No newline at end of file diff --git a/Server/CommandException.cs b/Server/CommandException.cs new file mode 100644 index 0000000..1c8cf6f --- /dev/null +++ b/Server/CommandException.cs @@ -0,0 +1,10 @@ +namespace Server; + +using System; + +public class CommandException : Exception +{ + public CommandException(string message) : base(message) + { + } +} \ No newline at end of file diff --git a/Server/CommandLibrary.cs b/Server/CommandLibrary.cs new file mode 100644 index 0000000..0f6b2c8 --- /dev/null +++ b/Server/CommandLibrary.cs @@ -0,0 +1,73 @@ +using System.Net.Sockets; +using DX86; +using Server.Commands; + +namespace Server; + +public class CommandLibrary +{ + [Command("example")] + public static string ExampleCommand(string[] args, TcpClient? client, TcpServer? socket) => + $"Example command executed with arguments: {string.Join(", ", args)}"; + + #region Basic Commands + + [Command("help")] + public static string HelpCommand() => + "Available commands:\n" + + "1. help - Show this help message\n" + + "2. exit - Exit the server\n" + + "3. user - User management\n" + + "4. settings - Server settings\n" + + "5. start - Start the server\n" + + "6. stop - Stop the server\n"; + + #endregion + + #region Client Commands + + [Command("login")] + public static string LoginCommand(string[] args, TcpClient? client, TcpServer? socket) + { + if (args.Length < 2) + throw new CommandException("Missing arguments: usage is login "); + + string username = args[0]; + string password = args[1]; + + if (username == "test" && password == "1234") + { + if (client != null) + { + socket?.LoggedInClients.Add(client, username); + return "Login successful"; + } + + throw new CommandException("No client connection detected."); + } + + throw new CommandException("Invalid username or password."); + } + + [Command("logout")] + public static string LogoutCommand(TcpClient? client, TcpServer? socket) + { + if (client != null && socket?.LoggedInClients.ContainsKey(client) == true) + { + socket.LoggedInClients.Remove(client); + return "Logout successful"; + } + throw new CommandException("No client provided or not logged in"); + } + + #endregion + + #region Administration Commands + + [Command("get")] + public static string GetCommand(string[] args, TcpClient? client, TcpServer? socket) => + $"not implemented yet, args: {string.Join(", ", args)}"; + + #endregion + +} \ No newline at end of file diff --git a/Server/CommandManager.cs b/Server/CommandManager.cs index d1720d5..f7154a8 100644 --- a/Server/CommandManager.cs +++ b/Server/CommandManager.cs @@ -8,7 +8,7 @@ namespace Server; public class CommandManager { - private readonly Dictionary _commands = new(); + private readonly Dictionary _commands = new(); public CommandManager() { @@ -17,38 +17,84 @@ public class CommandManager private void LoadCommands() { - // Get all types implementing ICommand - var commandTypes = Assembly.GetExecutingAssembly() + var methods = Assembly.GetExecutingAssembly() .GetTypes() - .Where(t => typeof(ICommand).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); + .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static)) + .Where(m => m.GetCustomAttribute() != null); - foreach (var type in commandTypes) + foreach (var method in methods) { - // Create an instance of the command - if (Activator.CreateInstance(type) is ICommand command) - { - // Use the Executor property as the key - _commands[command.Executor] = command; - } + var attr = method.GetCustomAttribute()!; + _commands[attr.Name.ToLower()] = method; + Program.messageSender.Log($"[COMMANDMANAGER] Registered command: {attr.Name}"); } } - public void ExecuteCommand(string executor, TcpClient? client = null, TcpServer? clientSocket = null, string cid = "", params string[] args) +{ + if (_commands.TryGetValue(executor.ToLower(), out var method)) { - if (_commands.TryGetValue(executor, out var command)) + try { - JsonMessage returnMessage = new JsonMessage(); - returnMessage.cid = cid; - returnMessage.cmd = command.Exec(args:args, client:client, clientSocket:clientSocket); + var parameters = method.GetParameters(); + var arguments = new object?[parameters.Length]; - string sendClientMessage = JsonSerializer.Serialize(returnMessage); - - clientSocket.SendMessageAsync(client:client, message:sendClientMessage+"\n"); - //clientSocket.SendMessageAsync(client:client, message:command.Exec(args:args, client:client, clientSocket:clientSocket)); + for (int i = 0; i < parameters.Length; i++) + { + var param = parameters[i]; + + if (param.ParameterType == typeof(string[])) + arguments[i] = args; + else if (param.ParameterType == typeof(TcpClient)) + arguments[i] = client; + else if (param.ParameterType == typeof(TcpServer)) + arguments[i] = clientSocket; + else + { + Program.messageSender.Warn($"[COMMANDMANAGER] Unknown parameter type '{param.ParameterType.Name}' in command '{executor}'. Defaulting to null."); + arguments[i] = null; + } + } + + Program.messageSender.Debug($"[COMMANDMANAGER] Executing command '{executor}'..."); + string result = method.Invoke(null, arguments)?.ToString() ?? ""; + + var returnMessage = new JsonMessage + { + cid = cid, + cmd = result + }; + + var sendClientMessage = JsonSerializer.Serialize(returnMessage); + clientSocket?.SendMessageAsync(client, sendClientMessage + "\n"); + Program.messageSender.Debug($"[COMMANDMANAGER] Response sent to client."); } - else + catch (TargetInvocationException ex) when (ex.InnerException is CommandException cmdEx) { - Program.messageSender.Log($"[COMMANDMANAGER] Command '{executor}' not found."); + Program.messageSender.Warn($"[COMMANDMANAGER] Command '{executor}' failed: {cmdEx.Message}"); + + var returnMessage = new JsonMessage + { + cid = cid, + cmd = $"Error: {cmdEx.Message}" + }; + + var sendClientMessage = JsonSerializer.Serialize(returnMessage); + clientSocket?.SendMessageAsync(client, sendClientMessage + "\n"); + } + catch (TargetInvocationException ex) + { + var actualError = ex.InnerException?.Message ?? ex.Message; + Program.messageSender.Error($"[COMMANDMANAGER] Unexpected error in command '{executor}': {actualError}"); + Program.messageSender.Debug($"[COMMANDMANAGER] Stack Trace: {ex.InnerException?.StackTrace ?? ex.StackTrace}"); + } + catch (Exception ex) + { + Program.messageSender.Error($"[COMMANDMANAGER] Failed to invoke command '{executor}': {ex.Message}"); } } + else + { + Program.messageSender.Warn($"[COMMANDMANAGER] Unknown command '{executor}' received."); + } +} } \ No newline at end of file