284 lines
7.8 KiB
C#
284 lines
7.8 KiB
C#
using System;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace Project
|
|
{
|
|
/// <summary>
|
|
/// Background chat client service with auto-reconnect
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>Connection status changed event</summary>
|
|
public event EventHandler<bool> ConnectionStatusChanged;
|
|
|
|
/// <summary>Message received event</summary>
|
|
public event EventHandler<ChatMessage> MessageReceived;
|
|
|
|
/// <summary>Connection status</summary>
|
|
public bool IsConnected => isConnected;
|
|
|
|
/// <summary>User nickname</summary>
|
|
public string NickName => nickName;
|
|
|
|
/// <summary>User employee ID</summary>
|
|
public string EmployeeId => employeeId;
|
|
|
|
/// <summary>User group</summary>
|
|
public string UserGroup => userGroup;
|
|
|
|
public ChatClientService(string serverIp, int serverPort)
|
|
{
|
|
this.serverIp = serverIp;
|
|
this.serverPort = serverPort;
|
|
this.hostName = System.Net.Dns.GetHostName();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start background service
|
|
/// </summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop background service
|
|
/// </summary>
|
|
public void Stop()
|
|
{
|
|
isRunning = false;
|
|
Disconnect();
|
|
|
|
try
|
|
{
|
|
reconnectThread?.Join(2000);
|
|
receiveThread?.Join(2000);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Auto-reconnect loop
|
|
/// </summary>
|
|
private void ReconnectLoop()
|
|
{
|
|
while (isRunning)
|
|
{
|
|
if (!isConnected)
|
|
{
|
|
try
|
|
{
|
|
Connect();
|
|
}
|
|
catch
|
|
{
|
|
// Retry after 5 seconds
|
|
Thread.Sleep(5000);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Thread.Sleep(1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Connect to server
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disconnect from server
|
|
/// </summary>
|
|
private void Disconnect()
|
|
{
|
|
if (!isConnected)
|
|
return;
|
|
|
|
isConnected = false;
|
|
|
|
try
|
|
{
|
|
stream?.Close();
|
|
tcpClient?.Close();
|
|
}
|
|
catch { }
|
|
|
|
// Notify connection status
|
|
ConnectionStatusChanged?.Invoke(this, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Message receive loop
|
|
/// </summary>
|
|
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<ChatMessage>(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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send message
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send chat message
|
|
/// </summary>
|
|
public bool SendChatMessage(string content)
|
|
{
|
|
var message = new ChatMessage
|
|
{
|
|
Type = MessageType.Chat,
|
|
Content = content
|
|
};
|
|
return SendMessage(message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Request user list
|
|
/// </summary>
|
|
public bool RequestUserList()
|
|
{
|
|
var message = new ChatMessage
|
|
{
|
|
Type = MessageType.UserListRequest
|
|
};
|
|
return SendMessage(message);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Stop();
|
|
}
|
|
}
|
|
}
|