FunGame-Core/Service/HTTPManager.cs
milimoe 2de1e57e0c
针对服务器端的新功能支持与改进 (#90)
* 添加SQLite模式

* 将Hashtable转为Dictionary<string, object>,因为它具有性能优势

* 添加GamingRequest用于区分Gaming

* 模组中AfterLoad方法现已移动至加载器完全加载完毕后触发

* 删除了服务器对GameModule的加载,现在只会加载GameModuleServer
2024-09-25 09:24:53 +08:00

234 lines
9.0 KiB
C#

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
{
internal static HttpListener? ServerSocket => _ServerSocket;
private static HttpListener? _ServerSocket = null;
internal static HttpListener StartListening(int port = 22227, bool ssl = false)
{
HttpListener listener = new();
listener.Prefixes.Add((ssl ? "https://" : "http://") + "localhost:" + port + "/ws");
listener.Start();
return listener;
}
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;
}
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;
}
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;
}
internal static async Task Receiving(HTTPListener listener)
{
if (ServerSocket != null)
{
try
{
while (true)
{
HttpListenerContext context = await ServerSocket.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
TaskUtility.NewTask(async () => await AddClientWebSocket(listener, context));
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
}
catch
{
_ServerSocket = null;
}
}
}
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 = Encoding.UTF8.GetString(buffer).Replace("\0", "").Trim();
SocketObject[] objs = await GetSocketObjects(client.Instance, result, msg);
foreach (SocketObject obj in objs)
{
SocketObject sendobject = client.SocketObject_Handler(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;
}
await Send(client.Instance, sendobject);
}
return true;
}
private static async Task AddClientWebSocket(HTTPListener listener, HttpListenerContext context)
{
HttpListenerWebSocketContext socketContext = await context.AcceptWebSocketAsync(null);
WebSocket socket = socketContext.WebSocket;
byte[] buffer = new byte[General.SocketByteSize];
WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string msg = Encoding.UTF8.GetString(buffer).Replace("\0", "").Trim();
SocketObject sendobject = new(SocketMessageType.Unknown, Guid.Empty);
SocketObject[] objs = await GetSocketObjects(socket, result, msg);
bool isConnect = false;
foreach (SocketObject obj in objs)
{
if (obj.SocketType == SocketMessageType.Connect)
{
isConnect = listener.CheckClientConnection(obj);
}
else if (listener.ClientSockets.ContainsKey(obj.Token))
{
sendobject = listener.SocketObject_Handler(obj);
isConnect = true;
}
}
if (isConnect)
{
Guid token = Guid.NewGuid();
listener.ClientSockets.TryAdd(token, socket);
await Send(socket, sendobject);
while (socket.State == WebSocketState.Open)
{
try
{
buffer = new byte[General.SocketByteSize];
result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.CloseStatus.HasValue)
{
await socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
return;
}
msg = Encoding.UTF8.GetString(buffer).Replace("\0", "").Trim();
objs = await GetSocketObjects(socket, result, msg);
foreach (SocketObject obj in objs)
{
sendobject = listener.SocketObject_Handler(obj);
if (obj.SocketType == SocketMessageType.Disconnect)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disconnect received", CancellationToken.None);
return;
}
await Send(socket, sendobject);
}
}
catch (Exception e)
{
// 处理其他异常
TXTHelper.AppendErrorLog(e.GetErrorInfo());
await socket.CloseAsync(WebSocketCloseStatus.InternalServerError, "Server Error", CancellationToken.None);
return;
}
}
}
}
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];
}
}
}