From 48facb797ed912e4ea6b04b17d1ff190ac2daac4 Mon Sep 17 00:00:00 2001 From: stefan Date: Wed, 12 Sep 2018 19:26:21 +0200 Subject: Update to 3.5.2 and .net core 2.1 --- .../HttpServer/WebSocketConnection.cs | 290 +++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 Emby.Server.Implementations/HttpServer/WebSocketConnection.cs (limited to 'Emby.Server.Implementations/HttpServer/WebSocketConnection.cs') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs new file mode 100644 index 000000000..d449e4424 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -0,0 +1,290 @@ +using System.Text; +using MediaBrowser.Common.Events; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Serialization; +using System; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Services; +using MediaBrowser.Model.Text; +using System.Net.WebSockets; +using Emby.Server.Implementations.Net; + +namespace Emby.Server.Implementations.HttpServer +{ + /// + /// Class WebSocketConnection + /// + public class WebSocketConnection : IWebSocketConnection + { + public event EventHandler Closed; + + /// + /// The _socket + /// + private readonly IWebSocket _socket; + + /// + /// The _remote end point + /// + public string RemoteEndPoint { get; private set; } + + /// + /// The logger + /// + private readonly ILogger _logger; + + /// + /// The _json serializer + /// + private readonly IJsonSerializer _jsonSerializer; + + /// + /// Gets or sets the receive action. + /// + /// The receive action. + public Func OnReceive { get; set; } + + /// + /// Gets the last activity date. + /// + /// The last activity date. + public DateTime LastActivityDate { get; private set; } + + /// + /// Gets the id. + /// + /// The id. + public Guid Id { get; private set; } + + /// + /// Gets or sets the URL. + /// + /// The URL. + public string Url { get; set; } + /// + /// Gets or sets the query string. + /// + /// The query string. + public QueryParamCollection QueryString { get; set; } + private readonly ITextEncoding _textEncoding; + + /// + /// Initializes a new instance of the class. + /// + /// The socket. + /// The remote end point. + /// The json serializer. + /// The logger. + /// socket + public WebSocketConnection(IWebSocket socket, string remoteEndPoint, IJsonSerializer jsonSerializer, ILogger logger, ITextEncoding textEncoding) + { + if (socket == null) + { + throw new ArgumentNullException("socket"); + } + if (string.IsNullOrEmpty(remoteEndPoint)) + { + throw new ArgumentNullException("remoteEndPoint"); + } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + + Id = Guid.NewGuid(); + _jsonSerializer = jsonSerializer; + _socket = socket; + _socket.OnReceiveBytes = OnReceiveInternal; + + var memorySocket = socket as IMemoryWebSocket; + if (memorySocket != null) + { + memorySocket.OnReceiveMemoryBytes = OnReceiveInternal; + } + + RemoteEndPoint = remoteEndPoint; + _logger = logger; + _textEncoding = textEncoding; + + socket.Closed += socket_Closed; + } + + void socket_Closed(object sender, EventArgs e) + { + EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); + } + + /// + /// Called when [receive]. + /// + /// The bytes. + private void OnReceiveInternal(byte[] bytes) + { + LastActivityDate = DateTime.UtcNow; + + if (OnReceive == null) + { + return; + } + + var charset = _textEncoding.GetDetectedEncodingName(bytes, bytes.Length, null, false); + + if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase)) + { + OnReceiveInternal(Encoding.UTF8.GetString(bytes, 0, bytes.Length)); + } + else + { + OnReceiveInternal(_textEncoding.GetASCIIEncoding().GetString(bytes, 0, bytes.Length)); + } + } + + /// + /// Called when [receive]. + /// + /// The bytes. + private void OnReceiveInternal(Memory memory, int length) + { + LastActivityDate = DateTime.UtcNow; + + if (OnReceive == null) + { + return; + } + + var bytes = memory.Slice(0, length).ToArray(); + + var charset = _textEncoding.GetDetectedEncodingName(bytes, bytes.Length, null, false); + + if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase)) + { + OnReceiveInternal(Encoding.UTF8.GetString(bytes, 0, bytes.Length)); + } + else + { + OnReceiveInternal(_textEncoding.GetASCIIEncoding().GetString(bytes, 0, bytes.Length)); + } + } + + private void OnReceiveInternal(string message) + { + LastActivityDate = DateTime.UtcNow; + + if (!message.StartsWith("{", StringComparison.OrdinalIgnoreCase)) + { + // This info is useful sometimes but also clogs up the log + //_logger.Error("Received web socket message that is not a json structure: " + message); + return; + } + + if (OnReceive == null) + { + return; + } + + try + { + var stub = (WebSocketMessage)_jsonSerializer.DeserializeFromString(message, typeof(WebSocketMessage)); + + var info = new WebSocketMessageInfo + { + MessageType = stub.MessageType, + Data = stub.Data == null ? null : stub.Data.ToString(), + Connection = this + }; + + OnReceive(info); + } + catch (Exception ex) + { + _logger.ErrorException("Error processing web socket message", ex); + } + } + + /// + /// Sends a message asynchronously. + /// + /// + /// The message. + /// The cancellation token. + /// Task. + /// message + public Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + var json = _jsonSerializer.SerializeToString(message); + + return SendAsync(json, cancellationToken); + } + + /// + /// Sends a message asynchronously. + /// + /// The buffer. + /// The cancellation token. + /// Task. + public Task SendAsync(byte[] buffer, CancellationToken cancellationToken) + { + if (buffer == null) + { + throw new ArgumentNullException("buffer"); + } + + cancellationToken.ThrowIfCancellationRequested(); + + return _socket.SendAsync(buffer, true, cancellationToken); + } + + public Task SendAsync(string text, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(text)) + { + throw new ArgumentNullException("text"); + } + + cancellationToken.ThrowIfCancellationRequested(); + + return _socket.SendAsync(text, true, cancellationToken); + } + + /// + /// Gets the state. + /// + /// The state. + public WebSocketState State + { + get { return _socket.State; } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + _socket.Dispose(); + } + } + } +} -- cgit v1.2.3