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

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

* 完成 WebSocket 消息处理系统

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

* 添加枚举

* 删除多余字符

* 添加监听器的名称

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

250 lines
9.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net;
using System.Net.WebSockets;
using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Library.Common.Network;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Library.Exception;
namespace Milimoe.FunGame.Core.Service
{
internal class HTTPManager
{
/// <summary>
/// 实际的 <see cref="System.Net.HttpListener"/> 监听实例 [ 单例 ]
/// </summary>
internal static HttpListener? HttpListener => _HttpListener;
private static HttpListener? _HttpListener = null;
/// <summary>
/// 开始监听
/// 当 <paramref name="address"/> = "*" 时,需要管理员权限
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="subUrl"></param>
/// <param name="ssl"></param>
/// <returns></returns>
internal static HttpListener StartListening(string address = "*", int port = 22223, string subUrl = "ws", bool ssl = false)
{
_HttpListener = new();
_HttpListener.Prefixes.Add((ssl ? "https://" : "http://") + address + ":" + port + "/" + subUrl.Trim('/') + "/");
_HttpListener.Start();
return _HttpListener;
}
/// <summary>
/// 客户端连接远程 WebSocket 服务器
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
internal static async Task<System.Net.WebSockets.ClientWebSocket?> Connect(Uri uri)
{
System.Net.WebSockets.ClientWebSocket socket = new();
await socket.ConnectAsync(uri, CancellationToken.None);
if (socket.State == WebSocketState.Open)
{
return socket;
}
return null;
}
/// <summary>
/// 客户端向服务器发送消息
/// </summary>
/// <param name="socket"></param>
/// <param name="obj"></param>
/// <returns></returns>
internal static async Task<SocketResult> Send(System.Net.WebSockets.ClientWebSocket socket, SocketObject obj)
{
if (socket != null)
{
try
{
await socket.SendAsync(new ArraySegment<byte>(General.DefaultEncoding.GetBytes(JsonManager.GetString(obj))), WebSocketMessageType.Text, true, CancellationToken.None);
return SocketResult.Success;
}
catch (Exception e)
{
TXTHelper.AppendErrorLog(e.GetErrorInfo());
return SocketResult.Fail;
}
}
return SocketResult.NotSent;
}
/// <summary>
/// 服务器向客户端发送消息
/// </summary>
/// <param name="socket"></param>
/// <param name="obj"></param>
/// <returns></returns>
internal static async Task<SocketResult> Send(WebSocket socket, SocketObject obj)
{
if (socket != null)
{
try
{
await socket.SendAsync(new ArraySegment<byte>(General.DefaultEncoding.GetBytes(JsonManager.GetString(obj))), WebSocketMessageType.Text, true, CancellationToken.None);
return SocketResult.Success;
}
catch (Exception e)
{
TXTHelper.AppendErrorLog(e.GetErrorInfo());
return SocketResult.Fail;
}
}
return SocketResult.NotSent;
}
/// <summary>
/// 服务器接受一个 HTTP 的 WebSocket 升级请求
/// </summary>
/// <returns>[0]客户端IP地址[1]客户端的WebSocket实例</returns>
internal static async Task<object[]> Accept()
{
if (HttpListener is null) return [];
try
{
HttpListenerContext context = await HttpListener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
HttpListenerWebSocketContext socketContext = await context.AcceptWebSocketAsync(null);
WebSocket socket = socketContext.WebSocket;
string ip = context.Request.RemoteEndPoint.ToString();
return [ip, socket];
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
catch
{
HttpListener?.Close();
}
return [];
}
/// <summary>
/// 服务器接收客户端消息
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
internal static async Task<SocketObject[]> Receive(WebSocket socket)
{
try
{
List<SocketObject> objs = [];
if (socket != null)
{
byte[] buffer = new byte[General.SocketByteSize];
WebSocketReceiveResult result;
StringBuilder builder = new();
do
{
result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
builder.Append(General.DefaultEncoding.GetString(buffer, 0, result.Count).Replace("\0", "").Trim());
}
while (!result.EndOfMessage);
string msg = builder.ToString();
if (JsonManager.IsCompleteJson<SocketObject>(msg))
{
foreach (SocketObject obj in JsonManager.GetObjects<SocketObject>(msg))
{
objs.Add(obj);
}
}
}
return [.. objs];
}
catch (Exception e)
{
TXTHelper.AppendErrorLog(e.GetErrorInfo());
return [];
}
}
/// <summary>
/// 客户端接收服务器消息
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
internal static async Task<bool> ReceiveMessage(HTTPClient client)
{
if (client.Instance is null) return false;
byte[] buffer = new byte[General.SocketByteSize];
WebSocketReceiveResult result = await client.Instance.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string msg = General.DefaultEncoding.GetString(buffer).Replace("\0", "").Trim();
SocketObject[] objs = await GetSocketObjects(client.Instance, result, msg);
foreach (SocketObject obj in objs)
{
SocketManager.OnSocketReceive(obj);
if (obj.SocketType == SocketMessageType.Connect)
{
return true;
}
else if (obj.SocketType == SocketMessageType.Disconnect)
{
await client.Instance.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, CancellationToken.None);
return true;
}
}
return true;
}
/// <summary>
/// 将收到的消息反序列为 <see cref="SocketObject"/>
/// </summary>
/// <param name="socket"></param>
/// <param name="result"></param>
/// <param name="msg"></param>
/// <returns></returns>
private static async Task<SocketObject[]> GetSocketObjects(WebSocket socket, WebSocketReceiveResult result, string msg)
{
List<SocketObject> objs = [];
if (JsonManager.IsCompleteJson<SocketObject>(msg))
{
foreach (SocketObject obj in JsonManager.GetObjects<SocketObject>(msg))
{
objs.Add(obj);
}
return [.. objs];
}
else
{
await Task.Delay(20);
while (true)
{
if (!result.CloseStatus.HasValue)
{
byte[] buffer = new byte[General.SocketByteSize];
result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
msg += General.DefaultEncoding.GetString(buffer).Replace("\0", "").Trim();
if (JsonManager.IsCompleteJson<SocketObject>(msg))
{
break;
}
await Task.Delay(20);
}
else break;
}
foreach (SocketObject obj in JsonManager.GetObjects<SocketObject>(msg))
{
objs.Add(obj);
}
}
return [.. objs];
}
}
}