diff options
Diffstat (limited to 'MediaBrowser.Common')
| -rw-r--r-- | MediaBrowser.Common/Configuration/ConfigurationHelper.cs | 68 | ||||
| -rw-r--r-- | MediaBrowser.Common/Configuration/IApplicationPaths.cs (renamed from MediaBrowser.Common/Kernel/IApplicationPaths.cs) | 2 | ||||
| -rw-r--r-- | MediaBrowser.Common/Configuration/IConfigurationManager.cs | 36 | ||||
| -rw-r--r-- | MediaBrowser.Common/IApplicationHost.cs (renamed from MediaBrowser.Common/Kernel/IApplicationHost.cs) | 8 | ||||
| -rw-r--r-- | MediaBrowser.Common/Kernel/BaseKernel.cs | 225 | ||||
| -rw-r--r-- | MediaBrowser.Common/Kernel/IKernel.cs | 46 | ||||
| -rw-r--r-- | MediaBrowser.Common/MediaBrowser.Common.csproj | 10 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/Handlers/BaseHandler.cs | 808 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/Handlers/IHttpServerHandler.cs | 32 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs | 264 | ||||
| -rw-r--r-- | MediaBrowser.Common/Plugins/BasePlugin.cs | 33 | ||||
| -rw-r--r-- | MediaBrowser.Common/Updates/ApplicationUpdater.cs | 1 | ||||
| -rw-r--r-- | MediaBrowser.Common/Updates/IPackageManager.cs | 36 |
13 files changed, 140 insertions, 1429 deletions
diff --git a/MediaBrowser.Common/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common/Configuration/ConfigurationHelper.cs new file mode 100644 index 000000000..fc74a6a4d --- /dev/null +++ b/MediaBrowser.Common/Configuration/ConfigurationHelper.cs @@ -0,0 +1,68 @@ +using MediaBrowser.Model.Serialization; +using System; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Common.Configuration +{ + /// <summary> + /// Class ConfigurationHelper + /// </summary> + public static class ConfigurationHelper + { + /// <summary> + /// Reads an xml configuration file from the file system + /// It will immediately re-serialize and save if new serialization data is available due to property changes + /// </summary> + /// <param name="type">The type.</param> + /// <param name="path">The path.</param> + /// <param name="xmlSerializer">The XML serializer.</param> + /// <returns>System.Object.</returns> + public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer) + { + object configuration; + + byte[] buffer = null; + + // Use try/catch to avoid the extra file system lookup using File.Exists + try + { + buffer = File.ReadAllBytes(path); + + configuration = xmlSerializer.DeserializeFromBytes(type, buffer); + } + catch (FileNotFoundException) + { + configuration = Activator.CreateInstance(type); + } + + // Take the object we just got and serialize it back to bytes + var newBytes = xmlSerializer.SerializeToBytes(configuration); + + // If the file didn't exist before, or if something has changed, re-save + if (buffer == null || !buffer.SequenceEqual(newBytes)) + { + // Save it after load in case we got new items + File.WriteAllBytes(path, newBytes); + } + + return configuration; + } + + + /// <summary> + /// Reads an xml configuration file from the file system + /// It will immediately save the configuration after loading it, just + /// in case there are new serializable properties + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="path">The path.</param> + /// <param name="xmlSerializer">The XML serializer.</param> + /// <returns>``0.</returns> + public static T GetXmlConfiguration<T>(string path, IXmlSerializer xmlSerializer) + where T : class + { + return GetXmlConfiguration(typeof(T), path, xmlSerializer) as T; + } + } +} diff --git a/MediaBrowser.Common/Kernel/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs index 52c3b199d..d2446ce46 100644 --- a/MediaBrowser.Common/Kernel/IApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs @@ -1,5 +1,5 @@ -namespace MediaBrowser.Common.Kernel +namespace MediaBrowser.Common.Configuration { /// <summary> /// Interface IApplicationPaths diff --git a/MediaBrowser.Common/Configuration/IConfigurationManager.cs b/MediaBrowser.Common/Configuration/IConfigurationManager.cs new file mode 100644 index 000000000..0d0759b66 --- /dev/null +++ b/MediaBrowser.Common/Configuration/IConfigurationManager.cs @@ -0,0 +1,36 @@ +using MediaBrowser.Model.Configuration; +using System; + +namespace MediaBrowser.Common.Configuration +{ + public interface IConfigurationManager + { + /// <summary> + /// Occurs when [configuration updated]. + /// </summary> + event EventHandler<EventArgs> ConfigurationUpdated; + + /// <summary> + /// Gets or sets the application paths. + /// </summary> + /// <value>The application paths.</value> + IApplicationPaths CommonApplicationPaths { get; } + + /// <summary> + /// Gets the configuration. + /// </summary> + /// <value>The configuration.</value> + BaseApplicationConfiguration CommonConfiguration { get; } + + /// <summary> + /// Saves the configuration. + /// </summary> + void SaveConfiguration(); + + /// <summary> + /// Replaces the configuration. + /// </summary> + /// <param name="newConfiguration">The new configuration.</param> + void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration); + } +} diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 38a1cb318..4bd90e531 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.Kernel +namespace MediaBrowser.Common { /// <summary> /// An interface to be implemented by the applications hosting a kernel @@ -18,12 +18,6 @@ namespace MediaBrowser.Common.Kernel void Restart(); /// <summary> - /// Configures the auto run at startup. - /// </summary> - /// <param name="autorun">if set to <c>true</c> [autorun].</param> - void ConfigureAutoRunAtStartup(bool autorun); - - /// <summary> /// Gets the application version. /// </summary> /// <value>The application version.</value> diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 489423d9e..cf8133e97 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -1,45 +1,21 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Security; -using MediaBrowser.Model.Configuration; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Events; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using System; -using System.IO; -using System.Linq; -using System.Threading; namespace MediaBrowser.Common.Kernel { /// <summary> /// Represents a shared base kernel for both the Ui and server apps /// </summary> - /// <typeparam name="TConfigurationType">The type of the T configuration type.</typeparam> - /// <typeparam name="TApplicationPathsType">The type of the T application paths type.</typeparam> - public abstract class BaseKernel<TConfigurationType, TApplicationPathsType> : IDisposable, IKernel - where TConfigurationType : BaseApplicationConfiguration, new() - where TApplicationPathsType : IApplicationPaths + public abstract class BaseKernel : IKernel { /// <summary> /// Occurs when [has pending restart changed]. /// </summary> public event EventHandler HasPendingRestartChanged; - #region ConfigurationUpdated Event - /// <summary> - /// Occurs when [configuration updated]. - /// </summary> - public event EventHandler<EventArgs> ConfigurationUpdated; - - /// <summary> - /// Called when [configuration updated]. - /// </summary> - internal void OnConfigurationUpdated() - { - EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger); - } - #endregion - #region ApplicationUpdated Event /// <summary> /// Occurs when [application updated]. @@ -58,65 +34,12 @@ namespace MediaBrowser.Common.Kernel #endregion /// <summary> - /// The _configuration loaded - /// </summary> - private bool _configurationLoaded; - /// <summary> - /// The _configuration sync lock - /// </summary> - private object _configurationSyncLock = new object(); - /// <summary> - /// The _configuration - /// </summary> - private TConfigurationType _configuration; - /// <summary> - /// Gets the system configuration - /// </summary> - /// <value>The configuration.</value> - public TConfigurationType Configuration - { - get - { - // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => GetXmlConfiguration<TConfigurationType>(ApplicationPaths.SystemConfigurationFilePath)); - return _configuration; - } - protected set - { - _configuration = value; - - if (value == null) - { - _configurationLoaded = false; - } - } - } - - /// <summary> /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart. /// </summary> /// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value> public bool HasPendingRestart { get; private set; } /// <summary> - /// Gets the application paths. - /// </summary> - /// <value>The application paths.</value> - public TApplicationPathsType ApplicationPaths { get; private set; } - - /// <summary> - /// Gets or sets the TCP manager. - /// </summary> - /// <value>The TCP manager.</value> - private IServerManager ServerManager { get; set; } - - /// <summary> - /// Gets the plug-in security manager. - /// </summary> - /// <value>The plug-in security manager.</value> - public ISecurityManager SecurityManager { get; set; } - - /// <summary> /// Gets the UDP server port number. /// This can't be configurable because then the user would have to configure their client to discover the server. /// </summary> @@ -141,7 +64,7 @@ namespace MediaBrowser.Common.Kernel { get { - return "http://+:" + Configuration.HttpServerPortNumber + "/" + WebApplicationName + "/"; + return "http://+:" + _configurationManager.CommonConfiguration.HttpServerPortNumber + "/" + WebApplicationName + "/"; } } @@ -163,25 +86,18 @@ namespace MediaBrowser.Common.Kernel /// <value>The application host.</value> protected IApplicationHost ApplicationHost { get; private set; } - /// <summary> - /// The _XML serializer - /// </summary> - private readonly IXmlSerializer _xmlSerializer; + private readonly IConfigurationManager _configurationManager; /// <summary> - /// Initializes a new instance of the <see cref="BaseKernel{TApplicationPathsType}" /> class. + /// Initializes a new instance of the <see cref="BaseKernel" /> class. /// </summary> /// <param name="appHost">The app host.</param> - /// <param name="appPaths">The app paths.</param> - /// <param name="xmlSerializer">The XML serializer.</param> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">isoManager</exception> - protected BaseKernel(IApplicationHost appHost, TApplicationPathsType appPaths, IXmlSerializer xmlSerializer, ILogger logger) + /// <param name="logManager">The log manager.</param> + protected BaseKernel(IApplicationHost appHost, ILogManager logManager, IConfigurationManager configurationManager) { - ApplicationPaths = appPaths; ApplicationHost = appHost; - _xmlSerializer = xmlSerializer; - Logger = logger; + _configurationManager = configurationManager; + Logger = logManager.GetLogger("Kernel"); } /// <summary> @@ -201,7 +117,6 @@ namespace MediaBrowser.Common.Kernel /// <returns>Task.</returns> protected virtual void ReloadInternal() { - ServerManager = ApplicationHost.Resolve<IServerManager>(); } /// <summary> @@ -215,24 +130,6 @@ namespace MediaBrowser.Common.Kernel } /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <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) - { - - } - - /// <summary> /// Performs the pending restart. /// </summary> /// <returns>Task.</returns> @@ -261,108 +158,10 @@ namespace MediaBrowser.Common.Kernel HasPendingRestart = HasPendingRestart, Version = ApplicationHost.ApplicationVersion.ToString(), IsNetworkDeployed = ApplicationHost.CanSelfUpdate, - WebSocketPortNumber = ServerManager.WebSocketPortNumber, - SupportsNativeWebSocket = ServerManager.SupportsNativeWebSocket, + WebSocketPortNumber = ApplicationHost.Resolve<IServerManager>().WebSocketPortNumber, + SupportsNativeWebSocket = ApplicationHost.Resolve<IServerManager>().SupportsNativeWebSocket, FailedPluginAssemblies = ApplicationHost.FailedAssemblies.ToArray() }; } - - /// <summary> - /// The _save lock - /// </summary> - private readonly object _configurationSaveLock = new object(); - - /// <summary> - /// Saves the current configuration - /// </summary> - public void SaveConfiguration() - { - lock (_configurationSaveLock) - { - _xmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath); - } - - OnConfigurationUpdated(); - } - - /// <summary> - /// Gets the application paths. - /// </summary> - /// <value>The application paths.</value> - IApplicationPaths IKernel.ApplicationPaths - { - get { return ApplicationPaths; } - } - /// <summary> - /// Gets the configuration. - /// </summary> - /// <value>The configuration.</value> - BaseApplicationConfiguration IKernel.Configuration - { - get { return Configuration; } - } - - /// <summary> - /// Reads an xml configuration file from the file system - /// It will immediately re-serialize and save if new serialization data is available due to property changes - /// </summary> - /// <param name="type">The type.</param> - /// <param name="path">The path.</param> - /// <returns>System.Object.</returns> - public object GetXmlConfiguration(Type type, string path) - { - Logger.Info("Loading {0} at {1}", type.Name, path); - - object configuration; - - byte[] buffer = null; - - // Use try/catch to avoid the extra file system lookup using File.Exists - try - { - buffer = File.ReadAllBytes(path); - - configuration = _xmlSerializer.DeserializeFromBytes(type, buffer); - } - catch (FileNotFoundException) - { - configuration = Activator.CreateInstance(type); - } - - // Take the object we just got and serialize it back to bytes - var newBytes = _xmlSerializer.SerializeToBytes(configuration); - - // If the file didn't exist before, or if something has changed, re-save - if (buffer == null || !buffer.SequenceEqual(newBytes)) - { - Logger.Info("Saving {0} to {1}", type.Name, path); - - // Save it after load in case we got new items - File.WriteAllBytes(path, newBytes); - } - - return configuration; - } - - - /// <summary> - /// Reads an xml configuration file from the file system - /// It will immediately save the configuration after loading it, just - /// in case there are new serializable properties - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="path">The path.</param> - /// <returns>``0.</returns> - private T GetXmlConfiguration<T>(string path) - where T : class - { - return GetXmlConfiguration(typeof(T), path) as T; - } - - /// <summary> - /// Limits simultaneous access to various resources - /// </summary> - /// <value>The resource pools.</value> - public ResourcePool ResourcePools { get; set; } } } diff --git a/MediaBrowser.Common/Kernel/IKernel.cs b/MediaBrowser.Common/Kernel/IKernel.cs index 1a2d86d7f..51677677a 100644 --- a/MediaBrowser.Common/Kernel/IKernel.cs +++ b/MediaBrowser.Common/Kernel/IKernel.cs @@ -1,17 +1,12 @@ -using MediaBrowser.Common.Plugins; -using MediaBrowser.Common.Security; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.System; +using MediaBrowser.Model.System; using System; -using System.Collections.Generic; -using System.Threading.Tasks; namespace MediaBrowser.Common.Kernel { /// <summary> /// Interface IKernel /// </summary> - public interface IKernel : IDisposable + public interface IKernel { /// <summary> /// Occurs when [has pending restart changed]. @@ -19,18 +14,6 @@ namespace MediaBrowser.Common.Kernel event EventHandler HasPendingRestartChanged; /// <summary> - /// Gets the application paths. - /// </summary> - /// <value>The application paths.</value> - IApplicationPaths ApplicationPaths { get; } - - /// <summary> - /// Gets the configuration. - /// </summary> - /// <value>The configuration.</value> - BaseApplicationConfiguration Configuration { get; } - - /// <summary> /// Gets the kernel context. /// </summary> /// <value>The kernel context.</value> @@ -84,33 +67,8 @@ namespace MediaBrowser.Common.Kernel string HttpServerUrlPrefix { get; } /// <summary> - /// Gets the plug-in security manager. - /// </summary> - /// <value>The plug-in security manager.</value> - ISecurityManager SecurityManager { get; set; } - - /// <summary> - /// Occurs when [configuration updated]. - /// </summary> - event EventHandler<EventArgs> ConfigurationUpdated; - - /// <summary> /// Notifies the pending restart. /// </summary> void NotifyPendingRestart(); - - /// <summary> - /// Gets the XML configuration. - /// </summary> - /// <param name="type">The type.</param> - /// <param name="path">The path.</param> - /// <returns>System.Object.</returns> - object GetXmlConfiguration(Type type, string path); - - /// <summary> - /// Limits simultaneous access to various resources - /// </summary> - /// <value>The resource pools.</value> - ResourcePool ResourcePools { get; set; } } } diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 284649b53..8b7aae9cb 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -46,6 +46,8 @@ <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> + <Compile Include="Configuration\ConfigurationHelper.cs" /> + <Compile Include="Configuration\IConfigurationManager.cs" /> <Compile Include="Constants\Constants.cs" /> <Compile Include="Events\EventHelper.cs" /> <Compile Include="Extensions\BaseExtensions.cs" /> @@ -58,14 +60,11 @@ <Compile Include="IO\ProgressStream.cs" /> <Compile Include="IO\StreamDefaults.cs" /> <Compile Include="Kernel\BasePeriodicWebSocketListener.cs" /> - <Compile Include="Kernel\IApplicationPaths.cs" /> + <Compile Include="Configuration\IApplicationPaths.cs" /> <Compile Include="Kernel\IServerManager.cs" /> <Compile Include="Kernel\IWebSocketListener.cs" /> - <Compile Include="Kernel\IApplicationHost.cs" /> + <Compile Include="IApplicationHost.cs" /> <Compile Include="Kernel\IKernel.cs" /> - <Compile Include="Kernel\ResourcePool.cs" /> - <Compile Include="Net\Handlers\IHttpServerHandler.cs" /> - <Compile Include="Net\Handlers\StaticFileHandler.cs" /> <Compile Include="Net\IHttpClient.cs" /> <Compile Include="Net\IHttpServer.cs" /> <Compile Include="Net\INetworkManager.cs" /> @@ -97,7 +96,6 @@ <Compile Include="ScheduledTasks\SystemEventTrigger.cs" /> <Compile Include="Kernel\BaseKernel.cs" /> <Compile Include="Kernel\KernelContext.cs" /> - <Compile Include="Net\Handlers\BaseHandler.cs" /> <Compile Include="Plugins\BasePlugin.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="ScheduledTasks\DailyTrigger.cs" /> diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs deleted file mode 100644 index 5d26c7e92..000000000 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ /dev/null @@ -1,808 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Kernel; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net.Handlers -{ - /// <summary> - /// Class BaseHandler - /// </summary> - public abstract class BaseHandler<TKernelType> : IHttpServerHandler - where TKernelType : IKernel - { - /// <summary> - /// Initializes the specified kernel. - /// </summary> - /// <param name="kernel">The kernel.</param> - public void Initialize(IKernel kernel) - { - Kernel = (TKernelType)kernel; - } - - /// <summary> - /// Gets or sets the kernel. - /// </summary> - /// <value>The kernel.</value> - protected TKernelType Kernel { get; private set; } - - /// <summary> - /// Gets the URL suffix used to determine if this handler can process a request. - /// </summary> - /// <value>The URL suffix.</value> - protected virtual string UrlSuffix - { - get - { - var name = GetType().Name; - - const string srch = "Handler"; - - if (name.EndsWith(srch, StringComparison.OrdinalIgnoreCase)) - { - name = name.Substring(0, name.Length - srch.Length); - } - - return "api/" + name; - } - } - - /// <summary> - /// Handleses the request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - public virtual bool HandlesRequest(HttpListenerRequest request) - { - var name = '/' + UrlSuffix.TrimStart('/'); - - var url = Kernel.WebApplicationName + name; - - return request.Url.LocalPath.EndsWith(url, StringComparison.OrdinalIgnoreCase); - } - - /// <summary> - /// Gets or sets the compressed stream. - /// </summary> - /// <value>The compressed stream.</value> - private Stream CompressedStream { get; set; } - - /// <summary> - /// Gets a value indicating whether [use chunked encoding]. - /// </summary> - /// <value><c>null</c> if [use chunked encoding] contains no value, <c>true</c> if [use chunked encoding]; otherwise, <c>false</c>.</value> - public virtual bool? UseChunkedEncoding - { - get - { - return null; - } - } - - /// <summary> - /// The original HttpListenerContext - /// </summary> - /// <value>The HTTP listener context.</value> - protected HttpListenerContext HttpListenerContext { get; set; } - - /// <summary> - /// The _query string - /// </summary> - private NameValueCollection _queryString; - /// <summary> - /// The original QueryString - /// </summary> - /// <value>The query string.</value> - public NameValueCollection QueryString - { - get - { - // HttpListenerContext.Request.QueryString is not decoded properly - return _queryString; - } - } - - /// <summary> - /// The _requested ranges - /// </summary> - private List<KeyValuePair<long, long?>> _requestedRanges; - /// <summary> - /// Gets the requested ranges. - /// </summary> - /// <value>The requested ranges.</value> - protected IEnumerable<KeyValuePair<long, long?>> RequestedRanges - { - get - { - if (_requestedRanges == null) - { - _requestedRanges = new List<KeyValuePair<long, long?>>(); - - if (IsRangeRequest) - { - // Example: bytes=0-,32-63 - var ranges = HttpListenerContext.Request.Headers["Range"].Split('=')[1].Split(','); - - foreach (var range in ranges) - { - var vals = range.Split('-'); - - long start = 0; - long? end = null; - - if (!string.IsNullOrEmpty(vals[0])) - { - start = long.Parse(vals[0]); - } - if (!string.IsNullOrEmpty(vals[1])) - { - end = long.Parse(vals[1]); - } - - _requestedRanges.Add(new KeyValuePair<long, long?>(start, end)); - } - } - } - - return _requestedRanges; - } - } - - /// <summary> - /// Gets a value indicating whether this instance is range request. - /// </summary> - /// <value><c>true</c> if this instance is range request; otherwise, <c>false</c>.</value> - protected bool IsRangeRequest - { - get - { - return HttpListenerContext.Request.Headers.AllKeys.Contains("Range"); - } - } - - /// <summary> - /// Gets a value indicating whether [client supports compression]. - /// </summary> - /// <value><c>true</c> if [client supports compression]; otherwise, <c>false</c>.</value> - protected bool ClientSupportsCompression - { - get - { - var enc = HttpListenerContext.Request.Headers["Accept-Encoding"] ?? string.Empty; - - return enc.Equals("*", StringComparison.OrdinalIgnoreCase) || - enc.IndexOf("deflate", StringComparison.OrdinalIgnoreCase) != -1 || - enc.IndexOf("gzip", StringComparison.OrdinalIgnoreCase) != -1; - } - } - - /// <summary> - /// Gets the compression method. - /// </summary> - /// <value>The compression method.</value> - private string CompressionMethod - { - get - { - var enc = HttpListenerContext.Request.Headers["Accept-Encoding"] ?? string.Empty; - - if (enc.IndexOf("deflate", StringComparison.OrdinalIgnoreCase) != -1 || enc.Equals("*", StringComparison.OrdinalIgnoreCase)) - { - return "deflate"; - } - if (enc.IndexOf("gzip", StringComparison.OrdinalIgnoreCase) != -1) - { - return "gzip"; - } - - return null; - } - } - - /// <summary> - /// Processes the request. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <returns>Task.</returns> - public virtual async Task ProcessRequest(HttpListenerContext ctx) - { - HttpListenerContext = ctx; - - ctx.Response.AddHeader("Access-Control-Allow-Origin", "*"); - - ctx.Response.KeepAlive = true; - - try - { - await ProcessRequestInternal(ctx).ConfigureAwait(false); - } - catch (InvalidOperationException ex) - { - HandleException(ctx.Response, ex, 422); - - throw; - } - catch (ResourceNotFoundException ex) - { - HandleException(ctx.Response, ex, 404); - - throw; - } - catch (FileNotFoundException ex) - { - HandleException(ctx.Response, ex, 404); - - throw; - } - catch (DirectoryNotFoundException ex) - { - HandleException(ctx.Response, ex, 404); - - throw; - } - catch (UnauthorizedAccessException ex) - { - HandleException(ctx.Response, ex, 401); - - throw; - } - catch (ArgumentException ex) - { - HandleException(ctx.Response, ex, 400); - - throw; - } - catch (Exception ex) - { - HandleException(ctx.Response, ex, 500); - - throw; - } - finally - { - DisposeResponseStream(); - } - } - - /// <summary> - /// Appends the error message. - /// </summary> - /// <param name="response">The response.</param> - /// <param name="ex">The ex.</param> - /// <param name="statusCode">The status code.</param> - private void HandleException(HttpListenerResponse response, Exception ex, int statusCode) - { - response.StatusCode = statusCode; - - response.Headers.Add("Status", statusCode.ToString(new CultureInfo("en-US"))); - - response.Headers.Remove("Age"); - response.Headers.Remove("Expires"); - response.Headers.Remove("Cache-Control"); - response.Headers.Remove("Etag"); - response.Headers.Remove("Last-Modified"); - - response.ContentType = "text/plain"; - - //Logger.ErrorException("Error processing request", ex); - - if (!string.IsNullOrEmpty(ex.Message)) - { - response.AddHeader("X-Application-Error-Code", ex.Message); - } - - var bytes = Encoding.UTF8.GetBytes(ex.Message); - - var stream = CompressedStream ?? response.OutputStream; - - // This could fail, but try to add the stack trace as the body content - try - { - stream.Write(bytes, 0, bytes.Length); - } - catch (Exception ex1) - { - //Logger.ErrorException("Error dumping stack trace", ex1); - } - } - - /// <summary> - /// Processes the request internal. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <returns>Task.</returns> - private async Task ProcessRequestInternal(HttpListenerContext ctx) - { - var responseInfo = await GetResponseInfo().ConfigureAwait(false); - - // Let the client know if byte range requests are supported or not - if (responseInfo.SupportsByteRangeRequests) - { - ctx.Response.Headers["Accept-Ranges"] = "bytes"; - } - else if (!responseInfo.SupportsByteRangeRequests) - { - ctx.Response.Headers["Accept-Ranges"] = "none"; - } - - if (responseInfo.IsResponseValid && responseInfo.SupportsByteRangeRequests && IsRangeRequest) - { - // Set the initial status code - // When serving a range request, we need to return status code 206 to indicate a partial response body - responseInfo.StatusCode = 206; - } - - ctx.Response.ContentType = responseInfo.ContentType; - - if (responseInfo.Etag.HasValue) - { - ctx.Response.Headers["ETag"] = responseInfo.Etag.Value.ToString("N"); - } - - var isCacheValid = true; - - // Validate If-Modified-Since - if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) - { - DateTime ifModifiedSince; - - if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"], out ifModifiedSince)) - { - isCacheValid = IsCacheValid(ifModifiedSince.ToUniversalTime(), responseInfo.CacheDuration, - responseInfo.DateLastModified); - } - } - - // Validate If-None-Match - if (isCacheValid && - (responseInfo.Etag.HasValue || !string.IsNullOrEmpty(ctx.Request.Headers["If-None-Match"]))) - { - Guid ifNoneMatch; - - if (Guid.TryParse(ctx.Request.Headers["If-None-Match"] ?? string.Empty, out ifNoneMatch)) - { - if (responseInfo.Etag.HasValue && responseInfo.Etag.Value == ifNoneMatch) - { - responseInfo.StatusCode = 304; - } - } - } - - LogResponse(ctx, responseInfo); - - if (responseInfo.IsResponseValid) - { - await OnProcessingRequest(responseInfo).ConfigureAwait(false); - } - - if (responseInfo.IsResponseValid) - { - await ProcessUncachedRequest(ctx, responseInfo).ConfigureAwait(false); - } - else - { - if (responseInfo.StatusCode == 304) - { - AddAgeHeader(ctx.Response, responseInfo); - AddExpiresHeader(ctx.Response, responseInfo); - } - - ctx.Response.StatusCode = responseInfo.StatusCode; - ctx.Response.SendChunked = false; - } - } - - /// <summary> - /// The _null task result - /// </summary> - private readonly Task<bool> _nullTaskResult = Task.FromResult(true); - - /// <summary> - /// Called when [processing request]. - /// </summary> - /// <param name="responseInfo">The response info.</param> - /// <returns>Task.</returns> - protected virtual Task OnProcessingRequest(ResponseInfo responseInfo) - { - return _nullTaskResult; - } - - /// <summary> - /// Logs the response. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <param name="responseInfo">The response info.</param> - private void LogResponse(HttpListenerContext ctx, ResponseInfo responseInfo) - { - // Don't log normal 200's - if (responseInfo.StatusCode == 200) - { - return; - } - - var log = new StringBuilder(); - - log.AppendLine(string.Format("Url: {0}", ctx.Request.Url)); - - log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k]))); - - var msg = "Http Response Sent (" + responseInfo.StatusCode + ") to " + ctx.Request.RemoteEndPoint; - - if (Kernel.Configuration.EnableHttpLevelLogging) - { - //Logger.LogMultiline(msg, LogSeverity.Debug, log); - } - } - - /// <summary> - /// Processes the uncached request. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <param name="responseInfo">The response info.</param> - /// <returns>Task.</returns> - private async Task ProcessUncachedRequest(HttpListenerContext ctx, ResponseInfo responseInfo) - { - var totalContentLength = GetTotalContentLength(responseInfo); - - // By default, use chunked encoding if we don't know the content length - var useChunkedEncoding = UseChunkedEncoding == null ? (totalContentLength == null) : UseChunkedEncoding.Value; - - // Don't force this to true. HttpListener will default it to true if supported by the client. - if (!useChunkedEncoding) - { - ctx.Response.SendChunked = false; - } - - // Set the content length, if we know it - if (totalContentLength.HasValue) - { - ctx.Response.ContentLength64 = totalContentLength.Value; - } - - var compressResponse = responseInfo.CompressResponse && ClientSupportsCompression; - - // Add the compression header - if (compressResponse) - { - ctx.Response.AddHeader("Content-Encoding", CompressionMethod); - ctx.Response.AddHeader("Vary", "Accept-Encoding"); - } - - // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant - // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching - if (responseInfo.DateLastModified.HasValue && (!responseInfo.Etag.HasValue || responseInfo.CacheDuration.Ticks > 0)) - { - ctx.Response.Headers[HttpResponseHeader.LastModified] = responseInfo.DateLastModified.Value.ToString("r"); - AddAgeHeader(ctx.Response, responseInfo); - } - - // Add caching headers - ConfigureCaching(ctx.Response, responseInfo); - - // Set the status code - ctx.Response.StatusCode = responseInfo.StatusCode; - - if (responseInfo.IsResponseValid) - { - // Finally, write the response data - var outputStream = ctx.Response.OutputStream; - - if (compressResponse) - { - if (CompressionMethod.Equals("deflate", StringComparison.OrdinalIgnoreCase)) - { - CompressedStream = new DeflateStream(outputStream, CompressionLevel.Fastest, true); - } - else - { - CompressedStream = new GZipStream(outputStream, CompressionLevel.Fastest, true); - } - - outputStream = CompressedStream; - } - - await WriteResponseToOutputStream(outputStream, responseInfo, totalContentLength).ConfigureAwait(false); - } - else - { - ctx.Response.SendChunked = false; - } - } - - /// <summary> - /// Configures the caching. - /// </summary> - /// <param name="response">The response.</param> - /// <param name="responseInfo">The response info.</param> - private void ConfigureCaching(HttpListenerResponse response, ResponseInfo responseInfo) - { - if (responseInfo.CacheDuration.Ticks > 0) - { - response.Headers[HttpResponseHeader.CacheControl] = "public, max-age=" + Convert.ToInt32(responseInfo.CacheDuration.TotalSeconds); - } - else if (responseInfo.Etag.HasValue) - { - response.Headers[HttpResponseHeader.CacheControl] = "public"; - } - else - { - response.Headers[HttpResponseHeader.CacheControl] = "no-cache, no-store, must-revalidate"; - response.Headers[HttpResponseHeader.Pragma] = "no-cache, no-store, must-revalidate"; - } - - AddExpiresHeader(response, responseInfo); - } - - /// <summary> - /// Adds the expires header. - /// </summary> - /// <param name="response">The response.</param> - /// <param name="responseInfo">The response info.</param> - private void AddExpiresHeader(HttpListenerResponse response, ResponseInfo responseInfo) - { - if (responseInfo.CacheDuration.Ticks > 0) - { - response.Headers[HttpResponseHeader.Expires] = DateTime.UtcNow.Add(responseInfo.CacheDuration).ToString("r"); - } - else if (!responseInfo.Etag.HasValue) - { - response.Headers[HttpResponseHeader.Expires] = "-1"; - } - } - - /// <summary> - /// Adds the age header. - /// </summary> - /// <param name="response">The response.</param> - /// <param name="responseInfo">The response info.</param> - private void AddAgeHeader(HttpListenerResponse response, ResponseInfo responseInfo) - { - if (responseInfo.DateLastModified.HasValue) - { - response.Headers[HttpResponseHeader.Age] = Convert.ToInt32((DateTime.UtcNow - responseInfo.DateLastModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture); - } - } - - /// <summary> - /// Writes the response to output stream. - /// </summary> - /// <param name="stream">The stream.</param> - /// <param name="responseInfo">The response info.</param> - /// <param name="contentLength">Length of the content.</param> - /// <returns>Task.</returns> - protected abstract Task WriteResponseToOutputStream(Stream stream, ResponseInfo responseInfo, long? contentLength); - - /// <summary> - /// Disposes the response stream. - /// </summary> - protected virtual void DisposeResponseStream() - { - if (CompressedStream != null) - { - try - { - CompressedStream.Dispose(); - } - catch (Exception ex) - { - //Logger.ErrorException("Error disposing compressed stream", ex); - } - } - - try - { - //HttpListenerContext.Response.OutputStream.Dispose(); - HttpListenerContext.Response.Close(); - } - catch (Exception ex) - { - //Logger.ErrorException("Error disposing response", ex); - } - } - - /// <summary> - /// Determines whether [is cache valid] [the specified if modified since]. - /// </summary> - /// <param name="ifModifiedSince">If modified since.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="dateModified">The date modified.</param> - /// <returns><c>true</c> if [is cache valid] [the specified if modified since]; otherwise, <c>false</c>.</returns> - private bool IsCacheValid(DateTime ifModifiedSince, TimeSpan cacheDuration, DateTime? dateModified) - { - if (dateModified.HasValue) - { - DateTime lastModified = NormalizeDateForComparison(dateModified.Value); - ifModifiedSince = NormalizeDateForComparison(ifModifiedSince); - - return lastModified <= ifModifiedSince; - } - - DateTime cacheExpirationDate = ifModifiedSince.Add(cacheDuration); - - if (DateTime.UtcNow < cacheExpirationDate) - { - return true; - } - - return false; - } - - /// <summary> - /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that - /// </summary> - /// <param name="date">The date.</param> - /// <returns>DateTime.</returns> - private DateTime NormalizeDateForComparison(DateTime date) - { - return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind); - } - - /// <summary> - /// Gets the total length of the content. - /// </summary> - /// <param name="responseInfo">The response info.</param> - /// <returns>System.Nullable{System.Int64}.</returns> - protected virtual long? GetTotalContentLength(ResponseInfo responseInfo) - { - return null; - } - - /// <summary> - /// Gets the response info. - /// </summary> - /// <returns>Task{ResponseInfo}.</returns> - protected abstract Task<ResponseInfo> GetResponseInfo(); - - /// <summary> - /// Gets a bool query string param. - /// </summary> - /// <param name="name">The name.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - protected bool GetBoolQueryStringParam(string name) - { - var val = QueryString[name] ?? string.Empty; - - return val.Equals("1", StringComparison.OrdinalIgnoreCase) || val.Equals("true", StringComparison.OrdinalIgnoreCase); - } - - /// <summary> - /// The _form values - /// </summary> - private Hashtable _formValues; - - /// <summary> - /// Gets a value from form POST data - /// </summary> - /// <param name="name">The name.</param> - /// <returns>Task{System.String}.</returns> - protected async Task<string> GetFormValue(string name) - { - if (_formValues == null) - { - _formValues = await GetFormValues(HttpListenerContext.Request).ConfigureAwait(false); - } - - if (_formValues.ContainsKey(name)) - { - return _formValues[name].ToString(); - } - - return null; - } - - /// <summary> - /// Extracts form POST data from a request - /// </summary> - /// <param name="request">The request.</param> - /// <returns>Task{Hashtable}.</returns> - private async Task<Hashtable> GetFormValues(HttpListenerRequest request) - { - var formVars = new Hashtable(); - - if (request.HasEntityBody) - { - if (request.ContentType.IndexOf("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) != -1) - { - using (var requestBody = request.InputStream) - { - using (var reader = new StreamReader(requestBody, request.ContentEncoding)) - { - var s = await reader.ReadToEndAsync().ConfigureAwait(false); - - var pairs = s.Split('&'); - - foreach (var pair in pairs) - { - var index = pair.IndexOf('='); - - if (index != -1) - { - var name = pair.Substring(0, index); - var value = pair.Substring(index + 1); - formVars.Add(name, value); - } - } - } - } - } - } - - return formVars; - } - } - - /// <summary> - /// Class ResponseInfo - /// </summary> - public class ResponseInfo - { - /// <summary> - /// Gets or sets the type of the content. - /// </summary> - /// <value>The type of the content.</value> - public string ContentType { get; set; } - /// <summary> - /// Gets or sets the etag. - /// </summary> - /// <value>The etag.</value> - public Guid? Etag { get; set; } - /// <summary> - /// Gets or sets the date last modified. - /// </summary> - /// <value>The date last modified.</value> - public DateTime? DateLastModified { get; set; } - /// <summary> - /// Gets or sets the duration of the cache. - /// </summary> - /// <value>The duration of the cache.</value> - public TimeSpan CacheDuration { get; set; } - /// <summary> - /// Gets or sets a value indicating whether [compress response]. - /// </summary> - /// <value><c>true</c> if [compress response]; otherwise, <c>false</c>.</value> - public bool CompressResponse { get; set; } - /// <summary> - /// Gets or sets the status code. - /// </summary> - /// <value>The status code.</value> - public int StatusCode { get; set; } - /// <summary> - /// Gets or sets a value indicating whether [supports byte range requests]. - /// </summary> - /// <value><c>true</c> if [supports byte range requests]; otherwise, <c>false</c>.</value> - public bool SupportsByteRangeRequests { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="ResponseInfo" /> class. - /// </summary> - public ResponseInfo() - { - CacheDuration = TimeSpan.FromTicks(0); - - CompressResponse = true; - - StatusCode = 200; - } - - /// <summary> - /// Gets a value indicating whether this instance is response valid. - /// </summary> - /// <value><c>true</c> if this instance is response valid; otherwise, <c>false</c>.</value> - public bool IsResponseValid - { - get - { - return StatusCode >= 200 && StatusCode < 300; - } - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Common/Net/Handlers/IHttpServerHandler.cs b/MediaBrowser.Common/Net/Handlers/IHttpServerHandler.cs deleted file mode 100644 index dadd61473..000000000 --- a/MediaBrowser.Common/Net/Handlers/IHttpServerHandler.cs +++ /dev/null @@ -1,32 +0,0 @@ -using MediaBrowser.Common.Kernel; -using System.Net; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net.Handlers -{ - /// <summary> - /// Interface IHttpServerHandler - /// </summary> - public interface IHttpServerHandler - { - /// <summary> - /// Initializes the specified kernel. - /// </summary> - /// <param name="kernel">The kernel.</param> - void Initialize(IKernel kernel); - - /// <summary> - /// Handleses the request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - bool HandlesRequest(HttpListenerRequest request); - - /// <summary> - /// Processes the request. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <returns>Task.</returns> - Task ProcessRequest(HttpListenerContext ctx); - } -} diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs deleted file mode 100644 index 3967d15c3..000000000 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ /dev/null @@ -1,264 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Kernel; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net.Handlers -{ - /// <summary> - /// Represents an http handler that serves static content - /// </summary> - public class StaticFileHandler : BaseHandler<IKernel> - { - /// <summary> - /// Initializes a new instance of the <see cref="StaticFileHandler" /> class. - /// </summary> - /// <param name="kernel">The kernel.</param> - public StaticFileHandler(IKernel kernel) - { - Initialize(kernel); - } - - /// <summary> - /// The _path - /// </summary> - private string _path; - /// <summary> - /// Gets or sets the path to the static resource - /// </summary> - /// <value>The path.</value> - public string Path - { - get - { - if (!string.IsNullOrWhiteSpace(_path)) - { - return _path; - } - - return QueryString["path"]; - } - set - { - _path = value; - } - } - - /// <summary> - /// Gets or sets the last date modified of the resource - /// </summary> - /// <value>The last date modified.</value> - public DateTime? LastDateModified { get; set; } - - /// <summary> - /// Gets or sets the content type of the resource - /// </summary> - /// <value>The type of the content.</value> - public string ContentType { get; set; } - - /// <summary> - /// Gets or sets the content type of the resource - /// </summary> - /// <value>The etag.</value> - public Guid Etag { get; set; } - - /// <summary> - /// Gets or sets the source stream of the resource - /// </summary> - /// <value>The source stream.</value> - public Stream SourceStream { get; set; } - - /// <summary> - /// Shoulds the compress response. - /// </summary> - /// <param name="contentType">Type of the content.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool ShouldCompressResponse(string contentType) - { - // It will take some work to support compression with byte range requests - if (IsRangeRequest) - { - return false; - } - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Don't compress images - if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return true; - } - - /// <summary> - /// Gets or sets the duration of the cache. - /// </summary> - /// <value>The duration of the cache.</value> - public TimeSpan? CacheDuration { get; set; } - - /// <summary> - /// Gets the total length of the content. - /// </summary> - /// <param name="responseInfo">The response info.</param> - /// <returns>System.Nullable{System.Int64}.</returns> - protected override long? GetTotalContentLength(ResponseInfo responseInfo) - { - // If we're compressing the response, content length must be the compressed length, which we don't know - if (responseInfo.CompressResponse && ClientSupportsCompression) - { - return null; - } - - return SourceStream.Length; - } - - /// <summary> - /// Gets the response info. - /// </summary> - /// <returns>Task{ResponseInfo}.</returns> - protected override Task<ResponseInfo> GetResponseInfo() - { - var info = new ResponseInfo - { - ContentType = ContentType ?? MimeTypes.GetMimeType(Path), - Etag = Etag, - DateLastModified = LastDateModified - }; - - if (SourceStream == null && !string.IsNullOrEmpty(Path)) - { - // FileShare must be ReadWrite in case someone else is currently writing to it. - SourceStream = new FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous); - } - - info.CompressResponse = ShouldCompressResponse(info.ContentType); - - info.SupportsByteRangeRequests = !info.CompressResponse || !ClientSupportsCompression; - - if (!info.DateLastModified.HasValue && !string.IsNullOrWhiteSpace(Path)) - { - info.DateLastModified = File.GetLastWriteTimeUtc(Path); - } - - if (CacheDuration.HasValue) - { - info.CacheDuration = CacheDuration.Value; - } - - if (SourceStream == null && string.IsNullOrEmpty(Path)) - { - throw new ResourceNotFoundException(); - } - - return Task.FromResult(info); - } - - /// <summary> - /// Writes the response to output stream. - /// </summary> - /// <param name="stream">The stream.</param> - /// <param name="responseInfo">The response info.</param> - /// <param name="totalContentLength">Total length of the content.</param> - /// <returns>Task.</returns> - protected override Task WriteResponseToOutputStream(Stream stream, ResponseInfo responseInfo, long? totalContentLength) - { - if (IsRangeRequest && totalContentLength.HasValue) - { - var requestedRange = RequestedRanges.First(); - - // If the requested range is "0-", we can optimize by just doing a stream copy - if (!requestedRange.Value.HasValue) - { - return ServeCompleteRangeRequest(requestedRange, stream, totalContentLength.Value); - } - - // This will have to buffer a portion of the content into memory - return ServePartialRangeRequest(requestedRange.Key, requestedRange.Value.Value, stream, totalContentLength.Value); - } - - return SourceStream.CopyToAsync(stream); - } - - /// <summary> - /// Disposes the response stream. - /// </summary> - protected override void DisposeResponseStream() - { - if (SourceStream != null) - { - SourceStream.Dispose(); - } - - base.DisposeResponseStream(); - } - - /// <summary> - /// Handles a range request of "bytes=0-" - /// This will serve the complete content and add the content-range header - /// </summary> - /// <param name="requestedRange">The requested range.</param> - /// <param name="responseStream">The response stream.</param> - /// <param name="totalContentLength">Total length of the content.</param> - /// <returns>Task.</returns> - private Task ServeCompleteRangeRequest(KeyValuePair<long, long?> requestedRange, Stream responseStream, long totalContentLength) - { - var rangeStart = requestedRange.Key; - var rangeEnd = totalContentLength - 1; - var rangeLength = 1 + rangeEnd - rangeStart; - - // Content-Length is the length of what we're serving, not the original content - HttpListenerContext.Response.ContentLength64 = rangeLength; - HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); - - if (rangeStart > 0) - { - SourceStream.Position = rangeStart; - } - - return SourceStream.CopyToAsync(responseStream); - } - - /// <summary> - /// Serves a partial range request - /// </summary> - /// <param name="rangeStart">The range start.</param> - /// <param name="rangeEnd">The range end.</param> - /// <param name="responseStream">The response stream.</param> - /// <param name="totalContentLength">Total length of the content.</param> - /// <returns>Task.</returns> - private async Task ServePartialRangeRequest(long rangeStart, long rangeEnd, Stream responseStream, long totalContentLength) - { - var rangeLength = 1 + rangeEnd - rangeStart; - - // Content-Length is the length of what we're serving, not the original content - HttpListenerContext.Response.ContentLength64 = rangeLength; - HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); - - SourceStream.Position = rangeStart; - - // Fast track to just copy the stream to the end - if (rangeEnd == totalContentLength - 1) - { - await SourceStream.CopyToAsync(responseStream).ConfigureAwait(false); - } - else - { - // Read the bytes we need - var buffer = new byte[Convert.ToInt32(rangeLength)]; - await SourceStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - await responseStream.WriteAsync(buffer, 0, Convert.ToInt32(rangeLength)).ConfigureAwait(false); - } - } - } -} diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index c968a65c8..4cff2eeb9 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Serialization; using System; @@ -17,22 +17,16 @@ namespace MediaBrowser.Common.Plugins where TConfigurationType : BasePluginConfiguration { /// <summary> - /// Gets the kernel. + /// Gets the application paths. /// </summary> - /// <value>The kernel.</value> - protected IKernel Kernel { get; private set; } + /// <value>The application paths.</value> + protected IApplicationPaths ApplicationPaths { get; private set; } /// <summary> /// Gets the XML serializer. /// </summary> /// <value>The XML serializer.</value> protected IXmlSerializer XmlSerializer { get; private set; } - - /// <summary> - /// Gets or sets the plugin's current context - /// </summary> - /// <value>The context.</value> - protected KernelContext Context { get { return Kernel.KernelContext; } } /// <summary> /// Gets the name of the plugin @@ -174,7 +168,7 @@ namespace MediaBrowser.Common.Plugins { get { - return Path.Combine(Kernel.ApplicationPaths.PluginsPath, AssemblyFileName); + return Path.Combine(ApplicationPaths.PluginsPath, AssemblyFileName); } } @@ -199,7 +193,7 @@ namespace MediaBrowser.Common.Plugins get { // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => Kernel.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath) as TConfigurationType); + LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => ConfigurationHelper.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath, XmlSerializer) as TConfigurationType); return _configuration; } protected set @@ -230,7 +224,7 @@ namespace MediaBrowser.Common.Plugins { get { - return Path.Combine(Kernel.ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName); + return Path.Combine(ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName); } } @@ -250,7 +244,7 @@ namespace MediaBrowser.Common.Plugins { // Give the folder name the same name as the config file name // We can always make this configurable if/when needed - _dataFolderPath = Path.Combine(Kernel.ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(ConfigurationFileName)); + _dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(ConfigurationFileName)); if (!Directory.Exists(_dataFolderPath)) { @@ -265,11 +259,11 @@ namespace MediaBrowser.Common.Plugins /// <summary> /// Initializes a new instance of the <see cref="BasePlugin{TConfigurationType}" /> class. /// </summary> - /// <param name="kernel">The kernel.</param> + /// <param name="applicationPaths">The application paths.</param> /// <param name="xmlSerializer">The XML serializer.</param> - protected BasePlugin(IKernel kernel, IXmlSerializer xmlSerializer) + protected BasePlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) { - Kernel = kernel; + ApplicationPaths = applicationPaths; XmlSerializer = xmlSerializer; } @@ -284,11 +278,6 @@ namespace MediaBrowser.Common.Plugins /// <exception cref="System.InvalidOperationException">Cannot call Plugin.SaveConfiguration from the UI.</exception> public virtual void SaveConfiguration() { - if (Kernel.KernelContext != KernelContext.Server) - { - throw new InvalidOperationException("Cannot call Plugin.SaveConfiguration from the UI."); - } - lock (_configurationSaveLock) { XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath); diff --git a/MediaBrowser.Common/Updates/ApplicationUpdater.cs b/MediaBrowser.Common/Updates/ApplicationUpdater.cs index e157c344b..a796e1bd2 100644 --- a/MediaBrowser.Common/Updates/ApplicationUpdater.cs +++ b/MediaBrowser.Common/Updates/ApplicationUpdater.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Kernel; namespace MediaBrowser.Common.Updates diff --git a/MediaBrowser.Common/Updates/IPackageManager.cs b/MediaBrowser.Common/Updates/IPackageManager.cs index 1db5ea706..ecaf9cef8 100644 --- a/MediaBrowser.Common/Updates/IPackageManager.cs +++ b/MediaBrowser.Common/Updates/IPackageManager.cs @@ -1,16 +1,8 @@ -using System; +using MediaBrowser.Model.Updates; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Security; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Updates; namespace MediaBrowser.Common.Updates { @@ -19,37 +11,17 @@ namespace MediaBrowser.Common.Updates /// <summary> /// Gets all available packages. /// </summary> - /// <param name="client"></param> - /// <param name="networkManager"></param> - /// <param name="securityManager"></param> - /// <param name="resourcePool"></param> - /// <param name="serializer"></param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{List{PackageInfo}}.</returns> - Task<IEnumerable<PackageInfo>> GetAvailablePackages(IHttpClient client, - INetworkManager networkManager, - ISecurityManager securityManager, - ResourcePool resourcePool, - IJsonSerializer serializer, - CancellationToken cancellationToken); + Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken); /// <summary> /// Installs a package. /// </summary> - /// <param name="client"></param> - /// <param name="logger"></param> - /// <param name="resourcePool"></param> /// <param name="progress"></param> - /// <param name="appPaths"></param> /// <param name="package">The package.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - Task InstallPackage(IHttpClient client, - ILogger logger, - ResourcePool resourcePool, - IProgress<double> progress, - IApplicationPaths appPaths, - PackageVersionInfo package, - CancellationToken cancellationToken); + Task InstallPackage(IProgress<double> progress, PackageVersionInfo package, CancellationToken cancellationToken); } } |
