Add GPL modules

This commit is contained in:
Andrew Rabert
2018-12-27 18:27:57 -05:00
parent 9bac3ac616
commit a86b71899e
648 changed files with 50005 additions and 123 deletions

View File

@@ -0,0 +1,69 @@
using System;
using MediaBrowser.Model.Services;
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, IResponse response, object requestDto)
{
AuthService.Authenticate(request, this);
}
/// <summary>
/// Order in which Request Filters are executed.
/// &lt;0 Executed before global request filters
/// &gt;0 Executed after global request filters
/// </summary>
/// <value>The priority.</value>
public int Priority
{
get { return 0; }
}
public string[] GetRoles()
{
return (Roles ?? string.Empty).Split(new []{ ',' }, StringSplitOptions.RemoveEmptyEntries);
}
public bool AllowLocalOnly { get; set; }
}
public interface IAuthenticationAttributes
{
bool EscapeParentalControl { get; }
bool AllowBeforeStartupWizard { get; }
bool AllowLocal { get; }
bool AllowLocalOnly { get; }
string[] GetRoles();
}
}

View File

@@ -0,0 +1,52 @@
using MediaBrowser.Controller.Entities;
using System;
namespace MediaBrowser.Controller.Net
{
public class AuthorizationInfo
{
/// <summary>
/// Gets or sets the user identifier.
/// </summary>
/// <value>The user identifier.</value>
public Guid UserId {
get {
if (User == null) {
return Guid.Empty;
}
else {
return User.Id;
}
}
}
/// <summary>
/// Gets or sets the device identifier.
/// </summary>
/// <value>The device identifier.</value>
public string DeviceId { get; set; }
/// <summary>
/// Gets or sets the device.
/// </summary>
/// <value>The device.</value>
public string Device { get; set; }
/// <summary>
/// Gets or sets the client.
/// </summary>
/// <value>The client.</value>
public string Client { get; set; }
/// <summary>
/// Gets or sets the version.
/// </summary>
/// <value>The version.</value>
public string Version { get; set; }
/// <summary>
/// Gets or sets the token.
/// </summary>
/// <value>The token.</value>
public string Token { get; set; }
public User User { get; set; }
}
}

View File

@@ -0,0 +1,322 @@
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.WebSockets;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received
/// </summary>
/// <typeparam name="TReturnDataType">The type of the T return data type.</typeparam>
/// <typeparam name="TStateType">The type of the T state type.</typeparam>
public abstract class BasePeriodicWebSocketListener<TReturnDataType, TStateType> : IWebSocketListener, IDisposable
where TStateType : WebSocketListenerState, new()
where TReturnDataType : class
{
/// <summary>
/// The _active connections
/// </summary>
protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>> ActiveConnections =
new List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>>();
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
protected abstract string Name { get; }
/// <summary>
/// Gets the data to send.
/// </summary>
/// <param name="state">The state.</param>
/// <returns>Task{`1}.</returns>
protected abstract Task<TReturnDataType> GetDataToSend(TStateType state, CancellationToken cancellationToken);
/// <summary>
/// The logger
/// </summary>
protected ILogger Logger;
protected ITimerFactory TimerFactory { get; private set; }
protected BasePeriodicWebSocketListener(ILogger logger)
{
if (logger == null)
{
throw new ArgumentNullException("logger");
}
Logger = logger;
}
/// <summary>
/// Processes the message.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>Task.</returns>
public Task ProcessMessage(WebSocketMessageInfo message)
{
if (message == null)
{
throw new ArgumentNullException("message");
}
if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase))
{
Start(message);
}
if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase))
{
Stop(message);
}
return Task.FromResult(true);
}
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
protected virtual bool SendOnTimer
{
get
{
return false;
}
}
protected virtual void ParseMessageParams(string[] values)
{
}
/// <summary>
/// Starts sending messages over a web socket
/// </summary>
/// <param name="message">The message.</param>
private void Start(WebSocketMessageInfo message)
{
var vals = message.Data.Split(',');
var dueTimeMs = long.Parse(vals[0], UsCulture);
var periodMs = long.Parse(vals[1], UsCulture);
if (vals.Length > 2)
{
ParseMessageParams(vals.Skip(2).ToArray());
}
var cancellationTokenSource = new CancellationTokenSource();
Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name);
var timer = SendOnTimer ?
TimerFactory.Create(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) :
null;
var state = new TStateType
{
IntervalMs = periodMs,
InitialDelayMs = dueTimeMs
};
lock (ActiveConnections)
{
ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>(message.Connection, cancellationTokenSource, timer, state));
}
if (timer != null)
{
timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs));
}
}
/// <summary>
/// Timers the callback.
/// </summary>
/// <param name="state">The state.</param>
private void TimerCallback(object state)
{
var connection = (IWebSocketConnection)state;
Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple;
lock (ActiveConnections)
{
tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection);
}
if (tuple == null)
{
return;
}
if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested)
{
DisposeConnection(tuple);
return;
}
SendData(tuple);
}
protected void SendData(bool force)
{
Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>[] tuples;
lock (ActiveConnections)
{
tuples = ActiveConnections
.Where(c =>
{
if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested)
{
var state = c.Item4;
if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs)
{
return true;
}
}
return false;
})
.ToArray();
}
foreach (var tuple in tuples)
{
SendData(tuple);
}
}
private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple)
{
var connection = tuple.Item1;
try
{
var state = tuple.Item4;
var cancellationToken = tuple.Item2.Token;
var data = await GetDataToSend(state, cancellationToken).ConfigureAwait(false);
if (data != null)
{
await connection.SendAsync(new WebSocketMessage<TReturnDataType>
{
MessageType = Name,
Data = data
}, cancellationToken).ConfigureAwait(false);
state.DateLastSendUtc = DateTime.UtcNow;
}
}
catch (OperationCanceledException)
{
if (tuple.Item2.IsCancellationRequested)
{
DisposeConnection(tuple);
}
}
catch (Exception ex)
{
Logger.ErrorException("Error sending web socket message {0}", ex, Name);
DisposeConnection(tuple);
}
}
/// <summary>
/// Stops sending messages over a web socket
/// </summary>
/// <param name="message">The message.</param>
private void Stop(WebSocketMessageInfo message)
{
lock (ActiveConnections)
{
var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection);
if (connection != null)
{
DisposeConnection(connection);
}
}
}
/// <summary>
/// Disposes the connection.
/// </summary>
/// <param name="connection">The connection.</param>
private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> connection)
{
Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
var timer = connection.Item3;
if (timer != null)
{
try
{
timer.Dispose();
}
catch (ObjectDisposedException)
{
}
}
try
{
connection.Item2.Cancel();
connection.Item2.Dispose();
}
catch (ObjectDisposedException)
{
}
ActiveConnections.Remove(connection);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
if (dispose)
{
lock (ActiveConnections)
{
foreach (var connection in ActiveConnections.ToArray())
{
DisposeConnection(connection);
}
}
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
}
}
public class WebSocketListenerState
{
public DateTime DateLastSendUtc { get; set; }
public long InitialDelayMs { get; set; }
public long IntervalMs { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
{
public interface IAuthService
{
void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues);
}
}

View File

@@ -0,0 +1,21 @@
using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
{
public interface IAuthorizationContext
{
/// <summary>
/// Gets the authorization information.
/// </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);
}
}

View File

@@ -0,0 +1,17 @@
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; }
}
}

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
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, FileShareMode fileShare = FileShareMode.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);
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Events;
namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Interface IHttpServer
/// </summary>
public interface IHttpServer : IDisposable
{
/// <summary>
/// Gets the URL prefix.
/// </summary>
/// <value>The URL prefix.</value>
string[] UrlPrefixes { get; }
/// <summary>
/// Stops this instance.
/// </summary>
void Stop();
/// <summary>
/// Occurs when [web socket connected].
/// </summary>
event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
/// <summary>
/// Inits this instance.
/// </summary>
void Init(IEnumerable<IService> services, IEnumerable<IWebSocketListener> listener);
/// <summary>
/// If set, all requests will respond with this message
/// </summary>
string GlobalResponse { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Session;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
{
public interface ISessionContext
{
SessionInfo GetSession(object requestContext);
User GetUser(object requestContext);
SessionInfo GetSession(IRequest requestContext);
User GetUser(IRequest requestContext);
}
}

View File

@@ -0,0 +1,85 @@
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services;
using System.Net.WebSockets;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace MediaBrowser.Controller.Net
{
public interface IWebSocketConnection : IDisposable
{
/// <summary>
/// Occurs when [closed].
/// </summary>
event EventHandler<EventArgs> Closed;
/// <summary>
/// Gets the id.
/// </summary>
/// <value>The id.</value>
Guid Id { get; }
/// <summary>
/// Gets the last activity date.
/// </summary>
/// <value>The last activity date.</value>
DateTime LastActivityDate { get; }
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>The URL.</value>
string Url { get; set; }
/// <summary>
/// Gets or sets the query string.
/// </summary>
/// <value>The query string.</value>
QueryParamCollection QueryString { get; set; }
/// <summary>
/// Gets or sets the receive action.
/// </summary>
/// <value>The receive action.</value>
Func<WebSocketMessageInfo, Task> OnReceive { get; set; }
/// <summary>
/// Gets the state.
/// </summary>
/// <value>The state.</value>
WebSocketState State { get; }
/// <summary>
/// Gets the remote end point.
/// </summary>
/// <value>The remote end point.</value>
string RemoteEndPoint { get; }
/// <summary>
/// Sends a message asynchronously.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">message</exception>
Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken);
/// <summary>
/// Sends a message asynchronously.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SendAsync(byte[] buffer, CancellationToken cancellationToken);
/// <summary>
/// Sends a message asynchronously.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">buffer</exception>
Task SendAsync(string text, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,17 @@
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Net
{
/// <summary>
///This is an interface for listening to messages coming through a web socket connection
/// </summary>
public interface IWebSocketListener
{
/// <summary>
/// Processes the message.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>Task.</returns>
Task ProcessMessage(WebSocketMessageInfo message);
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace MediaBrowser.Controller.Net
{
public class SecurityException : Exception
{
public SecurityException(string message)
: base(message)
{
}
public SecurityExceptionType SecurityExceptionType { get; set; }
}
public enum SecurityExceptionType
{
Unauthenticated = 0,
ParentalControl = 1
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Net
{
public class StaticResultOptions
{
public string ContentType { get; set; }
public TimeSpan? CacheDuration { get; set; }
public DateTime? DateLastModified { get; set; }
public Guid CacheKey { 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 FileShareMode FileShare { get; set; }
public StaticResultOptions()
{
ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
FileShare = FileShareMode.Read;
}
}
public class StaticFileResultOptions : StaticResultOptions
{
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Specialized;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Class WebSocketConnectEventArgs
/// </summary>
public class WebSocketConnectingEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>The URL.</value>
public string Url { get; set; }
/// <summary>
/// Gets or sets the endpoint.
/// </summary>
/// <value>The endpoint.</value>
public string Endpoint { get; set; }
/// <summary>
/// Gets or sets the query string.
/// </summary>
/// <value>The query string.</value>
public QueryParamCollection QueryString { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [allow connection].
/// </summary>
/// <value><c>true</c> if [allow connection]; otherwise, <c>false</c>.</value>
public bool AllowConnection { get; set; }
public WebSocketConnectingEventArgs()
{
QueryString = new QueryParamCollection();
AllowConnection = true;
}
}
}

View File

@@ -0,0 +1,16 @@
using MediaBrowser.Model.Net;
namespace MediaBrowser.Controller.Net
{
/// <summary>
/// Class WebSocketMessageInfo
/// </summary>
public class WebSocketMessageInfo : WebSocketMessage<string>
{
/// <summary>
/// Gets or sets the connection.
/// </summary>
/// <value>The connection.</value>
public IWebSocketConnection Connection { get; set; }
}
}