mirror of
https://github.com/MeowCraftMC/CrystalConnector
synced 2025-05-22 02:43:00 +00:00
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
using CrystalConnector.Utilities;
|
||||||
|
|
||||||
|
namespace CrystalConnector.Connector;
|
||||||
|
|
||||||
|
public class WebSocketConnectionManager
|
||||||
|
{
|
||||||
|
internal static Dictionary<WebSocket, WebSocketConnectionInfo> Info { get; } = new();
|
||||||
|
|
||||||
|
public static void DisconnectAll()
|
||||||
|
{
|
||||||
|
foreach (var (webSocket, info) in Info)
|
||||||
|
{
|
||||||
|
webSocket.Disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,4 +31,5 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using CrystalConnector.Utilities;
|
using CrystalConnector.Connector;
|
||||||
|
using CrystalConnector.Utilities;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -29,7 +30,7 @@ public class CrystalService : IHostedService
|
|||||||
private void OnStopping()
|
private void OnStopping()
|
||||||
{
|
{
|
||||||
Logger.LogInformation("Stopping!");
|
Logger.LogInformation("Stopping!");
|
||||||
WebSocketExtension.DisconnectAll();
|
WebSocketConnectionManager.DisconnectAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStopped()
|
private void OnStopped()
|
||||||
|
|||||||
@@ -1,42 +1,36 @@
|
|||||||
using System.Net;
|
using System.Formats.Cbor;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using CrystalConnector.Utilities;
|
using CrystalConnector.Utilities;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CrystalConnector.Handlers;
|
namespace CrystalConnector.Handlers;
|
||||||
|
|
||||||
public class WebSocketHandler : IWebSocketHandler
|
public class WebSocketHandler
|
||||||
{
|
{
|
||||||
|
private IConfiguration Config { get; }
|
||||||
|
|
||||||
private ILogger<WebSocketHandler> Logger { get; }
|
private ILogger<WebSocketHandler> Logger { get; }
|
||||||
|
|
||||||
public WebSocketHandler(ILogger<WebSocketHandler> logger)
|
public WebSocketHandler(IConfiguration config, ILogger<WebSocketHandler> logger)
|
||||||
{
|
{
|
||||||
|
Config = config;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void StartHandle(HttpContext context, WebSocket webSocket, TaskCompletionSource<WebSocketHandleResult> taskCompletionSource)
|
public void Handle(WebSocket webSocket, CborReader reader)
|
||||||
{
|
{
|
||||||
var remoteEndPoint = new IPEndPoint(context.Connection.RemoteIpAddress!, context.Connection.RemotePort); // qyl27: we believe it is a tcp connection.
|
var type = reader.ReadTextString();
|
||||||
var receiveCancellationTokenSource = new CancellationTokenSource();
|
if (type == "Authenticate")
|
||||||
webSocket.AddData(context.Connection.Id, remoteEndPoint, taskCompletionSource, receiveCancellationTokenSource);
|
|
||||||
await Handle(webSocket, receiveCancellationTokenSource.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Handle(WebSocket webSocket, CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
var buffer = new byte[1024 * 4];
|
if (!webSocket.GetConnectionInfo().Authorized)
|
||||||
|
|
||||||
WebSocketReceiveResult receiveResult;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
|
var secret = reader.ReadTextString();
|
||||||
} while (!cancellationToken.IsCancellationRequested && !receiveResult.CloseStatus.HasValue);
|
if (secret == Config.GetValue<string>("Connector:Auth:Secret"))
|
||||||
}
|
|
||||||
|
|
||||||
public void Disconnect(WebSocket webSocket)
|
|
||||||
{
|
{
|
||||||
webSocket.RemoveData();
|
webSocket.GetConnectionInfo().Authorized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using CrystalConnector;
|
using CrystalConnector;
|
||||||
using CrystalConnector.Handlers;
|
using CrystalConnector.Handlers;
|
||||||
|
using CrystalConnector.WebSockets;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -92,5 +93,6 @@ void ConfigureLogging(ILoggingBuilder logging)
|
|||||||
|
|
||||||
void ConfigureServices(IServiceCollection services)
|
void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IWebSocketHandler, WebSocketHandler>();
|
services.AddSingleton<IWebSocketManager, WebSocketManager>();
|
||||||
|
services.AddSingleton<WebSocketHandler>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using CrystalConnector.Handlers;
|
using CrystalConnector.Utilities;
|
||||||
using CrystalConnector.Utilities;
|
using CrystalConnector.WebSockets;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -12,7 +12,7 @@ public class Startup
|
|||||||
private IConfiguration Config { get; }
|
private IConfiguration Config { get; }
|
||||||
|
|
||||||
private ILogger<Startup> Logger { get; set; }
|
private ILogger<Startup> Logger { get; set; }
|
||||||
private IWebSocketHandler WebSocketHandler { get; set; }
|
private IWebSocketManager WebSocketManager { get; set; }
|
||||||
|
|
||||||
public Startup(IConfiguration config)
|
public Startup(IConfiguration config)
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,7 @@ public class Startup
|
|||||||
var provider = services.BuildServiceProvider();
|
var provider = services.BuildServiceProvider();
|
||||||
|
|
||||||
Logger = provider.GetService<ILogger<Startup>>()!;
|
Logger = provider.GetService<ILogger<Startup>>()!;
|
||||||
WebSocketHandler = provider.GetService<IWebSocketHandler>()!;
|
WebSocketManager = provider.GetService<IWebSocketManager>()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
public void Configure(IApplicationBuilder app)
|
||||||
@@ -39,8 +39,7 @@ public class Startup
|
|||||||
Logger.LogInformation("Got WebSocket connection from {Ip}:{Port}", context.Connection.RemoteIpAddress?.ToString(), context.Connection.RemotePort);
|
Logger.LogInformation("Got WebSocket connection from {Ip}:{Port}", context.Connection.RemoteIpAddress?.ToString(), context.Connection.RemotePort);
|
||||||
|
|
||||||
var taskCompletionSource = new TaskCompletionSource<WebSocketHandleResult>();
|
var taskCompletionSource = new TaskCompletionSource<WebSocketHandleResult>();
|
||||||
WebSocketHandler.StartHandle(context, websocket, taskCompletionSource);
|
await WebSocketManager.StartHandle(context, websocket, taskCompletionSource);
|
||||||
await taskCompletionSource.Task;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-3
@@ -3,7 +3,7 @@ using CrystalConnector.Connector;
|
|||||||
|
|
||||||
namespace CrystalConnector.Utilities;
|
namespace CrystalConnector.Utilities;
|
||||||
|
|
||||||
public class WebSocketData
|
public class WebSocketConnectionInfo
|
||||||
{
|
{
|
||||||
public required string Id { get; set; }
|
public required string Id { get; set; }
|
||||||
|
|
||||||
@@ -11,8 +11,6 @@ public class WebSocketData
|
|||||||
|
|
||||||
public required TaskCompletionSource<WebSocketHandleResult> CompletionSource { get; set; }
|
public required TaskCompletionSource<WebSocketHandleResult> CompletionSource { get; set; }
|
||||||
|
|
||||||
public required CancellationTokenSource ReceiveCancellationTokenSource { get; set; }
|
|
||||||
|
|
||||||
public bool Authorized { get; set; } = false;
|
public bool Authorized { get; set; } = false;
|
||||||
|
|
||||||
public List<MessageChannel> RegisteredChannels { get; } = new();
|
public List<MessageChannel> RegisteredChannels { get; } = new();
|
||||||
@@ -1,44 +1,34 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
|
using CrystalConnector.Connector;
|
||||||
|
|
||||||
namespace CrystalConnector.Utilities;
|
namespace CrystalConnector.Utilities;
|
||||||
|
|
||||||
public static class WebSocketExtension
|
public static class WebSocketExtension
|
||||||
{
|
{
|
||||||
private static Dictionary<WebSocket, WebSocketData> Data { get; } = new();
|
public static void AddConnectionInfo(this WebSocket webSocket, string id, IPEndPoint ip,
|
||||||
|
TaskCompletionSource<WebSocketHandleResult> taskCompletionSource)
|
||||||
public static void AddData(this WebSocket webSocket, string id, IPEndPoint ip,
|
|
||||||
TaskCompletionSource<WebSocketHandleResult> taskCompletionSource,
|
|
||||||
CancellationTokenSource receiveCancellationTokenSource)
|
|
||||||
{
|
{
|
||||||
Data.Add(webSocket, new WebSocketData
|
WebSocketConnectionManager.Info.Add(webSocket, new WebSocketConnectionInfo
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
||||||
IpEndPoint = ip,
|
IpEndPoint = ip,
|
||||||
CompletionSource = taskCompletionSource,
|
CompletionSource = taskCompletionSource,
|
||||||
ReceiveCancellationTokenSource = receiveCancellationTokenSource
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WebSocketData GetData(this WebSocket webSocket)
|
public static WebSocketConnectionInfo GetConnectionInfo(this WebSocket webSocket)
|
||||||
{
|
{
|
||||||
return Data[webSocket];
|
return WebSocketConnectionManager.Info[webSocket];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveData(this WebSocket webSocket)
|
public static void Disconnect(this WebSocket webSocket)
|
||||||
{
|
{
|
||||||
var data = GetData(webSocket);
|
var data = GetConnectionInfo(webSocket);
|
||||||
data.ReceiveCancellationTokenSource.Cancel();
|
|
||||||
data.CompletionSource.SetResult(WebSocketHandleResult.Successful);
|
data.CompletionSource.SetResult(WebSocketHandleResult.Successful);
|
||||||
|
|
||||||
Data.Remove(webSocket);
|
webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||||
}
|
|
||||||
|
|
||||||
public static void DisconnectAll()
|
WebSocketConnectionManager.Info.Remove(webSocket);
|
||||||
{
|
|
||||||
foreach (var (socket, _) in Data)
|
|
||||||
{
|
|
||||||
RemoveData(socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -2,11 +2,11 @@
|
|||||||
using CrystalConnector.Utilities;
|
using CrystalConnector.Utilities;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace CrystalConnector.Handlers;
|
namespace CrystalConnector.WebSockets;
|
||||||
|
|
||||||
public interface IWebSocketHandler
|
public interface IWebSocketManager
|
||||||
{
|
{
|
||||||
public void StartHandle(HttpContext context, WebSocket socket, TaskCompletionSource<WebSocketHandleResult> taskCompletionSource);
|
public Task StartHandle(HttpContext context, WebSocket socket, TaskCompletionSource<WebSocketHandleResult> taskCompletionSource);
|
||||||
|
|
||||||
public void Disconnect(WebSocket socket);
|
public void Disconnect(WebSocket socket);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using System.Formats.Cbor;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using CrystalConnector.Handlers;
|
||||||
|
using CrystalConnector.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace CrystalConnector.WebSockets;
|
||||||
|
|
||||||
|
public class WebSocketManager : IWebSocketManager
|
||||||
|
{
|
||||||
|
private ILogger<WebSocketManager> Logger { get; }
|
||||||
|
|
||||||
|
private WebSocketHandler Handler { get; }
|
||||||
|
|
||||||
|
public WebSocketManager(ILogger<WebSocketManager> logger, WebSocketHandler handler)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
Handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartHandle(HttpContext context, WebSocket webSocket, TaskCompletionSource<WebSocketHandleResult> taskCompletionSource)
|
||||||
|
{
|
||||||
|
var remoteEndPoint = new IPEndPoint(context.Connection.RemoteIpAddress!, context.Connection.RemotePort); // qyl27: we believe it is a tcp connection.
|
||||||
|
webSocket.AddConnectionInfo(context.Connection.Id, remoteEndPoint, taskCompletionSource);
|
||||||
|
await Receive(webSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Receive(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
var buffer = new byte[1024 * 4];
|
||||||
|
var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
|
||||||
|
while (!receiveResult.CloseStatus.HasValue)
|
||||||
|
{
|
||||||
|
var reader = new CborReader(new ReadOnlyMemory<byte>(buffer, 0, receiveResult.Count));
|
||||||
|
|
||||||
|
Handler.Handle(webSocket, reader);
|
||||||
|
|
||||||
|
receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disconnect(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
webSocket.Disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user