milimoe 940f8397f1
为服务器统一数据访问连接 (#91)
* 重做 WebSocket 监听;为服务器统一了多种数据连接访问时的处理;统一编码为 UTF-8

* ModelManager已更名并移动到工具命名空间中

* 完成 WebSocket 消息处理系统

* 添加Socket异步接收数据流;修复TaskUtility阻塞的问题;优化心跳、房间、模组

* 添加枚举

* 删除多余字符

* 添加监听器的名称

* 修改了命名
2024-10-02 15:00:34 +08:00

114 lines
4.3 KiB
C#

using System.Net.WebSockets;
using Milimoe.FunGame.Core.Interface.HTTP;
using Milimoe.FunGame.Core.Library.Common.Architecture;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Library.Exception;
using Milimoe.FunGame.Core.Service;
namespace Milimoe.FunGame.Core.Library.Common.Network
{
public class HTTPClient : IHTTPClient
{
public System.Net.WebSockets.ClientWebSocket? Instance { get; } = null;
public SocketRuntimeType Runtime => SocketRuntimeType.Client;
public Guid Token { get; set; } = Guid.Empty;
public string ServerAddress { get; } = "";
public int ServerPort { get; } = 0;
public string ServerName { get; } = "";
public string ServerNotice { get; } = "";
public bool Connected => Instance != null && Instance.State == WebSocketState.Open;
public bool Receiving => _receiving;
private HeartBeat HeartBeat { get; }
private bool _receiving = false;
private readonly HashSet<Action<SocketObject>> _boundEvents = [];
private HTTPClient(System.Net.WebSockets.ClientWebSocket instance, string serverAddress, int serverPort, params object[] args)
{
Instance = instance;
ServerAddress = serverAddress;
ServerPort = serverPort;
HeartBeat = new(this);
HeartBeat.StartSendingHeartBeat();
Task.Factory.StartNew(async () => await StartListening(args));
}
public static async Task<HTTPClient> Connect(string serverAddress, int serverPort, bool ssl, string subUrl = "", params object[] args)
{
string ServerIP = Api.Utility.NetworkUtility.GetIPAddress(serverAddress);
Uri uri = new((ssl ? "wss://" : "ws://") + ServerIP + ":" + serverPort + "/" + subUrl.Trim('/') + "/");
System.Net.WebSockets.ClientWebSocket? socket = await HTTPManager.Connect(uri);
if (socket != null && socket.State == WebSocketState.Open)
{
HTTPClient client = new(socket, serverAddress, serverPort, args);
return client;
}
throw new CanNotConnectException();
}
public async Task Receive()
{
while (_receiving)
{
try
{
await HTTPManager.ReceiveMessage(this);
}
catch (System.Exception e)
{
Close();
Api.Utility.TXTHelper.AppendErrorLog(e.GetErrorInfo());
throw new SocketWrongInfoException();
}
}
}
public async Task<SocketResult> Send(SocketMessageType type, params object[] objs)
{
if (Instance != null)
{
return await HTTPManager.Send(Instance, new(type, Token, objs));
}
return SocketResult.NotSent;
}
public void AddSocketObjectHandler(Action<SocketObject> method)
{
if (_boundEvents.Add(method))
{
SocketManager.SocketReceive += new SocketManager.SocketReceiveHandler(method);
}
}
public void RemoveSocketObjectHandler(Action<SocketObject> method)
{
_boundEvents.Remove(method);
SocketManager.SocketReceive -= new SocketManager.SocketReceiveHandler(method);
}
public void Close()
{
_receiving = false;
HeartBeat.StopSendingHeartBeat();
Instance?.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
Instance?.Dispose();
foreach (Action<SocketObject> method in _boundEvents.ToList())
{
RemoveSocketObjectHandler(method);
}
}
private async Task StartListening(params object[] args)
{
if (Instance != null && Instance.State == WebSocketState.Open)
{
if (await HTTPManager.Send(Instance, new(SocketMessageType.Connect, Guid.Empty, args)) == SocketResult.Success && await HTTPManager.ReceiveMessage(this))
{
_receiving = true;
await Receive();
}
}
}
}
}