Files
Groupware/Project/ChatClientService.cs
2025-11-12 13:57:13 +09:00

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();
}
}
}