XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using XFEExtension.NetCore.CyberComm;
using XFEExtension.NetCore.ServerInteractive.Implements.CoreService;

namespace XFEToolBox.Server.Realtime;

/// <summary>
/// Bridges CyberComm's raw WebSocket lifecycle into the authenticated chat broker.
/// Register this service with <c>AddOriginalService&lt;ChatRealtimeWebSocketService&gt;()</c>.
/// </summary>
public sealed class ChatRealtimeWebSocketService : ServerCoreOriginalServiceBase
{
    public const string RealtimePath = "/api/chat/realtime";

    public ChatRealtimeBroker? ChatRealtimeBroker { get; set; }

    public override void ServerStarted(object? sender, EventArgs e)
    {
        // Broker maintenance starts from its constructor; this lifecycle hook is
        // intentionally present because original services require it.
    }

    public override void ClientConnected(object? sender, CyberCommServerEventArgs e)
    {
        var requestUrl = e.RequestUrl;
        if (requestUrl is null || !IsRealtimeRoute(requestUrl))
            return;

        if (ChatRealtimeBroker is null ||
            !ChatRealtimeBroker.TryRegister(e.CurrentWebSocket, requestUrl, out _))
            TryClose(e);
    }

    public override void MessageReceived(object? sender, CyberCommServerEventArgs e)
    {
        if (!IsRealtimeRoute(e.RequestUrl))
            return;
        if (ChatRealtimeBroker is null)
        {
            TryClose(e);
            return;
        }

        if (e.MessageType == BackMessageType.Text)
            ChatRealtimeBroker.ReceiveFrame(e.CurrentWebSocket, e.TextMessage ?? string.Empty, e.EndOfMessage);
        else
            ChatRealtimeBroker.RejectBinaryFrame(e.CurrentWebSocket);
    }

    public override void ConnectionClosed(object? sender, CyberCommServerEventArgs e)
    {
        if (IsRealtimeRoute(e.RequestUrl))
            ChatRealtimeBroker?.ConnectionClosed(e.CurrentWebSocket);
    }

    public static bool IsRealtimeRoute(Uri? requestUrl) =>
        requestUrl is not null && string.Equals(
            requestUrl.AbsolutePath.TrimEnd('/'),
            RealtimePath,
            StringComparison.OrdinalIgnoreCase);

    private static void TryClose(CyberCommServerEventArgs e)
    {
        try { e.Close(); }
        catch { e.CurrentWebSocket.Abort(); }
    }
}