This commit is contained in:
David Oppermann 2025-06-05 11:18:18 +02:00
commit 35aa165734
15 changed files with 303 additions and 40 deletions

View File

@ -155,6 +155,7 @@ namespace DX86
catch (Exception ex) catch (Exception ex)
{ {
ms.Error("[DX86] Error handling client: " + ex.Message); ms.Error("[DX86] Error handling client: " + ex.Message);
ms.Debug("[DX86] Stack Trace: " + ex.StackTrace);
} }
finally finally
{ {

View File

@ -37,6 +37,11 @@ public class MessageSender
} }
public async void Debug(string message)
{
Console.ForegroundColor = ConsoleColor.Green;
this.Send($"[{DateTime.Now}] [DEBUG] {message}");
}
public async void Log(string message) public async void Log(string message)
{ {
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
@ -76,6 +81,8 @@ public class MessageSender
int i = 0; int i = 0;
foreach (var s in messageHistory) foreach (var s in messageHistory)
{ {
if (s.Contains("[DEBUG]"))
Console.ForegroundColor = ConsoleColor.Green;
if (s.Contains("[INFO ]")) if (s.Contains("[INFO ]"))
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
if (s.Contains("[WARN ]")) if (s.Contains("[WARN ]"))

View File

@ -12,6 +12,7 @@ public abstract class TcpServer
protected MessageSender ms; protected MessageSender ms;
private DX86 dx86; private DX86 dx86;
public List<string> optionsList; public List<string> optionsList;
public Dictionary<TcpClient, string> LoggedInClients { get; }
public TcpServer(string address, int port, MessageSender ms) public TcpServer(string address, int port, MessageSender ms)
@ -28,6 +29,7 @@ public abstract class TcpServer
} }
private async Task RunServer() private async Task RunServer()
{ {
ms.Log("[DX86] Starting server."); ms.Log("[DX86] Starting server.");

View File

@ -69,8 +69,8 @@ public class Server
// Create the JSON request // Create the JSON request
var request = new JsonRequest var request = new JsonRequest
{ {
Id = requestId, cmd = command,
Command = command cid = requestId
}; };
string jsonString = JsonSerializer.Serialize(request); string jsonString = JsonSerializer.Serialize(request);
@ -92,8 +92,8 @@ public class Server
private class JsonRequest private class JsonRequest
{ {
public string Id { get; set; } public string cmd { get; set; }
public string Command { get; set; } public string cid { get; set; }
} }
private class JsonResponse private class JsonResponse
@ -119,9 +119,9 @@ public class Server
// Implement logic to get a worker by ID or code // Implement logic to get a worker by ID or code
if (id != null) if (id != null)
commandResult = ExecuteCommandAsync(".get worker byid " + id).Result; commandResult = ExecuteCommandAsync("get worker byid " + id).Result;
else else
commandResult = ExecuteCommandAsync(".get worker bycode " + id).Result; commandResult = ExecuteCommandAsync("get worker bycode " + id).Result;
// Deserialize the command result to an Employee object // Deserialize the command result to an Employee object
try try
@ -140,7 +140,7 @@ public class Server
public Task<string> Login(string username, string password) public Task<string> Login(string username, string password)
{ {
// Implement login logic // Implement login logic
var commandResult = ExecuteCommandAsync(".login " + username + " " + password).Result; var commandResult = ExecuteCommandAsync("login " + username + " " + password).Result;
if (commandResult == "success") if (commandResult == "success")
{ {
return Task.FromResult("Success"); return Task.FromResult("Success");
@ -151,7 +151,7 @@ public class Server
public Task<string> Logout() public Task<string> Logout()
{ {
// Implement logout logic // Implement logout logic
var commandResult = ExecuteCommandAsync(".logout").Result; var commandResult = ExecuteCommandAsync("logout").Result;
if (commandResult == "success") if (commandResult == "success")
{ {
return Task.FromResult("Success"); return Task.FromResult("Success");
@ -161,7 +161,7 @@ public class Server
public Task<string> clockIn(Employee employee) public Task<string> clockIn(Employee employee)
{ {
var commandResult = ExecuteCommandAsync(".clockin ").Result; var commandResult = ExecuteCommandAsync("clock in").Result;
if (commandResult == "success") if (commandResult == "success")
{ {
return Task.FromResult("Success"); return Task.FromResult("Success");
@ -170,7 +170,7 @@ public class Server
} }
public Task<string> clockOut(Employee employee) public Task<string> clockOut(Employee employee)
{ {
var commandResult = ExecuteCommandAsync(".clockout ").Result; var commandResult = ExecuteCommandAsync("clock out").Result;
if (commandResult == "success") if (commandResult == "success")
{ {
return Task.FromResult("Success"); return Task.FromResult("Success");
@ -182,7 +182,7 @@ public class Server
} }
public Task<string> clockBreak(Employee employee) public Task<string> clockBreak(Employee employee)
{ {
var commandResult = ExecuteCommandAsync(".clockbreak").Result; var commandResult = ExecuteCommandAsync("clock break").Result;
if (commandResult == "success") if (commandResult == "success")
{ {
return Task.FromResult("Success"); return Task.FromResult("Success");

View File

@ -1,8 +1,16 @@
using System.Net.Sockets; using System.Net.Sockets;
using System.Text.Json;
using DX86.Modules; using DX86.Modules;
using MySqlX.XDevAPI;
namespace Server; namespace Server;
class JsonMessage
{
public string cmd { get; set; }
public string cid { get; set; }
}
public class BackendServer : DX86.TcpServer public class BackendServer : DX86.TcpServer
{ {
CommandManager commandManager; CommandManager commandManager;
@ -31,11 +39,25 @@ public class BackendServer : DX86.TcpServer
protected override void MessageReceivedEvent(TcpClient client, string message) protected override void MessageReceivedEvent(TcpClient client, string message)
{ {
ms.Log("[BACKENDSERVER] Message received from client: " + message); ms.Log("[BACKENDSERVER] Message received from client: " + message);
if (message.StartsWith(".")) // format json recieved
JsonMessage? jsonMessage;
if (message.StartsWith("{") && message.EndsWith("}"))
{ {
handleCommand(cmd: message, client: client); try
{
jsonMessage = JsonSerializer.Deserialize<JsonMessage>(message);
if (jsonMessage != null)
{
ms.Log("[BACKENDSERVER] JSON Message received: cmd=" + jsonMessage.cmd + ", cid=" + jsonMessage.cid);
handleCommand(cmd: jsonMessage.cmd, cid: jsonMessage.cid, client: client);
}
}
catch (JsonException ex)
{
ms.Log("[BACKENDSERVER] Error parsing JSON: " + ex.Message);
}
} }
} }
protected override void ClientDisconnectEvent(TcpClient client) protected override void ClientDisconnectEvent(TcpClient client)
@ -43,12 +65,16 @@ public class BackendServer : DX86.TcpServer
throw new NotImplementedException(); throw new NotImplementedException();
} }
private void handleCommand(string cmd, TcpClient client) private void handleCommand(string cmd, string cid, TcpClient client)
{ {
string[] args = cmd.Split(' '); string[] args = cmd.Split(' ');
string command = args[0].Substring(1); // Remove the leading dot string command = args[0]; // Remove the leading dot
string[] commandArgs = args.Skip(1).ToArray(); // Get the arguments after the command string[] commandArgs = args.Skip(1).ToArray(); // Get the arguments after the command
foreach (var commandArg in commandArgs)
{
ms.Debug("[BACKENDSERVER] Command argument: " + commandArg);
}
commandManager.ExecuteCommand(executor:command, args:commandArgs, client:client, clientSocket:this); commandManager.ExecuteCommand(executor:command, args:commandArgs, client:client, clientSocket:this, cid: cid);
} }
} }

View File

@ -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;
}
}

View File

@ -0,0 +1,10 @@
namespace Server;
using System;
public class CommandException : Exception
{
public CommandException(string message) : base(message)
{
}
}

73
Server/CommandLibrary.cs Normal file
View File

@ -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 <username> <password>");
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
}

View File

@ -1,5 +1,6 @@
using System.Net.Sockets; using System.Net.Sockets;
using System.Reflection; using System.Reflection;
using System.Text.Json;
using DX86; using DX86;
using Server.Commands; using Server.Commands;
@ -7,7 +8,7 @@ namespace Server;
public class CommandManager public class CommandManager
{ {
private readonly Dictionary<string, ICommand> _commands = new(); private readonly Dictionary<string, MethodInfo> _commands = new();
public CommandManager() public CommandManager()
{ {
@ -16,31 +17,84 @@ public class CommandManager
private void LoadCommands() private void LoadCommands()
{ {
// Get all types implementing ICommand var methods = Assembly.GetExecutingAssembly()
var commandTypes = Assembly.GetExecutingAssembly()
.GetTypes() .GetTypes()
.Where(t => typeof(ICommand).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static))
.Where(m => m.GetCustomAttribute<CommandAttribute>() != null);
foreach (var type in commandTypes) foreach (var method in methods)
{ {
// Create an instance of the command var attr = method.GetCustomAttribute<CommandAttribute>()!;
if (Activator.CreateInstance(type) is ICommand command) _commands[attr.Name.ToLower()] = method;
{ Program.messageSender.Log($"[COMMANDMANAGER] Registered command: {attr.Name}");
// Use the Executor property as the key
_commands[command.Executor] = command;
}
} }
} }
public void ExecuteCommand(string executor, TcpClient? client = null, TcpServer? clientSocket = null, string cid = "", params string[] args)
public void ExecuteCommand(string executor, TcpClient? client = null, TcpServer? clientSocket = null, params string[] args) {
if (_commands.TryGetValue(executor.ToLower(), out var method))
{ {
if (_commands.TryGetValue(executor, out var command)) try
{ {
command.Exec(args:args, client:client, clientSocket:clientSocket); var parameters = method.GetParameters();
var arguments = new object?[parameters.Length];
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)
{ {
Console.WriteLine($"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.");
} }
} }
}

View File

@ -0,0 +1,6 @@
namespace Server.Commands;
public class ClockCommand
{
}

View File

@ -0,0 +1,6 @@
namespace Server.Commands;
public class GetCommand
{
}

View File

@ -6,19 +6,21 @@ namespace Server.Commands;
public class HelpCommand : ICommand public class HelpCommand : ICommand
{ {
public string Executor { get; } public string Executor { get; }
public HelpCommand() public HelpCommand()
{ {
Executor = "help"; Executor = "help";
} }
public void Exec(string[] args, TcpClient? client = null, TcpServer? clientSocket = null) public string Exec(string[] args, TcpClient? client = null, TcpServer? clientSocket = null)
{ {
clientSocket.SendMessageAsync(client, "" + return
"Available commands:\n" + "Available commands:\n" +
"1. help - Show this help message\n" + "1. help - Show this help message\n" +
"2. exit - Exit the server\n" + "2. exit - Exit the server\n" +
"3. user - User management\n" + "3. user - User management\n" +
"4. settings - Server settings\n" + "4. settings - Server settings\n" +
"5. start - Start the server\n" + "5. start - Start the server\n" +
"6. stop - Stop the server\n"); "6. stop - Stop the server\n"
;
} }
} }

View File

@ -6,5 +6,5 @@ namespace Server.Commands;
public interface ICommand public interface ICommand
{ {
string Executor { get; } string Executor { get; }
public void Exec(string[] args, TcpClient? client = null, TcpServer? clientSocket = null); public string Exec(string[] args, TcpClient? client, TcpServer? clientSocket);
} }

View File

@ -0,0 +1,34 @@
using System.Net.Sockets;
using DX86;
using MySqlX.XDevAPI;
namespace Server.Commands;
public class LoginCommand : ICommand
{
public string Executor { get; }
public LoginCommand()
{
Executor = "login";
}
public string Exec(string[] args, TcpClient? client, TcpServer? clientSocket)
{
if (args[0] == "test" && args[1] == "test")
{
if (client != null)
{
//clientSocket?.SendMessageAsync(client, "Login successful");
clientSocket?.LoggedInClients.Add(client, "test");
return "Login successful";
}
}
else
{
if (client != null) return "Invalid credentials";
}
return "No client provided or invalid credentials";
}
}

View File

@ -0,0 +1,30 @@
using System.Net.Sockets;
using DX86;
namespace Server.Commands;
public class LogoutCommand : ICommand
{
public string Executor { get; }
public LogoutCommand()
{
Executor = "logout";
}
public string Exec(string[] args, TcpClient? client = null, TcpServer? clientSocket = null)
{
if (clientSocket == null && client == null)
return "Please provide a valid client or clientSocket.";
if (client != null && clientSocket != null && clientSocket.LoggedInClients.ContainsKey(client))
{
clientSocket.LoggedInClients.Remove(client);
//clientSocket.SendMessageAsync(client, "Success");
return "Logout successful.";
}
else
{
//clientSocket?.SendMessageAsync(client, "Logout failed. You are not logged in.");
return "Logout failed. You are not logged in.";
}
}
}