diff options
| author | Joshua M. Boniface <joshua@boniface.me> | 2021-08-18 02:46:59 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-18 02:46:59 -0400 |
| commit | 72d3f7020ad80ce1a53eeae8c5d57abeb22a4679 (patch) | |
| tree | dd43e663838cdc7d99a4af565523df58ae23c856 /MediaBrowser.Controller/Net | |
| parent | 7aef0fce444e6d8e06386553ec7ea1401a01bbb1 (diff) | |
| parent | e5cbafdb6b47377052e0d638908ef96e30a997d6 (diff) | |
Merge branch 'master' into patch-2
Diffstat (limited to 'MediaBrowser.Controller/Net')
| -rw-r--r-- | MediaBrowser.Controller/Net/AuthenticatedAttribute.cs | 76 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/AuthorizationInfo.cs | 23 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs | 61 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IAuthService.cs | 19 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IAuthorizationContext.cs | 10 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IHasResultFactory.cs | 17 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IHttpResultFactory.cs | 82 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IHttpServer.cs | 50 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/ISessionContext.cs | 8 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IWebSocketConnection.cs | 8 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IWebSocketListener.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/IWebSocketManager.cs | 18 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/SecurityException.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/StaticResultOptions.cs | 44 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/WebSocketListenerState.cs | 17 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/WebSocketMessageInfo.cs | 2 |
16 files changed, 110 insertions, 336 deletions
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs deleted file mode 100644 index 1366fd42e..000000000 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ /dev/null @@ -1,76 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; - -namespace MediaBrowser.Controller.Net -{ - public class AuthenticatedAttribute : Attribute, IHasRequestFilter, IAuthenticationAttributes - { - public static IAuthService AuthService { get; set; } - - /// <summary> - /// Gets or sets the roles. - /// </summary> - /// <value>The roles.</value> - public string Roles { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [escape parental control]. - /// </summary> - /// <value><c>true</c> if [escape parental control]; otherwise, <c>false</c>.</value> - public bool EscapeParentalControl { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [allow before startup wizard]. - /// </summary> - /// <value><c>true</c> if [allow before startup wizard]; otherwise, <c>false</c>.</value> - public bool AllowBeforeStartupWizard { get; set; } - - public bool AllowLocal { get; set; } - - /// <summary> - /// The request filter is executed before the service. - /// </summary> - /// <param name="request">The http request wrapper.</param> - /// <param name="response">The http response wrapper.</param> - /// <param name="requestDto">The request DTO.</param> - public void RequestFilter(IRequest request, HttpResponse response, object requestDto) - { - AuthService.Authenticate(request, this); - } - - /// <summary> - /// Order in which Request Filters are executed. - /// <0 Executed before global request filters - /// >0 Executed after global request filters - /// </summary> - /// <value>The priority.</value> - public int Priority => 0; - - public string[] GetRoles() - { - return (Roles ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - } - - public bool IgnoreLegacyAuth { get; set; } - - public bool AllowLocalOnly { get; set; } - } - - public interface IAuthenticationAttributes - { - bool EscapeParentalControl { get; } - - bool AllowBeforeStartupWizard { get; } - - bool AllowLocal { get; } - - bool AllowLocalOnly { get; } - - string[] GetRoles(); - - bool IgnoreLegacyAuth { get; } - } -} diff --git a/MediaBrowser.Controller/Net/AuthorizationInfo.cs b/MediaBrowser.Controller/Net/AuthorizationInfo.cs index 735c46ef8..2452b25ab 100644 --- a/MediaBrowser.Controller/Net/AuthorizationInfo.cs +++ b/MediaBrowser.Controller/Net/AuthorizationInfo.cs @@ -1,10 +1,13 @@ -#pragma warning disable CS1591 +#nullable disable using System; using Jellyfin.Data.Entities; namespace MediaBrowser.Controller.Net { + /// <summary> + /// The request authorization info. + /// </summary> public class AuthorizationInfo { /// <summary> @@ -43,6 +46,24 @@ namespace MediaBrowser.Controller.Net /// <value>The token.</value> public string Token { get; set; } + /// <summary> + /// Gets or sets a value indicating whether the authorization is from an api key. + /// </summary> + public bool IsApiKey { get; set; } + + /// <summary> + /// Gets or sets the user making the request. + /// </summary> public User User { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether the token is authenticated. + /// </summary> + public bool IsAuthenticated { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether the request has a token. + /// </summary> + public bool HasToken { get; set; } } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 916dea58b..0813a8e7d 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -1,4 +1,6 @@ -#pragma warning disable CS1591 +#nullable disable + +#pragma warning disable CS1591, SA1306, SA1401 using System; using System.Collections.Generic; @@ -8,6 +10,7 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; +using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Net @@ -28,18 +31,6 @@ namespace MediaBrowser.Controller.Net new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>(); /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - protected abstract string Name { get; } - - /// <summary> - /// Gets the data to send. - /// </summary> - /// <returns>Task{`1}.</returns> - protected abstract Task<TReturnDataType> GetDataToSend(); - - /// <summary> /// The logger. /// </summary> protected ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger; @@ -55,6 +46,30 @@ namespace MediaBrowser.Controller.Net } /// <summary> + /// Gets the type used for the messages sent to the client. + /// </summary> + /// <value>The type.</value> + protected abstract SessionMessageType Type { get; } + + /// <summary> + /// Gets the message type received from the client to start sending messages. + /// </summary> + /// <value>The type.</value> + protected abstract SessionMessageType StartType { get; } + + /// <summary> + /// Gets the message type received from the client to stop sending messages. + /// </summary> + /// <value>The type.</value> + protected abstract SessionMessageType StopType { get; } + + /// <summary> + /// Gets the data to send. + /// </summary> + /// <returns>Task{`1}.</returns> + protected abstract Task<TReturnDataType> GetDataToSend(); + + /// <summary> /// Processes the message. /// </summary> /// <param name="message">The message.</param> @@ -66,12 +81,12 @@ namespace MediaBrowser.Controller.Net throw new ArgumentNullException(nameof(message)); } - if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase)) + if (message.MessageType == StartType) { Start(message); } - if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase)) + if (message.MessageType == StopType) { Stop(message); } @@ -79,6 +94,9 @@ namespace MediaBrowser.Controller.Net return Task.CompletedTask; } + /// <inheritdoc /> + public Task ProcessWebSocketConnectedAsync(IWebSocketConnection connection) => Task.CompletedTask; + /// <summary> /// Starts sending messages over a web socket. /// </summary> @@ -159,7 +177,7 @@ namespace MediaBrowser.Controller.Net new WebSocketMessage<TReturnDataType> { MessageId = Guid.NewGuid(), - MessageType = Name, + MessageType = Type, Data = data }, cancellationToken).ConfigureAwait(false); @@ -176,7 +194,7 @@ namespace MediaBrowser.Controller.Net } catch (Exception ex) { - Logger.LogError(ex, "Error sending web socket message {Name}", Name); + Logger.LogError(ex, "Error sending web socket message {Name}", Type); DisposeConnection(tuple); } } @@ -252,13 +270,4 @@ namespace MediaBrowser.Controller.Net GC.SuppressFinalize(this); } } - - public class WebSocketListenerState - { - public DateTime DateLastSendUtc { get; set; } - - public long InitialDelayMs { get; set; } - - public long IntervalMs { get; set; } - } } diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index 2055a656a..d15c6d318 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -1,7 +1,3 @@ -#nullable enable - -using Jellyfin.Data.Entities; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -12,21 +8,6 @@ namespace MediaBrowser.Controller.Net public interface IAuthService { /// <summary> - /// Authenticate and authorize request. - /// </summary> - /// <param name="request">Request.</param> - /// <param name="authAttribtutes">Authorization attributes.</param> - void Authenticate(IRequest request, IAuthenticationAttributes authAttribtutes); - - /// <summary> - /// Authenticate and authorize request. - /// </summary> - /// <param name="request">Request.</param> - /// <param name="authAttribtutes">Authorization attributes.</param> - /// <returns>Authenticated user.</returns> - User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtutes); - - /// <summary> /// Authenticate request. /// </summary> /// <param name="request">The request.</param> diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs index 37a7425b9..0d310548d 100644 --- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs +++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs @@ -1,4 +1,3 @@ -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -13,14 +12,7 @@ namespace MediaBrowser.Controller.Net /// </summary> /// <param name="requestContext">The request context.</param> /// <returns>AuthorizationInfo.</returns> - AuthorizationInfo GetAuthorizationInfo(object requestContext); - - /// <summary> - /// Gets the authorization information. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <returns>AuthorizationInfo.</returns> - AuthorizationInfo GetAuthorizationInfo(IRequest requestContext); + AuthorizationInfo GetAuthorizationInfo(HttpContext requestContext); /// <summary> /// Gets the authorization information. diff --git a/MediaBrowser.Controller/Net/IHasResultFactory.cs b/MediaBrowser.Controller/Net/IHasResultFactory.cs deleted file mode 100644 index b8cf8cd78..000000000 --- a/MediaBrowser.Controller/Net/IHasResultFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Interface IHasResultFactory - /// Services that require a ResultFactory should implement this - /// </summary> - public interface IHasResultFactory : IRequiresRequest - { - /// <summary> - /// Gets or sets the result factory. - /// </summary> - /// <value>The result factory.</value> - IHttpResultFactory ResultFactory { get; set; } - } -} diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs deleted file mode 100644 index 8293a8714..000000000 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ /dev/null @@ -1,82 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Interface IHttpResultFactory. - /// </summary> - public interface IHttpResultFactory - { - /// <summary> - /// Gets the result. - /// </summary> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - object GetResult(string content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetResult(IRequest requestContext, byte[] content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetResult(IRequest requestContext, Stream content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetResult(IRequest requestContext, string content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetRedirectResult(string url); - - object GetResult<T>(IRequest requestContext, T result, IDictionary<string, string> responseHeaders = null) - where T : class; - - /// <summary> - /// Gets the static result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticResult(IRequest requestContext, - Guid cacheKey, - DateTime? lastDateModified, - TimeSpan? cacheDuration, - string contentType, Func<Task<Stream>> factoryFn, - IDictionary<string, string> responseHeaders = null, - bool isHeadRequest = false); - - /// <summary> - /// Gets the static result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="options">The options.</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options); - - /// <summary> - /// Gets the static file result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="path">The path.</param> - /// <param name="fileShare">The file share.</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read); - - /// <summary> - /// Gets the static file result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="options">The options.</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticFileResult(IRequest requestContext, - StaticFileResultOptions options); - } -} diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs deleted file mode 100644 index b04ebda8c..000000000 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Jellyfin.Data.Events; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Interface IHttpServer. - /// </summary> - public interface IHttpServer - { - /// <summary> - /// Gets the URL prefix. - /// </summary> - /// <value>The URL prefix.</value> - string[] UrlPrefixes { get; } - - /// <summary> - /// Occurs when [web socket connected]. - /// </summary> - event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; - - /// <summary> - /// Inits this instance. - /// </summary> - void Init(IEnumerable<Type> serviceTypes, IEnumerable<IWebSocketListener> listener, IEnumerable<string> urlPrefixes); - - /// <summary> - /// If set, all requests will respond with this message. - /// </summary> - string GlobalResponse { get; set; } - - /// <summary> - /// The HTTP request handler. - /// </summary> - /// <param name="context"></param> - /// <returns></returns> - Task RequestHandler(HttpContext context); - - /// <summary> - /// Get the default CORS headers. - /// </summary> - /// <param name="req"></param> - /// <returns></returns> - IDictionary<string, string> GetDefaultCorsHeaders(IRequest req); - } -} diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs index 5da748f41..6b896b41f 100644 --- a/MediaBrowser.Controller/Net/ISessionContext.cs +++ b/MediaBrowser.Controller/Net/ISessionContext.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { @@ -10,10 +10,10 @@ namespace MediaBrowser.Controller.Net { SessionInfo GetSession(object requestContext); - User GetUser(object requestContext); + User? GetUser(object requestContext); - SessionInfo GetSession(IRequest requestContext); + SessionInfo GetSession(HttpContext requestContext); - User GetUser(IRequest requestContext); + User? GetUser(HttpContext requestContext); } } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index e87f3bca6..c8c5caf80 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -1,7 +1,5 @@ #pragma warning disable CS1591 -#nullable enable - using System; using System.Net; using System.Net.WebSockets; @@ -32,7 +30,7 @@ namespace MediaBrowser.Controller.Net DateTime LastKeepAliveDate { get; set; } /// <summary> - /// Gets or sets the query string. + /// Gets the query string. /// </summary> /// <value>The query string.</value> IQueryCollection QueryString { get; } @@ -58,11 +56,11 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Sends a message asynchronously. /// </summary> - /// <typeparam name="T"></typeparam> + /// <typeparam name="T">The type of websocket message data.</typeparam> /// <param name="message">The message.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - /// <exception cref="ArgumentNullException">message</exception> + /// <exception cref="ArgumentNullException">The message is null.</exception> Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken); Task ProcessAsync(CancellationToken cancellationToken = default); diff --git a/MediaBrowser.Controller/Net/IWebSocketListener.cs b/MediaBrowser.Controller/Net/IWebSocketListener.cs index 7250a57b0..f1a75d518 100644 --- a/MediaBrowser.Controller/Net/IWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/IWebSocketListener.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.Net { /// <summary> - ///This is an interface for listening to messages coming through a web socket connection. + /// Interface for listening to messages coming through a web socket connection. /// </summary> public interface IWebSocketListener { @@ -13,5 +13,12 @@ namespace MediaBrowser.Controller.Net /// <param name="message">The message.</param> /// <returns>Task.</returns> Task ProcessMessageAsync(WebSocketMessageInfo message); + + /// <summary> + /// Processes a new web socket connection. + /// </summary> + /// <param name="connection">An instance of the <see cref="IWebSocketConnection"/> interface.</param> + /// <returns>Task.</returns> + Task ProcessWebSocketConnectedAsync(IWebSocketConnection connection); } } diff --git a/MediaBrowser.Controller/Net/IWebSocketManager.cs b/MediaBrowser.Controller/Net/IWebSocketManager.cs new file mode 100644 index 000000000..bb0ae83be --- /dev/null +++ b/MediaBrowser.Controller/Net/IWebSocketManager.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace MediaBrowser.Controller.Net +{ + /// <summary> + /// Interface IHttpServer. + /// </summary> + public interface IWebSocketManager + { + /// <summary> + /// The HTTP request handler. + /// </summary> + /// <param name="context">The current HTTP context.</param> + /// <returns>The task.</returns> + Task WebSocketRequestHandler(HttpContext context); + } +} diff --git a/MediaBrowser.Controller/Net/SecurityException.cs b/MediaBrowser.Controller/Net/SecurityException.cs index c6347133a..f0d0b45a0 100644 --- a/MediaBrowser.Controller/Net/SecurityException.cs +++ b/MediaBrowser.Controller/Net/SecurityException.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; namespace MediaBrowser.Controller.Net diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs deleted file mode 100644 index c1e9bc845..000000000 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ /dev/null @@ -1,44 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Net -{ - public class StaticResultOptions - { - public string ContentType { get; set; } - - public TimeSpan? CacheDuration { get; set; } - - public DateTime? DateLastModified { get; set; } - - public Func<Task<Stream>> ContentFactory { get; set; } - - public bool IsHeadRequest { get; set; } - - public IDictionary<string, string> ResponseHeaders { get; set; } - - public Action OnComplete { get; set; } - - public Action OnError { get; set; } - - public string Path { get; set; } - - public long? ContentLength { get; set; } - - public FileShare FileShare { get; set; } - - public StaticResultOptions() - { - ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - FileShare = FileShare.Read; - } - } - - public class StaticFileResultOptions : StaticResultOptions - { - } -} diff --git a/MediaBrowser.Controller/Net/WebSocketListenerState.cs b/MediaBrowser.Controller/Net/WebSocketListenerState.cs new file mode 100644 index 000000000..70604d60a --- /dev/null +++ b/MediaBrowser.Controller/Net/WebSocketListenerState.cs @@ -0,0 +1,17 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System; + +namespace MediaBrowser.Controller.Net +{ + public class WebSocketListenerState + { + public DateTime DateLastSendUtc { get; set; } + + public long InitialDelayMs { get; set; } + + public long IntervalMs { get; set; } + } +}
\ No newline at end of file diff --git a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs index be0b3ddc3..6f7ebf156 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs @@ -1,3 +1,5 @@ +#nullable disable + using MediaBrowser.Model.Net; namespace MediaBrowser.Controller.Net |
