Conflicts:
	MediaBrowser.Common.Implementations/BaseApplicationHost.cs
	MediaBrowser.ServerApplication/ApplicationHost.cs
This commit is contained in:
LukePulverenti 2013-02-27 11:57:14 -05:00
commit 6d5d291762
10 changed files with 266 additions and 221 deletions

View File

@ -1,3 +1,4 @@
<<<<<<< HEAD
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Implementations.HttpServer;
using MediaBrowser.Common.Implementations.Udp;
@ -6,6 +7,11 @@ using MediaBrowser.Common.Kernel;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Model.IO;
=======
using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Common.Kernel;
using MediaBrowser.Common.Updates;
>>>>>>> c9f48fe0d0d5cf4aec62df1d1e97f629967aff6f
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
@ -44,6 +50,11 @@ namespace MediaBrowser.Common.Implementations
/// </summary>
protected readonly Container Container = new Container();
/// <summary>
/// The package manager
/// </summary>
protected readonly IPackageManager PackageManager = new PackageManager();
/// <summary>
/// Gets assemblies that failed to load
/// </summary>

View File

@ -129,6 +129,7 @@
<Compile Include="ServerManager\ServerManager.cs" />
<Compile Include="ServerManager\WebSocketConnection.cs" />
<Compile Include="Udp\UdpServer.cs" />
<Compile Include="Updates\PackageManager.cs" />
<Compile Include="WebSocket\AlchemyServer.cs" />
<Compile Include="WebSocket\AlchemyWebSocket.cs" />
</ItemGroup>
@ -163,9 +164,7 @@
<Content Include="swagger-ui\swagger-ui.js" />
<Content Include="swagger-ui\swagger-ui.min.js" />
</ItemGroup>
<ItemGroup>
<Folder Include="Updates\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<PropertyGroup>

View File

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Kernel;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
using MediaBrowser.Common.Updates;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Common.Implementations.Updates
{
public class PackageManager : IPackageManager
{
public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(IHttpClient client,
INetworkManager networkManager,
ISecurityManager securityManager,
ResourcePool resourcePool,
IJsonSerializer serializer,
CancellationToken cancellationToken)
{
var data = new Dictionary<string, string> { { "key", securityManager.SupporterKey }, { "mac", networkManager.GetMacAddress() } };
using (var json = await client.Post(Constants.Constants.MBAdminUrl + "service/package/retrieveall", data, resourcePool.Mb, cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
var packages = serializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
foreach (var package in packages)
{
package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
.OrderByDescending(v => v.version).ToList();
}
return packages;
}
}
public async Task InstallPackage(IHttpClient client, ILogger logger, ResourcePool resourcePool, IProgress<double> progress, IZipClient zipClient, IApplicationPaths appPaths, PackageVersionInfo package, CancellationToken cancellationToken)
{
// Target based on if it is an archive or single assembly
// zip archives are assumed to contain directory structures relative to our ProgramDataPath
var isArchive = string.Equals(Path.GetExtension(package.sourceUrl), ".zip", StringComparison.OrdinalIgnoreCase);
var target = isArchive ? appPaths.ProgramDataPath : Path.Combine(appPaths.PluginsPath, package.targetFilename);
// Download to temporary file so that, if interrupted, it won't destroy the existing installation
var tempFile = await client.GetTempFile(package.sourceUrl, resourcePool.Mb, cancellationToken, progress).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
// Validate with a checksum
if (package.checksum != Guid.Empty) // support for legacy uploads for now
{
using (var crypto = new MD5CryptoServiceProvider())
using (var stream = new BufferedStream(File.OpenRead(tempFile), 100000))
{
var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty));
if (check != package.checksum)
{
throw new ApplicationException(string.Format("Download validation failed for {0}. Probably corrupted during transfer.", package.name));
}
}
}
cancellationToken.ThrowIfCancellationRequested();
// Success - move it to the real target based on type
if (isArchive)
{
try
{
zipClient.ExtractAll(tempFile, target, true);
}
catch (IOException e)
{
logger.ErrorException("Error attempting to extract archive from {0} to {1}", e, tempFile, target);
throw;
}
}
else
{
try
{
File.Copy(tempFile, target, true);
File.Delete(tempFile);
}
catch (IOException e)
{
logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target);
throw;
}
}
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Common.Constants
{
public static class Constants
{
public const string MBAdminUrl = "http://mb3admin.com/admin/";
}
}

View File

@ -47,6 +47,7 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Constants\Constants.cs" />
<Compile Include="Events\EventHelper.cs" />
<Compile Include="Extensions\BaseExtensions.cs" />
<Compile Include="Events\GenericEventArgs.cs" />
@ -104,7 +105,7 @@
<Compile Include="ScheduledTasks\IntervalTrigger.cs" />
<Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
<Compile Include="Security\ISecurityManager.cs" />
<Compile Include="Updates\IInstallationManager.cs" />
<Compile Include="Updates\IPackageManager.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

View File

@ -1,119 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Common.Updates
{
public interface IInstallationManager
{
/// <summary>
/// The current installations
/// </summary>
List<Tuple<InstallationInfo, CancellationTokenSource>> CurrentInstallations { get; set; }
/// <summary>
/// The completed installations
/// </summary>
ConcurrentBag<InstallationInfo> CompletedInstallations { get; set; }
/// <summary>
/// Occurs when [plugin uninstalled].
/// </summary>
event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
/// <summary>
/// Occurs when [plugin updated].
/// </summary>
event EventHandler<GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>>> PluginUpdated;
/// <summary>
/// Called when [plugin updated].
/// </summary>
/// <param name="plugin">The plugin.</param>
/// <param name="newVersion">The new version.</param>
void OnPluginUpdated(IPlugin plugin, PackageVersionInfo newVersion);
/// <summary>
/// Occurs when [plugin updated].
/// </summary>
event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
/// <summary>
/// Called when [plugin installed].
/// </summary>
/// <param name="package">The package.</param>
void OnPluginInstalled(PackageVersionInfo package);
/// <summary>
/// Gets all available packages.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="packageType">Type of the package.</param>
/// <param name="applicationVersion">The application version.</param>
/// <returns>Task{List{PackageInfo}}.</returns>
Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
PackageType? packageType = null,
Version applicationVersion = null);
/// <summary>
/// Gets the package.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="classification">The classification.</param>
/// <param name="version">The version.</param>
/// <returns>Task{PackageVersionInfo}.</returns>
Task<PackageVersionInfo> GetPackage(string name, PackageVersionClass classification, Version version);
/// <summary>
/// Gets the latest compatible version.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="classification">The classification.</param>
/// <returns>Task{PackageVersionInfo}.</returns>
Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, PackageVersionClass classification = PackageVersionClass.Release);
/// <summary>
/// Gets the latest compatible version.
/// </summary>
/// <param name="availablePackages">The available packages.</param>
/// <param name="name">The name.</param>
/// <param name="classification">The classification.</param>
/// <returns>PackageVersionInfo.</returns>
PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, PackageVersionClass classification = PackageVersionClass.Release);
/// <summary>
/// Gets the available plugin updates.
/// </summary>
/// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns>
Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(bool withAutoUpdateEnabled, CancellationToken cancellationToken);
/// <summary>
/// Installs the package.
/// </summary>
/// <param name="package">The package.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">package</exception>
Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
/// Uninstalls a plugin
/// </summary>
/// <param name="plugin">The plugin.</param>
/// <exception cref="System.ArgumentException"></exception>
void UninstallPlugin(IPlugin plugin);
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
void Dispose();
}
}

View File

@ -0,0 +1,57 @@
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
{
public interface IPackageManager
{
/// <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);
/// <summary>
/// Installs a package.
/// </summary>
/// <param name="client"></param>
/// <param name="logger"></param>
/// <param name="resourcePool"></param>
/// <param name="progress"></param>
/// <param name="zipClient"></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,
IZipClient zipClient,
IApplicationPaths appPaths,
PackageVersionInfo package,
CancellationToken cancellationToken);
}
}

View File

@ -33,11 +33,6 @@ namespace MediaBrowser.Controller
/// </summary>
public class Kernel : BaseKernel<ServerConfiguration, IServerApplicationPaths>
{
/// <summary>
/// The MB admin URL
/// </summary>
public const string MBAdminUrl = "http://mb3admin.com/admin/";
/// <summary>
/// Gets the instance.
/// </summary>
@ -72,7 +67,7 @@ namespace MediaBrowser.Controller
/// Gets the installation manager.
/// </summary>
/// <value>The installation manager.</value>
public IInstallationManager InstallationManager { get; private set; }
public InstallationManager InstallationManager { get; private set; }
/// <summary>
/// Gets or sets the file system manager.

View File

@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Updates
/// <summary>
/// Manages all install, uninstall and update operations (both plugins and system)
/// </summary>
public class InstallationManager : BaseManager<Kernel>, IInstallationManager
public class InstallationManager : BaseManager<Kernel>
{
/// <summary>
/// The current installations
@ -109,6 +109,11 @@ namespace MediaBrowser.Controller.Updates
/// </summary>
private readonly INetworkManager _networkManager;
/// <summary>
/// The package manager
/// </summary>
private readonly IPackageManager _packageManager;
/// <summary>
/// Gets the json serializer.
/// </summary>
@ -134,11 +139,12 @@ namespace MediaBrowser.Controller.Updates
/// <param name="httpClient">The HTTP client.</param>
/// <param name="zipClient">The zip client.</param>
/// <param name="networkManager">The network manager.</param>
/// <param name="packageManager">The package manager.</param>
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="logger">The logger.</param>
/// <param name="appHost">The app host.</param>
/// <exception cref="System.ArgumentNullException">zipClient</exception>
public InstallationManager(Kernel kernel, IHttpClient httpClient, IZipClient zipClient, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost)
public InstallationManager(Kernel kernel, IHttpClient httpClient, IZipClient zipClient, INetworkManager networkManager, IPackageManager packageManager, IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost)
: base(kernel)
{
if (zipClient == null)
@ -149,6 +155,10 @@ namespace MediaBrowser.Controller.Updates
{
throw new ArgumentNullException("networkManager");
}
if (packageManager == null)
{
throw new ArgumentNullException("packageManager");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
@ -168,6 +178,7 @@ namespace MediaBrowser.Controller.Updates
HttpClient = httpClient;
ApplicationHost = appHost;
_networkManager = networkManager;
_packageManager = packageManager;
_logger = logger;
ZipClient = zipClient;
}
@ -183,39 +194,26 @@ namespace MediaBrowser.Controller.Updates
PackageType? packageType = null,
Version applicationVersion = null)
{
var data = new Dictionary<string, string> { { "key", Kernel.SecurityManager.SupporterKey }, { "mac", _networkManager.GetMacAddress() } };
var packages = (await _packageManager.GetAvailablePackages(HttpClient, _networkManager, Kernel.SecurityManager, Kernel.ResourcePools, JsonSerializer, cancellationToken).ConfigureAwait(false)).ToList();
using (var json = await HttpClient.Post(Controller.Kernel.MBAdminUrl + "service/package/retrieveall", data, Kernel.ResourcePools.Mb, cancellationToken).ConfigureAwait(false))
if (packageType.HasValue)
{
cancellationToken.ThrowIfCancellationRequested();
var packages = JsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
packages = packages.Where(p => p.type == packageType.Value).ToList();
}
// If an app version was supplied, filter the versions for each package to only include supported versions
if (applicationVersion != null)
{
foreach (var package in packages)
{
package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
.OrderByDescending(v => v.version).ToList();
package.versions = package.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToList();
}
if (packageType.HasValue)
{
packages = packages.Where(p => p.type == packageType.Value).ToList();
}
// If an app version was supplied, filter the versions for each package to only include supported versions
if (applicationVersion != null)
{
foreach (var package in packages)
{
package.versions = package.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToList();
}
}
// Remove packages with no versions
packages = packages.Where(p => p.versions.Any()).ToList();
return packages;
}
// Remove packages with no versions
packages = packages.Where(p => p.versions.Any()).ToList();
return packages;
}
/// <summary>
@ -431,77 +429,31 @@ namespace MediaBrowser.Controller.Updates
/// <returns>Task.</returns>
private async Task InstallPackageInternal(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
{
// Target based on if it is an archive or single assembly
// zip archives are assumed to contain directory structures relative to our ProgramDataPath
var isArchive = string.Equals(Path.GetExtension(package.sourceUrl), ".zip", StringComparison.OrdinalIgnoreCase);
var target = isArchive ? Kernel.ApplicationPaths.ProgramDataPath : Path.Combine(Kernel.ApplicationPaths.PluginsPath, package.targetFilename);
// Do the install
await _packageManager.InstallPackage(HttpClient, _logger, Kernel.ResourcePools, progress, ZipClient, Kernel.ApplicationPaths, package, cancellationToken).ConfigureAwait(false);
// Download to temporary file so that, if interrupted, it won't destroy the existing installation
var tempFile = await HttpClient.GetTempFile(package.sourceUrl, Kernel.ResourcePools.Mb, cancellationToken, progress).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
// Validate with a checksum
if (package.checksum != Guid.Empty) // support for legacy uploads for now
// Do plugin-specific processing
if (!(Path.GetExtension(package.targetFilename) ?? "").Equals(".zip", StringComparison.OrdinalIgnoreCase))
{
using (var crypto = new MD5CryptoServiceProvider())
using (var stream = new BufferedStream(File.OpenRead(tempFile), 100000))
// Set last update time if we were installed before
var plugin = Kernel.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
if (plugin != null)
{
var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty));
if (check != package.checksum)
// Synchronize the UpdateClass value
if (plugin.Configuration.UpdateClass != package.classification)
{
throw new ApplicationException(string.Format("Download validation failed for {0}. Probably corrupted during transfer.", package.name));
plugin.Configuration.UpdateClass = package.classification;
plugin.SaveConfiguration();
}
OnPluginUpdated(plugin, package);
}
}
cancellationToken.ThrowIfCancellationRequested();
// Success - move it to the real target based on type
if (isArchive)
{
try
else
{
ZipClient.ExtractAll(tempFile, target, true);
OnPluginInstalled(package);
}
catch (IOException e)
{
_logger.ErrorException("Error attempting to extract archive from {0} to {1}", e, tempFile, target);
throw;
}
}
else
{
try
{
File.Copy(tempFile, target, true);
File.Delete(tempFile);
}
catch (IOException e)
{
_logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target);
throw;
}
}
// Set last update time if we were installed before
var plugin = Kernel.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
if (plugin != null)
{
// Synchronize the UpdateClass value
if (plugin.Configuration.UpdateClass != package.classification)
{
plugin.Configuration.UpdateClass = package.classification;
plugin.SaveConfiguration();
}
OnPluginUpdated(plugin, package);
}
else
{
OnPluginInstalled(package);
}
}

View File

@ -7,13 +7,15 @@ using MediaBrowser.Common.Implementations.Logging;
using MediaBrowser.Common.Implementations.NetworkManagement;
using MediaBrowser.Common.Implementations.ScheduledTasks;
using MediaBrowser.Common.Implementations.Serialization;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Implementations.ServerManager;
using MediaBrowser.Common.Implementations.Udp;
using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Common.Implementations.WebSocket;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Kernel;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
using MediaBrowser.IsoMounter;
using MediaBrowser.Model.IO;
@ -86,7 +88,13 @@ namespace MediaBrowser.ServerApplication
RegisterResources(taskManager, networkManager, serverManager);
<<<<<<< HEAD
FindParts();
=======
RegisterResources(taskManager, httpServer, networkManager, serverManager, PackageManager);
FindParts(taskManager, httpServer);
>>>>>>> c9f48fe0d0d5cf4aec62df1d1e97f629967aff6f
}
/// <summary>
@ -110,7 +118,11 @@ namespace MediaBrowser.ServerApplication
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
<<<<<<< HEAD
protected override void RegisterResources(ITaskManager taskManager, INetworkManager networkManager, IServerManager serverManager)
=======
private void RegisterResources(ITaskManager taskManager, IHttpServer httpServer, INetworkManager networkManager, IServerManager serverManager, IPackageManager packageManager)
>>>>>>> c9f48fe0d0d5cf4aec62df1d1e97f629967aff6f
{
base.RegisterResources(taskManager, networkManager, serverManager);
@ -126,7 +138,27 @@ namespace MediaBrowser.ServerApplication
RegisterSingleInstance<IZipClient>(new DotNetZipClient());
RegisterSingleInstance(_jsonSerializer);
RegisterSingleInstance(_xmlSerializer);
<<<<<<< HEAD
RegisterSingleInstance(ServerFactory.CreateServer(this, ProtobufSerializer, Logger, "Media Browser", "index.html"), false);
=======
RegisterSingleInstance(ProtobufSerializer);
RegisterSingleInstance<IUdpServer>(new UdpServer(Logger), false);
RegisterSingleInstance(httpServer, false);
RegisterSingleInstance(networkManager);
RegisterSingleInstance(serverManager);
RegisterSingleInstance(packageManager);
}
/// <summary>
/// Finds the parts.
/// </summary>
private void FindParts(ITaskManager taskManager, IHttpServer httpServer)
{
taskManager.AddTasks(GetExports<IScheduledTask>(false));
httpServer.Init(GetExports<IRestfulService>(false));
>>>>>>> c9f48fe0d0d5cf4aec62df1d1e97f629967aff6f
}
/// <summary>