using System; using System.Net.Sockets; using System.Text; using System.Threading; using Newtonsoft.Json; namespace Project { /// /// Background chat client service with auto-reconnect /// public class ChatClientService : IDisposable { private TcpClient tcpClient; private NetworkStream stream; private Thread receiveThread; private Thread reconnectThread; private bool isRunning; private bool isConnected; private string serverIp; private int serverPort; private string nickName; private string employeeId; private string hostName; private string userGroup; /// Connection status changed event public event EventHandler ConnectionStatusChanged; /// Message received event public event EventHandler MessageReceived; /// Connection status public bool IsConnected => isConnected; /// User nickname public string NickName => nickName; /// User employee ID public string EmployeeId => employeeId; /// User group public string UserGroup => userGroup; public ChatClientService(string serverIp, int serverPort) { this.serverIp = serverIp; this.serverPort = serverPort; this.hostName = System.Net.Dns.GetHostName(); } /// /// Start background service /// public void Start(string nickName, string employeeId, string userGroup) { if (isRunning) return; this.nickName = nickName; this.employeeId = employeeId; this.userGroup = userGroup; isRunning = true; // Start reconnect thread reconnectThread = new Thread(ReconnectLoop) { IsBackground = true, Name = "ChatReconnectThread" }; reconnectThread.Start(); } /// /// Stop background service /// public void Stop() { isRunning = false; Disconnect(); try { reconnectThread?.Join(2000); receiveThread?.Join(2000); } catch { } } /// /// Auto-reconnect loop /// private void ReconnectLoop() { while (isRunning) { if (!isConnected) { try { Connect(); } catch { // Retry after 5 seconds Thread.Sleep(5000); } } else { Thread.Sleep(1000); } } } /// /// Connect to server /// private void Connect() { try { tcpClient = new TcpClient(); tcpClient.Connect(serverIp, serverPort); stream = tcpClient.GetStream(); isConnected = true; // Notify connection status ConnectionStatusChanged?.Invoke(this, true); // Send connect message var connectMsg = new ChatMessage { Type = MessageType.Connect, NickName = nickName, EmployeeId = employeeId, HostName = hostName, UserGroup = userGroup, Timestamp = DateTime.Now }; SendMessage(connectMsg); // Start receive thread receiveThread = new Thread(ReceiveLoop) { IsBackground = true, Name = "ChatReceiveThread" }; receiveThread.Start(); } catch { Disconnect(); throw; } } /// /// Disconnect from server /// private void Disconnect() { if (!isConnected) return; isConnected = false; try { stream?.Close(); tcpClient?.Close(); } catch { } // Notify connection status ConnectionStatusChanged?.Invoke(this, false); } /// /// Message receive loop /// private void ReceiveLoop() { byte[] buffer = new byte[8192]; try { while (isRunning && isConnected && tcpClient.Connected) { int bytesRead = stream.Read(buffer, 0, buffer.Length); if (bytesRead == 0) { // Connection closed break; } string jsonData = Encoding.UTF8.GetString(buffer, 0, bytesRead); var message = JsonConvert.DeserializeObject(jsonData); if (message != null) { // Filter messages by group (dev can see all) // UserListResponse and system messages should always be received if (userGroup == "dev" || message.UserGroup == userGroup || message.Type == MessageType.Notice || message.Type == MessageType.UserListResponse || message.Type == MessageType.Pong) { MessageReceived?.Invoke(this, message); } } } } catch { // Connection error } finally { Disconnect(); } } /// /// Send message /// public bool SendMessage(ChatMessage message) { if (!isConnected || tcpClient == null || !tcpClient.Connected) return false; try { message.NickName = nickName; message.UserGroup = userGroup; message.Timestamp = DateTime.Now; string jsonData = JsonConvert.SerializeObject(message); byte[] data = Encoding.UTF8.GetBytes(jsonData); stream.Write(data, 0, data.Length); stream.Flush(); return true; } catch { Disconnect(); return false; } } /// /// Send chat message /// public bool SendChatMessage(string content) { var message = new ChatMessage { Type = MessageType.Chat, Content = content }; return SendMessage(message); } /// /// Request user list /// public bool RequestUserList() { var message = new ChatMessage { Type = MessageType.UserListRequest }; return SendMessage(message); } public void Dispose() { Stop(); } } }