using System.Net.Sockets; using System.Text; using System.Text.Json; using System.Collections.Concurrent; namespace Library; public class Server { private TcpClient client; private NetworkStream stream; private StreamReader reader; private StreamWriter writer; private Action onMessageReceived; private Action onCommandReceived; public Action OnMessageReceived { get => onMessageReceived; set => onMessageReceived = value ?? throw new ArgumentNullException(nameof(value), "onMessageReceived cannot be null."); } public Action OnCommandReceived { get => onCommandReceived; set => onCommandReceived = value ?? throw new ArgumentNullException(nameof(value), "onMessageReceived cannot be null."); } private ConcurrentDictionary> pendingRequests = new(); public Server(string ip, int port) { ConnectAsync(ip, port).Wait(); } private async Task ConnectAsync(string serverIp, int serverPort) { client = new TcpClient(); await client.ConnectAsync(serverIp, serverPort); stream = client.GetStream(); reader = new StreamReader(stream, Encoding.UTF8); writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true }; Console.WriteLine("Connected to the server."); _ = ReceiveMessagesAsync(); // Start receiving messages in the background } private async Task ReceiveMessagesAsync() { try { while (client.Connected) { string message = await reader.ReadLineAsync(); if (message != null) { if (message.StartsWith("{") && message.EndsWith("}")) { onCommandReceived?.Invoke(message); Console.WriteLine("Received: " + message); // Parse the JSON response var response = JsonSerializer.Deserialize(message); Console.WriteLine("Parsed Response: " + (response != null ? $"Id={response.Id}, Response={response.Response}" : "null")); if (response != null && pendingRequests.TryRemove(response.Id, out var tcs)) { tcs.SetResult(response.Response); // Complete the task with the response } else { onMessageReceived?.Invoke(message); // Handle other messages } } else { onMessageReceived?.Invoke(message); // Handle other messages } } } } catch (Exception ex) { Console.WriteLine("Error receiving data: " + ex.Message); } } private async Task ExecuteCommandAsync(string command) { var requestId = Guid.NewGuid().ToString(); // Generate a unique ID for the request var tcs = new TaskCompletionSource(); pendingRequests[requestId] = tcs; // Create the JSON request var request = new JsonRequest { cmd = command, cid = requestId }; string jsonString = JsonSerializer.Serialize(request); // Send the command with the request ID await SendMessageAsync(jsonString); // Await the response return await tcs.Task; } private async Task SendMessageAsync(string message) { if (client.Connected) { await writer.WriteLineAsync(message); } } public class JsonRequest { public string cmd { get; set; } public string cid { get; set; } } public class JsonResponse { public string Id { get; set; } public string Response { get; set; } } public Task GetEmployee(int? id = null, string code = null) { if (id == null && code == null) { throw new ArgumentException("Either id or code must be provided."); } if (id != null && code != null) { throw new ArgumentException("Only one of id or code should be provided."); } string commandResult; // Implement logic to get a worker by ID or code if (id != null) commandResult = ExecuteCommandAsync("get employee byid " + id).Result; else commandResult = ExecuteCommandAsync("get employee bycode " + code).Result; // Deserialize the command result to an Employee object try { var employee = Employee.FromJson(commandResult); return Task.FromResult(employee); } catch (JsonException) { Console.WriteLine("Failed to deserialize the command result."); } return Task.FromException(new Exception("Failed to get worker.")); } public Task Login(string username, string password) { // Implement login logic var commandResult = ExecuteCommandAsync("login " + username + " " + password).Result; if (commandResult == "success") { return Task.FromResult("Success"); } return Task.FromException(new Exception("Failed to login.")); } public Task HelpCommand() => ExecuteCommandAsync("help"); public Task Logout() { // Implement logout logic var commandResult = ExecuteCommandAsync("logout").Result; if (commandResult == "success") { return Task.FromResult("Success"); } return Task.FromException(new Exception("Failed to logout.")); } public Task GetLoggedInEmployee() { var commandResult = ExecuteCommandAsync("getSelfUser").Result; try { var employee = Employee.FromJson(commandResult); if (employee != null) { return Task.FromResult(employee); } return Task.FromException(new Exception("Failed to deserialize the employee data.")); } catch (JsonException) { Console.WriteLine("Failed to deserialize the command result."); } return Task.FromException(new Exception("Failed to get logged in employee.")); } public Task ClockIn(Employee? employee = null) { var commandResult = ExecuteCommandAsync("clock in").Result; if (commandResult == "success") { return Task.FromResult("Success"); } return Task.FromException(new Exception("Failed to clock in.")); } public Task ClockOut(Employee? employee = null) { var commandResult = ExecuteCommandAsync("clock out").Result; if (commandResult == "success") { return Task.FromResult("Success"); } else { return Task.FromException(new Exception("Failed to clock out.")); } } public Task ClockBreak(Employee? employee = null) { var commandResult = ExecuteCommandAsync("clock break").Result; if (commandResult == "success") { return Task.FromResult("Success"); } else { return Task.FromException(new Exception("Failed to clock break.")); } } public Task ClockHistory(string employeeCode) { var commandResult = ExecuteCommandAsync("fullClockHistory " + employeeCode).Result; return Task.FromResult(commandResult); } public Task FullClockHistory(int limit = 50) { var commandResult = ExecuteCommandAsync("fullClockHistory " + limit).Result; return Task.FromResult(commandResult); } }