using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Text;
using Microsoft.Extensions.Logging;
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(nameof(socket));
}
if (string.IsNullOrEmpty(remoteEndPoint))
{
throw new ArgumentNullException(nameof(remoteEndPoint));
}
if (jsonSerializer == null)
{
throw new ArgumentNullException(nameof(jsonSerializer));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(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)
{
Closed?.Invoke(this, EventArgs.Empty);
}
///
/// 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 memory block.
/// The length of the memory block.
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.LogDebug("Received web socket message that is not a json structure: {message}", message);
return;
}
if (OnReceive == null)
{
return;
}
try
{
var stub = (WebSocketMessage