diff options
93 files changed, 2450 insertions, 1576 deletions
diff --git a/MediaBrowser.ApiInteraction.Javascript/ApiClient.js b/MediaBrowser.Api/Javascript/ApiClient.js index df1c8f2c0..df1c8f2c0 100644 --- a/MediaBrowser.ApiInteraction.Javascript/ApiClient.js +++ b/MediaBrowser.Api/Javascript/ApiClient.js diff --git a/MediaBrowser.ApiInteraction.Javascript/JavascriptApiClientService.cs b/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs index c03146e69..8c7499a7c 100644 --- a/MediaBrowser.ApiInteraction.Javascript/JavascriptApiClientService.cs +++ b/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs @@ -5,13 +5,13 @@ using System; using System.IO; using System.Threading.Tasks; -namespace MediaBrowser.ApiInteraction.Javascript +namespace MediaBrowser.Api.Javascript { /// <summary> /// Class GetJavascriptApiClient /// </summary> [Route("/JsApiClient.js", "GET")] - [Api(("Gets an api wrapper in Javascript"))] + [ServiceStack.ServiceHost.Api(("Gets an api wrapper in Javascript"))] public class GetJavascriptApiClient { /// <summary> @@ -52,7 +52,7 @@ namespace MediaBrowser.ApiInteraction.Javascript /// <returns>Stream.</returns> private Task<Stream> GetStream() { - return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.ApiInteraction.Javascript.ApiClient.js")); + return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.Api.Javascript.ApiClient.js")); } } } diff --git a/MediaBrowser.Api/LibraryService.cs b/MediaBrowser.Api/LibraryService.cs index 4ca073c10..434b04eff 100644 --- a/MediaBrowser.Api/LibraryService.cs +++ b/MediaBrowser.Api/LibraryService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Net; +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -98,6 +99,26 @@ namespace MediaBrowser.Api public class LibraryService : BaseRestService { /// <summary> + /// The _app host + /// </summary> + private readonly IApplicationHost _appHost; + + /// <summary> + /// Initializes a new instance of the <see cref="LibraryService" /> class. + /// </summary> + /// <param name="appHost">The app host.</param> + /// <exception cref="System.ArgumentNullException">appHost</exception> + public LibraryService(IApplicationHost appHost) + { + if (appHost == null) + { + throw new ArgumentNullException("appHost"); + } + + _appHost = appHost; + } + + /// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> @@ -210,7 +231,7 @@ namespace MediaBrowser.Api { var kernel = (Kernel)Kernel; - var allTypes = kernel.AllTypes.Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(BaseItem))); + var allTypes = _appHost.AllConcreteTypes.Where(t => t.IsSubclassOf(typeof(BaseItem))); if (request.HasInternetProvider) { diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 9bdcdb650..c6c822624 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -80,6 +80,7 @@ <Compile Include="Images\ImageService.cs" /> <Compile Include="Images\ImageWriter.cs" /> <Compile Include="Images\UploadImageHandler.cs" /> + <Compile Include="Javascript\JavascriptApiClientService.cs" /> <Compile Include="LibraryService.cs" /> <Compile Include="LocalizationService.cs" /> <Compile Include="PackageService.cs" /> @@ -128,6 +129,7 @@ <None Include="packages.config" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="Javascript\ApiClient.js" /> <Content Include="options.xml" /> </ItemGroup> <ItemGroup /> diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index f982602bf..1f906f814 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -1,15 +1,15 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; -using MediaBrowser.Common.Serialization; using MediaBrowser.Controller; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Plugins; +using MediaBrowser.Model.Serialization; using ServiceStack.ServiceHost; +using ServiceStack.Text.Controller; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using ServiceStack.Text.Controller; namespace MediaBrowser.Api { @@ -120,6 +120,27 @@ namespace MediaBrowser.Api public class PluginService : BaseRestService { /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginService" /> class. + /// </summary> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">jsonSerializer</exception> + public PluginService(IJsonSerializer jsonSerializer) + : base() + { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + _jsonSerializer = jsonSerializer; + } + + /// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> @@ -198,7 +219,7 @@ namespace MediaBrowser.Api { var kernel = (Kernel)Kernel; - var info = JsonSerializer.DeserializeFromStream<PluginSecurityInfo>(request.RequestStream); + var info = _jsonSerializer.DeserializeFromStream<PluginSecurityInfo>(request.RequestStream); kernel.PluginSecurityManager.SupporterKey = info.SupporterKey; kernel.PluginSecurityManager.LegacyKey = info.LegacyKey; @@ -217,7 +238,7 @@ namespace MediaBrowser.Api var plugin = Kernel.Plugins.First(p => p.Id == id); - var configuration = JsonSerializer.DeserializeFromStream(request.RequestStream, plugin.ConfigurationType) as BasePluginConfiguration; + var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, plugin.ConfigurationType) as BasePluginConfiguration; plugin.UpdateConfiguration(configuration); } diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs index 1ca744542..e79ab90da 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs @@ -1,7 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.Serialization; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using ServiceStack.ServiceHost; using System; @@ -90,11 +90,32 @@ namespace MediaBrowser.Api.ScheduledTasks /// <value>The task manager.</value> private ITaskManager TaskManager { get; set; } - public ScheduledTaskService(ITaskManager taskManager) + /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// Initializes a new instance of the <see cref="ScheduledTaskService" /> class. + /// </summary> + /// <param name="taskManager">The task manager.</param> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">taskManager</exception> + public ScheduledTaskService(ITaskManager taskManager, IJsonSerializer jsonSerializer) { + if (taskManager == null) + { + throw new ArgumentNullException("taskManager"); + } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + TaskManager = taskManager; + _jsonSerializer = jsonSerializer; } - + /// <summary> /// Gets the specified request. /// </summary> @@ -113,6 +134,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// </summary> /// <param name="request">The request.</param> /// <returns>IEnumerable{TaskInfo}.</returns> + /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception> public object Get(GetScheduledTask request) { var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id); @@ -131,6 +153,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// Posts the specified request. /// </summary> /// <param name="request">The request.</param> + /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception> public void Post(StartScheduledTask request) { var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id); @@ -147,6 +170,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// Posts the specified request. /// </summary> /// <param name="request">The request.</param> + /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception> public void Delete(StopScheduledTask request) { var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id); @@ -163,6 +187,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// Posts the specified request. /// </summary> /// <param name="request">The request.</param> + /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception> public void Post(UpdateScheduledTaskTriggers request) { // We need to parse this manually because we told service stack not to with IRequiresRequestStream @@ -177,7 +202,7 @@ namespace MediaBrowser.Api.ScheduledTasks throw new ResourceNotFoundException("Task not found"); } - var triggerInfos = JsonSerializer.DeserializeFromStream<TaskTriggerInfo[]>(request.RequestStream); + var triggerInfos = _jsonSerializer.DeserializeFromStream<TaskTriggerInfo[]>(request.RequestStream); task.Triggers = triggerInfos.Select(ScheduledTaskHelpers.GetTrigger); } diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs index 04632aa8e..7921d024a 100644 --- a/MediaBrowser.Api/SystemService.cs +++ b/MediaBrowser.Api/SystemService.cs @@ -1,15 +1,19 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; -using MediaBrowser.Common.Serialization; using MediaBrowser.Controller; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using ServiceStack.ServiceHost; +using System; using System.IO; using System.Threading.Tasks; namespace MediaBrowser.Api { + /// <summary> + /// Class GetSystemInfo + /// </summary> [Route("/System/Info", "GET")] public class GetSystemInfo : IReturn<SystemInfo> { @@ -40,6 +44,10 @@ namespace MediaBrowser.Api [Route("/System/Configuration", "POST")] public class UpdateConfiguration : IRequiresRequestStream { + /// <summary> + /// The raw Http Request Input Stream + /// </summary> + /// <value>The request stream.</value> public Stream RequestStream { get; set; } } @@ -49,6 +57,27 @@ namespace MediaBrowser.Api public class SystemService : BaseRestService { /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// Initializes a new instance of the <see cref="SystemService" /> class. + /// </summary> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">jsonSerializer</exception> + public SystemService(IJsonSerializer jsonSerializer) + : base() + { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + _jsonSerializer = jsonSerializer; + } + + /// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> @@ -95,8 +124,8 @@ namespace MediaBrowser.Api /// <param name="request">The request.</param> public void Post(UpdateConfiguration request) { - var serverConfig = JsonSerializer.DeserializeFromStream<ServerConfiguration>(request.RequestStream); - + var serverConfig = _jsonSerializer.DeserializeFromStream<ServerConfiguration>(request.RequestStream); + var kernel = (Kernel)Kernel; kernel.UpdateConfiguration(serverConfig); diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 576ff8892..4267947ad 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -1,11 +1,11 @@ using MediaBrowser.Common.Net; -using MediaBrowser.Common.Serialization; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Serialization; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -28,7 +28,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the id. /// </summary> @@ -48,7 +48,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the item id. /// </summary> @@ -68,7 +68,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the id. /// </summary> @@ -106,7 +106,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the id. /// </summary> @@ -125,7 +125,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the id. /// </summary> @@ -144,7 +144,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the id. /// </summary> @@ -163,7 +163,7 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <value>The user id.</value> public Guid UserId { get; set; } - + /// <summary> /// Gets or sets the id. /// </summary> @@ -215,6 +215,9 @@ namespace MediaBrowser.Api.UserLibrary public string Id { get; set; } } + /// <summary> + /// Class GetLocalTrailers + /// </summary> [Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET")] public class GetLocalTrailers : IReturn<List<BaseItemDto>> { @@ -231,6 +234,9 @@ namespace MediaBrowser.Api.UserLibrary public string Id { get; set; } } + /// <summary> + /// Class GetSpecialFeatures + /// </summary> [Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")] public class GetSpecialFeatures : IReturn<List<BaseItemDto>> { @@ -253,6 +259,32 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> public class UserLibraryService : BaseRestService { + /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// Initializes a new instance of the <see cref="UserLibraryService" /> class. + /// </summary> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">jsonSerializer</exception> + public UserLibraryService(IJsonSerializer jsonSerializer) + : base() + { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + _jsonSerializer = jsonSerializer; + } + + /// <summary> + /// Gets the specified request. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>System.Object.</returns> public object Get(GetSpecialFeatures request) { var kernel = (Kernel)Kernel; @@ -260,7 +292,7 @@ namespace MediaBrowser.Api.UserLibrary var user = kernel.GetUserById(request.UserId); var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); - + // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); @@ -272,7 +304,12 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(items); } - + + /// <summary> + /// Gets the specified request. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>System.Object.</returns> public object Get(GetLocalTrailers request) { var kernel = (Kernel)Kernel; @@ -280,7 +317,7 @@ namespace MediaBrowser.Api.UserLibrary var user = kernel.GetUserById(request.UserId); var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); - + // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); @@ -290,7 +327,7 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(items); } - + /// <summary> /// Gets the specified request. /// </summary> @@ -303,7 +340,7 @@ namespace MediaBrowser.Api.UserLibrary var user = kernel.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, user.Id); - + // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); @@ -366,7 +403,7 @@ namespace MediaBrowser.Api.UserLibrary var item = (Folder)DtoBuilder.GetItemByClientId(itemId, user.Id); - var displayPreferences = JsonSerializer.DeserializeFromStream<DisplayPreferences>(request.RequestStream); + var displayPreferences = _jsonSerializer.DeserializeFromStream<DisplayPreferences>(request.RequestStream); var task = kernel.LibraryManager.SaveDisplayPreferencesForFolder(user, item, displayPreferences); diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index c76479d19..d4490d856 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -1,16 +1,16 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; -using MediaBrowser.Common.Serialization; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Serialization; using ServiceStack.ServiceHost; +using ServiceStack.Text.Controller; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using ServiceStack.Text.Controller; namespace MediaBrowser.Api { @@ -136,6 +136,39 @@ namespace MediaBrowser.Api public class UserService : BaseRestService { /// <summary> + /// The _XML serializer + /// </summary> + private readonly IXmlSerializer _xmlSerializer; + + /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// Initializes a new instance of the <see cref="UserService" /> class. + /// </summary> + /// <param name="xmlSerializer">The XML serializer.</param> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">xmlSerializer</exception> + public UserService(IXmlSerializer xmlSerializer, IJsonSerializer jsonSerializer) + : base() + { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + if (xmlSerializer == null) + { + throw new ArgumentNullException("xmlSerializer"); + } + + _jsonSerializer = jsonSerializer; + _xmlSerializer = xmlSerializer; + } + + /// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> @@ -262,10 +295,10 @@ namespace MediaBrowser.Api // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue<string>(1)); - + var kernel = (Kernel)Kernel; - var dtoUser = JsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream); + var dtoUser = _jsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream); var user = kernel.GetUserById(id); @@ -273,7 +306,7 @@ namespace MediaBrowser.Api Task.WaitAll(task); - user.UpdateConfiguration(dtoUser.Configuration); + user.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer); } /// <summary> @@ -285,7 +318,7 @@ namespace MediaBrowser.Api { var kernel = (Kernel)Kernel; - var dtoUser = JsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream); + var dtoUser = _jsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream); var newUser = kernel.UserManager.CreateUser(dtoUser.Name).Result; diff --git a/MediaBrowser.ApiInteraction.Javascript/MediaBrowser.ApiInteraction.Javascript.csproj b/MediaBrowser.ApiInteraction.Javascript/MediaBrowser.ApiInteraction.Javascript.csproj deleted file mode 100644 index 68e8c880d..000000000 --- a/MediaBrowser.ApiInteraction.Javascript/MediaBrowser.ApiInteraction.Javascript.csproj +++ /dev/null @@ -1,105 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProjectGuid>{767B536E-D90C-4D74-A14B-8564B16F3499}</ProjectGuid> - <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>MediaBrowser.ApiInteraction.Javascript</RootNamespace> - <AssemblyName>MediaBrowser.ApiInteraction.Javascript</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> - <FileAlignment>512</FileAlignment> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> - <RestorePackages>true</RestorePackages> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>false</Optimize> - <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> - <Optimize>true</Optimize> - <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <PropertyGroup> - <RunPostBuildEvent>Always</RunPostBuildEvent> - </PropertyGroup> - <ItemGroup> - <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite.SqlServer, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Redis, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath> - </Reference> - <Reference Include="System" /> - <Reference Include="System.Core" /> - <Reference Include="Microsoft.CSharp" /> - </ItemGroup> - <ItemGroup> - <Compile Include="..\SharedVersion.cs"> - <Link>Properties\SharedVersion.cs</Link> - </Compile> - <Compile Include="JavascriptApiClientService.cs" /> - <Compile Include="Properties\AssemblyInfo.cs" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> - <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project> - <Name>MediaBrowser.Common</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <EmbeddedResource Include="ApiClient.js" /> - </ItemGroup> - <ItemGroup> - <None Include="packages.config" /> - </ItemGroup> - <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> - <PropertyGroup> - <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\MediaBrowser.ServerApplication\CorePlugins\" /y</PostBuildEvent> - </PropertyGroup> - <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> - <!-- To modify your build process, add your task inside one of the targets below and uncomment it. - Other similar extension points exist, see Microsoft.Common.targets. - <Target Name="BeforeBuild"> - </Target> - <Target Name="AfterBuild"> - </Target> - --> -</Project>
\ No newline at end of file diff --git a/MediaBrowser.ApiInteraction.Javascript/Properties/AssemblyInfo.cs b/MediaBrowser.ApiInteraction.Javascript/Properties/AssemblyInfo.cs deleted file mode 100644 index 1a0333e49..000000000 --- a/MediaBrowser.ApiInteraction.Javascript/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MediaBrowser.ApiInteraction.Javascript")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("MediaBrowser.ApiInteraction.Javascript")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("97f9d4da-d7de-47d9-ae68-06d78679d327")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -//
\ No newline at end of file diff --git a/MediaBrowser.ApiInteraction.Javascript/packages.config b/MediaBrowser.ApiInteraction.Javascript/packages.config deleted file mode 100644 index ea25110aa..000000000 --- a/MediaBrowser.ApiInteraction.Javascript/packages.config +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<packages> - <package id="ServiceStack" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" /> -</packages>
\ No newline at end of file diff --git a/MediaBrowser.Common/Kernel/BaseApplicationPaths.cs b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs index 936c484c8..93478b22c 100644 --- a/MediaBrowser.Common/Kernel/BaseApplicationPaths.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs @@ -3,7 +3,7 @@ using System.Configuration; using System.IO; using System.Reflection; -namespace MediaBrowser.Common.Kernel +namespace MediaBrowser.Common.Implementations { /// <summary> /// Provides a base class to hold common application paths used by both the Ui and Server. diff --git a/MediaBrowser.Server.WorldWeatherOnline/MediaBrowser.Server.WorldWeatherOnline.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 1e97a482e..d271db060 100644 --- a/MediaBrowser.Server.WorldWeatherOnline/MediaBrowser.Server.WorldWeatherOnline.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -4,13 +4,15 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProjectGuid>{973CA45C-8362-490B-8327-C68098FD4891}</ProjectGuid> + <ProjectGuid>{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}</ProjectGuid> <OutputType>Library</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>MediaBrowser.Server.WorldWeatherOnline</RootNamespace> - <AssemblyName>MediaBrowser.Server.WorldWeatherOnline</AssemblyName> + <RootNamespace>MediaBrowser.Common.Implementations</RootNamespace> + <AssemblyName>MediaBrowser.Common.Implementations</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> + <RestorePackages>true</RestorePackages> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -29,39 +31,52 @@ <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> - <PropertyGroup> - <RunPostBuildEvent>Always</RunPostBuildEvent> - </PropertyGroup> <ItemGroup> + <Reference Include="protobuf-net"> + <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Text"> + <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath> + </Reference> <Reference Include="System" /> + <Reference Include="System.Configuration" /> <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> + <Compile Include="BaseApplicationPaths.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="WeatherProvider.cs" /> + <Compile Include="ScheduledTasks\TaskManager.cs" /> + <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" /> + <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" /> + <Compile Include="ScheduledTasks\Tasks\ReloadLoggerTask.cs" /> + <Compile Include="ScheduledTasks\Tasks\SystemUpdateTask.cs" /> + <Compile Include="Serialization\JsonSerializer.cs" /> + <Compile Include="Serialization\ProtobufSerializer.cs" /> + <Compile Include="Serialization\XmlSerializer.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project> <Name>MediaBrowser.Common</Name> </ProjectReference> - <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj"> - <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project> - <Name>MediaBrowser.Controller</Name> - </ProjectReference> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj"> <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project> <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> - <PropertyGroup> - <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\MediaBrowser.ServerApplication\CorePlugins\" /y</PostBuildEvent> - </PropertyGroup> + <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> diff --git a/MediaBrowser.Server.Sqlite/Properties/AssemblyInfo.cs b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs index 7c69b5544..f9c3e0bd1 100644 --- a/MediaBrowser.Server.Sqlite/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("MediaBrowser.Server.Sqlite")] +[assembly: AssemblyTitle("MediaBrowser.Common.Implementations")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("MediaBrowser.Server.Sqlite")] +[assembly: AssemblyProduct("MediaBrowser.Common.Implementations")] [assembly: AssemblyCopyright("Copyright © 2013")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f46c9f4b-24ed-49e1-be19-4b6242dd8382")] +[assembly: Guid("fc7d85c6-0fe7-4db6-8158-54f7b18f17cd")] // Version information for an assembly consists of the following four values: // @@ -28,4 +28,4 @@ using System.Runtime.InteropServices; // Minor Version // Build Number // Revision -//
\ No newline at end of file +// diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs new file mode 100644 index 000000000..c6eca29d1 --- /dev/null +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs @@ -0,0 +1,322 @@ +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Tasks; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Common.Implementations.ScheduledTasks +{ + /// <summary> + /// Class TaskManager + /// </summary> + public class TaskManager : ITaskManager + { + /// <summary> + /// Gets the list of Scheduled Tasks + /// </summary> + /// <value>The scheduled tasks.</value> + public IScheduledTask[] ScheduledTasks { get; private set; } + + /// <summary> + /// The _task queue + /// </summary> + private readonly List<Type> _taskQueue = new List<Type>(); + + /// <summary> + /// The _logger + /// </summary> + private readonly ILogger _logger; + + /// <summary> + /// The _application paths + /// </summary> + private readonly IApplicationPaths _applicationPaths; + + /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// Initializes a new instance of the <see cref="TaskManager" /> class. + /// </summary> + /// <param name="applicationPaths">The application paths.</param> + /// <param name="jsonSerializer">The json serializer.</param> + /// <param name="logger">The logger.</param> + /// <exception cref="System.ArgumentException">kernel</exception> + public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger) + { + if (applicationPaths == null) + { + throw new ArgumentException("applicationPaths"); + } + if (jsonSerializer == null) + { + throw new ArgumentException("jsonSerializer"); + } + if (logger == null) + { + throw new ArgumentException("logger"); + } + + _applicationPaths = applicationPaths; + _jsonSerializer = jsonSerializer; + _logger = logger; + + ScheduledTasks = new IScheduledTask[] {}; + } + + /// <summary> + /// Cancels if running and queue. + /// </summary> + /// <typeparam name="T"></typeparam> + public void CancelIfRunningAndQueue<T>() + where T : IScheduledTask + { + ScheduledTasks.OfType<T>().First().CancelIfRunning(); + QueueScheduledTask<T>(); + } + + /// <summary> + /// Queues the scheduled task. + /// </summary> + /// <typeparam name="T"></typeparam> + public void QueueScheduledTask<T>() + where T : IScheduledTask + { + var scheduledTask = ScheduledTasks.OfType<T>().First(); + + QueueScheduledTask(scheduledTask); + } + + /// <summary> + /// Queues the scheduled task. + /// </summary> + /// <param name="task">The task.</param> + public void QueueScheduledTask(IScheduledTask task) + { + var type = task.GetType(); + + var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); + + lock (_taskQueue) + { + // If it's idle just execute immediately + if (scheduledTask.State == TaskState.Idle) + { + scheduledTask.Execute(); + return; + } + + if (!_taskQueue.Contains(type)) + { + _logger.Info("Queueing task {0}", type.Name); + _taskQueue.Add(type); + } + else + { + _logger.Info("Task already queued: {0}", type.Name); + } + } + } + + /// <summary> + /// Called when [task completed]. + /// </summary> + /// <param name="task">The task.</param> + public void OnTaskCompleted(IScheduledTask task) + { + // Execute queued tasks + lock (_taskQueue) + { + var copy = _taskQueue.ToList(); + + foreach (var type in copy) + { + var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); + + if (scheduledTask.State == TaskState.Idle) + { + scheduledTask.Execute(); + + _taskQueue.Remove(type); + } + } + } + } + + /// <summary> + /// Adds the tasks. + /// </summary> + /// <param name="tasks">The tasks.</param> + public void AddTasks(IEnumerable<IScheduledTask> tasks) + { + var myTasks = ScheduledTasks.ToList(); + + myTasks.AddRange(tasks); + + ScheduledTasks = myTasks.ToArray(); + } + + /// <summary> + /// The _scheduled tasks configuration directory + /// </summary> + private string _scheduledTasksConfigurationDirectory; + /// <summary> + /// Gets the scheduled tasks configuration directory. + /// </summary> + /// <value>The scheduled tasks configuration directory.</value> + private string ScheduledTasksConfigurationDirectory + { + get + { + if (_scheduledTasksConfigurationDirectory == null) + { + _scheduledTasksConfigurationDirectory = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); + + if (!Directory.Exists(_scheduledTasksConfigurationDirectory)) + { + Directory.CreateDirectory(_scheduledTasksConfigurationDirectory); + } + } + return _scheduledTasksConfigurationDirectory; + } + } + + /// <summary> + /// The _scheduled tasks data directory + /// </summary> + private string _scheduledTasksDataDirectory; + /// <summary> + /// Gets the scheduled tasks data directory. + /// </summary> + /// <value>The scheduled tasks data directory.</value> + private string ScheduledTasksDataDirectory + { + get + { + if (_scheduledTasksDataDirectory == null) + { + _scheduledTasksDataDirectory = Path.Combine(_applicationPaths.DataPath, "ScheduledTasks"); + + if (!Directory.Exists(_scheduledTasksDataDirectory)) + { + Directory.CreateDirectory(_scheduledTasksDataDirectory); + } + } + return _scheduledTasksDataDirectory; + } + } + + /// <summary> + /// Gets the history file path. + /// </summary> + /// <value>The history file path.</value> + private string GetHistoryFilePath(IScheduledTask task) + { + return Path.Combine(ScheduledTasksDataDirectory, task.Id + ".js"); + } + + /// <summary> + /// Gets the configuration file path. + /// </summary> + /// <param name="task">The task.</param> + /// <returns>System.String.</returns> + private string GetConfigurationFilePath(IScheduledTask task) + { + return Path.Combine(ScheduledTasksConfigurationDirectory, task.Id + ".js"); + } + + /// <summary> + /// Called when [task completed]. + /// </summary> + /// <param name="task">The task.</param> + /// <param name="startTime">The start time.</param> + /// <param name="endTime">The end time.</param> + /// <param name="status">The status.</param> + public void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status) + { + var elapsedTime = endTime - startTime; + + _logger.Info("{0} {1} after {2} minute(s) and {3} seconds", task.Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); + + var result = new TaskResult + { + StartTimeUtc = startTime, + EndTimeUtc = endTime, + Status = status, + Name = task.Name, + Id = task.Id + }; + + _jsonSerializer.SerializeToFile(result, GetHistoryFilePath(task)); + + //task.LastExecutionResult = result; + } + + /// <summary> + /// Gets the last execution result. + /// </summary> + /// <param name="task">The task.</param> + /// <returns>TaskResult.</returns> + public TaskResult GetLastExecutionResult(IScheduledTask task) + { + return _jsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath(task)); + } + + /// <summary> + /// Loads the triggers. + /// </summary> + /// <param name="task">The task.</param> + /// <returns>IEnumerable{BaseTaskTrigger}.</returns> + public IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task) + { + try + { + return _jsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath(task)) + .Select(ScheduledTaskHelpers.GetTrigger) + .ToList(); + } + catch (IOException) + { + // File doesn't exist. No biggie. Return defaults. + return task.GetDefaultTriggers(); + } + } + + /// <summary> + /// Saves the triggers. + /// </summary> + /// <param name="task">The task.</param> + /// <param name="triggers">The triggers.</param> + public void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers) + { + _jsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath(task)); + } + + /// <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) + { + foreach (var task in ScheduledTasks) + { + task.Dispose(); + } + } + } +} diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index b06134ee2..2ef056658 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -7,7 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.ScheduledTasks.Tasks +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks { /// <summary> /// Deletes old cache files @@ -29,7 +30,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index 0b243cb10..dd00a7148 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -7,7 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.ScheduledTasks.Tasks +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks { /// <summary> /// Deletes old log files @@ -29,7 +30,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs index 35cbe98f1..79c633c76 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs @@ -1,11 +1,12 @@ using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.ScheduledTasks.Tasks +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks { /// <summary> /// Class ReloadLoggerFileTask @@ -27,7 +28,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// Gets the default triggers. /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(0) }; //12am diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs index f02293a5e..a101ad3dd 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs @@ -1,11 +1,12 @@ using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.ScheduledTasks.Tasks +namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks { /// <summary> /// Plugin Update Task @@ -34,9 +35,9 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { - return new BaseTaskTrigger[] { + return new ITaskTrigger[] { // 1am new DailyTrigger { TimeOfDay = TimeSpan.FromHours(1) }, diff --git a/MediaBrowser.Common/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs index 5b6e354a8..bc8935a86 100644 --- a/MediaBrowser.Common/Serialization/JsonSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs @@ -1,13 +1,19 @@ -using System; +using MediaBrowser.Model.Serialization; +using System; using System.IO; -namespace MediaBrowser.Common.Serialization +namespace MediaBrowser.Common.Implementations.Serialization { /// <summary> /// Provides a wrapper around third party json serialization. /// </summary> - public class JsonSerializer + public class JsonSerializer : IJsonSerializer { + public JsonSerializer() + { + Configure(); + } + /// <summary> /// Serializes to stream. /// </summary> @@ -15,7 +21,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="obj">The obj.</param> /// <param name="stream">The stream.</param> /// <exception cref="System.ArgumentNullException">obj</exception> - public static void SerializeToStream<T>(T obj, Stream stream) + public void SerializeToStream<T>(T obj, Stream stream) where T : class { if (obj == null) @@ -28,8 +34,6 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("stream"); } - Configure(); - ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); } @@ -40,7 +44,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="obj">The obj.</param> /// <param name="file">The file.</param> /// <exception cref="System.ArgumentNullException">obj</exception> - public static void SerializeToFile<T>(T obj, string file) + public void SerializeToFile<T>(T obj, string file) where T : class { if (obj == null) @@ -53,8 +57,6 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("file"); } - Configure(); - using (Stream stream = File.Open(file, FileMode.Create)) { SerializeToStream(obj, stream); @@ -68,7 +70,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="file">The file.</param> /// <returns>System.Object.</returns> /// <exception cref="System.ArgumentNullException">type</exception> - public static object DeserializeFromFile(Type type, string file) + public object DeserializeFromFile(Type type, string file) { if (type == null) { @@ -80,8 +82,6 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("file"); } - Configure(); - using (Stream stream = File.OpenRead(file)) { return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); @@ -95,7 +95,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="file">The file.</param> /// <returns>``0.</returns> /// <exception cref="System.ArgumentNullException">file</exception> - public static T DeserializeFromFile<T>(string file) + public T DeserializeFromFile<T>(string file) where T : class { if (string.IsNullOrEmpty(file)) @@ -103,8 +103,6 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("file"); } - Configure(); - using (Stream stream = File.OpenRead(file)) { return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream); @@ -118,15 +116,13 @@ namespace MediaBrowser.Common.Serialization /// <param name="stream">The stream.</param> /// <returns>``0.</returns> /// <exception cref="System.ArgumentNullException">stream</exception> - public static T DeserializeFromStream<T>(Stream stream) + public T DeserializeFromStream<T>(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } - Configure(); - return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream); } @@ -137,15 +133,13 @@ namespace MediaBrowser.Common.Serialization /// <param name="text">The text.</param> /// <returns>``0.</returns> /// <exception cref="System.ArgumentNullException">text</exception> - public static T DeserializeFromString<T>(string text) + public T DeserializeFromString<T>(string text) { if (string.IsNullOrEmpty(text)) { throw new ArgumentNullException("text"); } - Configure(); - return ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(text); } @@ -156,7 +150,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="type">The type.</param> /// <returns>System.Object.</returns> /// <exception cref="System.ArgumentNullException">stream</exception> - public static object DeserializeFromStream(Stream stream, Type type) + public object DeserializeFromStream(Stream stream, Type type) { if (stream == null) { @@ -168,27 +162,17 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("type"); } - Configure(); - return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); } /// <summary> - /// The _is configured - /// </summary> - private static bool _isConfigured; - /// <summary> /// Configures this instance. /// </summary> - internal static void Configure() + private void Configure() { - if (!_isConfigured) - { - ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601; - ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; - ServiceStack.Text.JsConfig.IncludeNullValues = false; - _isConfigured = true; - } + ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601; + ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; + ServiceStack.Text.JsConfig.IncludeNullValues = false; } /// <summary> @@ -198,7 +182,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="type">The type.</param> /// <returns>System.Object.</returns> /// <exception cref="System.ArgumentNullException">json</exception> - public static object DeserializeFromString(string json, Type type) + public object DeserializeFromString(string json, Type type) { if (string.IsNullOrEmpty(json)) { @@ -210,8 +194,6 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("type"); } - Configure(); - return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type); } @@ -222,7 +204,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="obj">The obj.</param> /// <returns>System.String.</returns> /// <exception cref="System.ArgumentNullException">obj</exception> - public static string SerializeToString<T>(T obj) + public string SerializeToString<T>(T obj) where T : class { if (obj == null) @@ -230,7 +212,6 @@ namespace MediaBrowser.Common.Serialization throw new ArgumentNullException("obj"); } - Configure(); return ServiceStack.Text.JsonSerializer.SerializeToString(obj, obj.GetType()); } @@ -241,7 +222,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="obj">The obj.</param> /// <returns>System.Byte[][].</returns> /// <exception cref="System.ArgumentNullException">obj</exception> - public static byte[] SerializeToBytes<T>(T obj) + public byte[] SerializeToBytes<T>(T obj) where T : class { if (obj == null) diff --git a/MediaBrowser.Common/Serialization/DynamicProtobufSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs index 359cf9da0..85325f3c1 100644 --- a/MediaBrowser.Common/Serialization/DynamicProtobufSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs @@ -1,22 +1,23 @@ -using ProtoBuf; +using MediaBrowser.Model.Serialization; +using ProtoBuf; using ProtoBuf.Meta; using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace MediaBrowser.Common.Serialization +namespace MediaBrowser.Common.Implementations.Serialization { /// <summary> /// Creates a compiled protobuf serializer based on a set of assemblies /// </summary> - public class DynamicProtobufSerializer + public class ProtobufSerializer : IProtobufSerializer { /// <summary> /// Gets or sets the type model. /// </summary> /// <value>The type model.</value> - public TypeModel TypeModel { get; set; } + private TypeModel TypeModel { get; set; } /// <summary> /// Serializes to stream. @@ -135,7 +136,7 @@ namespace MediaBrowser.Common.Serialization /// </summary> /// <returns>DynamicProtobufSerializer.</returns> /// <exception cref="System.ArgumentNullException">assemblies</exception> - public static DynamicProtobufSerializer Create(IEnumerable<Type> types) + public static ProtobufSerializer Create(IEnumerable<Type> types) { if (types == null) { @@ -151,7 +152,7 @@ namespace MediaBrowser.Common.Serialization model.Add(type, true); } - return new DynamicProtobufSerializer { TypeModel = model.Compile() }; + return new ProtobufSerializer { TypeModel = model.Compile() }; } } } diff --git a/MediaBrowser.Common/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs index 07010a5d2..d01199f6f 100644 --- a/MediaBrowser.Common/Serialization/XmlSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs @@ -1,35 +1,21 @@ -using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.IO; -using System.Linq; using System.Xml; -namespace MediaBrowser.Common.Serialization +namespace MediaBrowser.Common.Implementations.Serialization { /// <summary> /// Provides a wrapper around third party xml serialization. /// </summary> - public class XmlSerializer + public class XmlSerializer : IXmlSerializer { /// <summary> /// Serializes to writer. /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="obj">The obj.</param> - /// <param name="writer">The writer.</param> - public static void SerializeToWriter<T>(T obj, XmlTextWriter writer) - { - writer.Formatting = Formatting.Indented; - var netSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); - netSerializer.Serialize(writer, obj); - } - - /// <summary> - /// Serializes to writer. - /// </summary> /// <param name="obj">The obj.</param> /// <param name="writer">The writer.</param> - public static void SerializeToWriter(object obj, XmlTextWriter writer) + private void SerializeToWriter(object obj, XmlTextWriter writer) { writer.Formatting = Formatting.Indented; var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); @@ -42,7 +28,7 @@ namespace MediaBrowser.Common.Serialization /// <typeparam name="T"></typeparam> /// <param name="stream">The stream.</param> /// <returns>``0.</returns> - public static T DeserializeFromStream<T>(Stream stream) + public T DeserializeFromStream<T>(Stream stream) { using (var reader = new XmlTextReader(stream)) { @@ -58,7 +44,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="type">The type.</param> /// <param name="stream">The stream.</param> /// <returns>System.Object.</returns> - public static object DeserializeFromStream(Type type, Stream stream) + public object DeserializeFromStream(Type type, Stream stream) { using (var reader = new XmlTextReader(stream)) { @@ -73,7 +59,7 @@ namespace MediaBrowser.Common.Serialization /// </summary> /// <param name="obj">The obj.</param> /// <param name="stream">The stream.</param> - public static void SerializeToStream(object obj, Stream stream) + public void SerializeToStream(object obj, Stream stream) { using (var writer = new XmlTextWriter(stream, null)) { @@ -87,7 +73,7 @@ namespace MediaBrowser.Common.Serialization /// <typeparam name="T"></typeparam> /// <param name="file">The file.</param> /// <returns>``0.</returns> - public static T DeserializeFromFile<T>(string file) + public T DeserializeFromFile<T>(string file) { using (var stream = File.OpenRead(file)) { @@ -100,7 +86,7 @@ namespace MediaBrowser.Common.Serialization /// </summary> /// <param name="obj">The obj.</param> /// <param name="file">The file.</param> - public static void SerializeToFile(object obj, string file) + public void SerializeToFile(object obj, string file) { using (var stream = new FileStream(file, FileMode.Create)) { @@ -114,7 +100,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="type">The type.</param> /// <param name="file">The file.</param> /// <returns>System.Object.</returns> - public static object DeserializeFromFile(Type type, string file) + public object DeserializeFromFile(Type type, string file) { using (var stream = File.OpenRead(file)) { @@ -128,7 +114,7 @@ namespace MediaBrowser.Common.Serialization /// <param name="type">The type.</param> /// <param name="buffer">The buffer.</param> /// <returns>System.Object.</returns> - public static object DeserializeFromBytes(Type type, byte[] buffer) + public object DeserializeFromBytes(Type type, byte[] buffer) { using (var stream = new MemoryStream(buffer)) { @@ -141,7 +127,7 @@ namespace MediaBrowser.Common.Serialization /// </summary> /// <param name="obj">The obj.</param> /// <returns>System.Byte[][].</returns> - public static byte[] SerializeToBytes(object obj) + public byte[] SerializeToBytes(object obj) { using (var stream = new MemoryStream()) { @@ -150,63 +136,5 @@ namespace MediaBrowser.Common.Serialization return stream.ToArray(); } } - - /// <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="logger">The logger.</param> - /// <returns>System.Object.</returns> - public static object GetXmlConfiguration(Type type, string path, ILogger logger) - { - 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 = DeserializeFromBytes(type, buffer); - } - catch (FileNotFoundException) - { - configuration = Activator.CreateInstance(type); - } - - // Take the object we just got and serialize it back to bytes - var newBytes = 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> - /// <param name="logger">The logger.</param> - /// <returns>``0.</returns> - public static T GetXmlConfiguration<T>(string path, ILogger logger) - where T : class - { - return GetXmlConfiguration(typeof(T), path, logger) as T; - } } } diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config new file mode 100644 index 000000000..14eb42cac --- /dev/null +++ b/MediaBrowser.Common.Implementations/packages.config @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" /> + <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" /> +</packages>
\ No newline at end of file diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 28ccd8602..a5a9b46ec 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -2,16 +2,14 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -24,7 +22,7 @@ namespace MediaBrowser.Common.Kernel /// <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 : BaseApplicationPaths, new() + where TApplicationPathsType : IApplicationPaths { /// <summary> /// Occurs when [has pending restart changed]. @@ -129,7 +127,7 @@ namespace MediaBrowser.Common.Kernel get { // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration<TConfigurationType>(ApplicationPaths.SystemConfigurationFilePath, Logger)); + LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => GetXmlConfiguration<TConfigurationType>(ApplicationPaths.SystemConfigurationFilePath)); return _configuration; } protected set @@ -162,19 +160,6 @@ namespace MediaBrowser.Common.Kernel public TApplicationPathsType ApplicationPaths { get; private set; } /// <summary> - /// The _failed assembly loads - /// </summary> - private readonly List<string> _failedPluginAssemblies = new List<string>(); - /// <summary> - /// Gets the plugin assemblies that failed to load. - /// </summary> - /// <value>The failed assembly loads.</value> - public IEnumerable<string> FailedPluginAssemblies - { - get { return _failedPluginAssemblies; } - } - - /// <summary> /// Gets the list of currently loaded plugins /// </summary> /// <value>The plugins.</value> @@ -205,46 +190,6 @@ namespace MediaBrowser.Common.Kernel public IEnumerable<IRestfulService> RestServices { get; private set; } /// <summary> - /// The disposable parts - /// </summary> - private readonly List<IDisposable> _disposableParts = new List<IDisposable>(); - - /// <summary> - /// The _protobuf serializer initialized - /// </summary> - private bool _protobufSerializerInitialized; - /// <summary> - /// The _protobuf serializer sync lock - /// </summary> - private object _protobufSerializerSyncLock = new object(); - /// <summary> - /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection - /// </summary> - private DynamicProtobufSerializer _protobufSerializer; - /// <summary> - /// Gets the protobuf serializer. - /// </summary> - /// <value>The protobuf serializer.</value> - public DynamicProtobufSerializer ProtobufSerializer - { - get - { - // Lazy load - LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => DynamicProtobufSerializer.Create(AllTypes)); - return _protobufSerializer; - } - private set - { - _protobufSerializer = value; - - if (value == null) - { - _protobufSerializerInitialized = false; - } - } - } - - /// <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> @@ -301,42 +246,40 @@ namespace MediaBrowser.Common.Kernel protected IApplicationHost ApplicationHost { get; private set; } /// <summary> - /// Gets or sets the task manager. - /// </summary> - /// <value>The task manager.</value> - protected ITaskManager TaskManager { get; set; } - - /// <summary> - /// Gets the assemblies. + /// The _XML serializer /// </summary> - /// <value>The assemblies.</value> - protected Assembly[] Assemblies { get; private set; } - - /// <summary> - /// Gets all types. - /// </summary> - /// <value>All types.</value> - public Type[] AllTypes { get; private set; } + private readonly IXmlSerializer _xmlSerializer; /// <summary> /// Initializes a new instance of the <see cref="BaseKernel{TApplicationPathsType}" /> 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, ILogger logger) + protected BaseKernel(IApplicationHost appHost, TApplicationPathsType appPaths, IXmlSerializer xmlSerializer, ILogger logger) { if (appHost == null) { throw new ArgumentNullException("appHost"); } - + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + if (xmlSerializer == null) + { + throw new ArgumentNullException("xmlSerializer"); + } if (logger == null) { throw new ArgumentNullException("logger"); } + ApplicationPaths = appPaths; ApplicationHost = appHost; + _xmlSerializer = xmlSerializer; Logger = logger; } @@ -344,14 +287,12 @@ namespace MediaBrowser.Common.Kernel /// Initializes the Kernel /// </summary> /// <returns>Task.</returns> - public async Task Init() + public Task Init() { - ApplicationPaths = new TApplicationPathsType(); - IsFirstRun = !File.Exists(ApplicationPaths.SystemConfigurationFilePath); // Performs initializations that can be reloaded at anytime - await Reload().ConfigureAwait(false); + return Reload(); } /// <summary> @@ -377,7 +318,6 @@ namespace MediaBrowser.Common.Kernel { // Set these to null so that they can be lazy loaded again Configuration = null; - ProtobufSerializer = null; ReloadLogger(); @@ -388,14 +328,12 @@ namespace MediaBrowser.Common.Kernel await OnConfigurationLoaded().ConfigureAwait(false); - DisposeTaskManager(); - TaskManager = new TaskManager(Logger); + FindParts(); - Logger.Info("Loading Plugins"); - await ReloadComposableParts().ConfigureAwait(false); + await OnComposablePartsLoaded().ConfigureAwait(false); DisposeTcpManager(); - TcpManager = new TcpManager(ApplicationHost, this, ApplicationHost.Resolve<INetworkManager>(), Logger); + TcpManager = (TcpManager)ApplicationHost.CreateInstance(typeof(TcpManager)); } /// <summary> @@ -418,183 +356,13 @@ namespace MediaBrowser.Common.Kernel } /// <summary> - /// Uses MEF to locate plugins - /// Subclasses can use this to locate types within plugins - /// </summary> - /// <returns>Task.</returns> - private async Task ReloadComposableParts() - { - _failedPluginAssemblies.Clear(); - - DisposeComposableParts(); - - Assemblies = GetComposablePartAssemblies().ToArray(); - - AllTypes = Assemblies.SelectMany(GetTypes).ToArray(); - - ComposeParts(AllTypes); - - await OnComposablePartsLoaded().ConfigureAwait(false); - } - - /// <summary> - /// Composes the parts. - /// </summary> - /// <param name="allTypes">All types.</param> - private void ComposeParts(IEnumerable<Type> allTypes) - { - var concreteTypes = allTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray(); - - RegisterExportedValues(); - - FindParts(concreteTypes); - } - - /// <summary> /// Composes the parts with ioc container. /// </summary> - /// <param name="allTypes">All types.</param> - protected virtual void FindParts(Type[] allTypes) - { - RestServices = GetExports<IRestfulService>(allTypes); - WebSocketListeners = GetExports<IWebSocketListener>(allTypes); - Plugins = GetExports<IPlugin>(allTypes); - - var tasks = GetExports<IScheduledTask>(allTypes, false); - - TaskManager.AddTasks(tasks); - } - - /// <summary> - /// Gets the exports. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="allTypes">All types.</param> - /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param> - /// <returns>IEnumerable{``0}.</returns> - protected IEnumerable<T> GetExports<T>(Type[] allTypes, bool manageLiftime = true) - { - var currentType = typeof(T); - - Logger.Info("Composing instances of " + currentType.Name); - - var parts = allTypes.Where(currentType.IsAssignableFrom).Select(Instantiate).Cast<T>().ToArray(); - - if (manageLiftime) - { - _disposableParts.AddRange(parts.OfType<IDisposable>()); - } - - return parts; - } - - /// <summary> - /// Instantiates the specified type. - /// </summary> - /// <param name="type">The type.</param> - /// <returns>System.Object.</returns> - private object Instantiate(Type type) - { - return ApplicationHost.CreateInstance(type); - } - - /// <summary> - /// Composes the exported values. - /// </summary> - /// <param name="container">The container.</param> - protected virtual void RegisterExportedValues() + protected virtual void FindParts() { - ApplicationHost.RegisterSingleInstance<IKernel>(this); - ApplicationHost.RegisterSingleInstance(TaskManager); - } - - /// <summary> - /// Gets the composable part assemblies. - /// </summary> - /// <returns>IEnumerable{Assembly}.</returns> - protected virtual IEnumerable<Assembly> GetComposablePartAssemblies() - { - // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that - // This will prevent the .dll file from getting locked, and allow us to replace it when needed - var pluginAssemblies = Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) - .Select(file => - { - try - { - return Assembly.Load(File.ReadAllBytes((file))); - } - catch (Exception ex) - { - _failedPluginAssemblies.Add(file); - Logger.ErrorException("Error loading {0}", ex, file); - return null; - } - - }).Where(a => a != null); - - foreach (var pluginAssembly in pluginAssemblies) - { - yield return pluginAssembly; - } - - var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); - var corePluginDirectory = Path.Combine(runningDirectory, "CorePlugins"); - - // This will prevent the .dll file from getting locked, and allow us to replace it when needed - pluginAssemblies = Directory.EnumerateFiles(corePluginDirectory, "*.dll", SearchOption.TopDirectoryOnly) - .Select(file => - { - try - { - return Assembly.Load(File.ReadAllBytes((file))); - } - catch (Exception ex) - { - _failedPluginAssemblies.Add(file); - Logger.ErrorException("Error loading {0}", ex, file); - return null; - } - - }).Where(a => a != null); - - foreach (var pluginAssembly in pluginAssemblies) - { - yield return pluginAssembly; - } - - // Include composable parts in the Model assembly - yield return typeof(SystemInfo).Assembly; - - // Include composable parts in the Common assembly - yield return Assembly.GetExecutingAssembly(); - - // Include composable parts in the subclass assembly - yield return GetType().Assembly; - } - - /// <summary> - /// Gets a list of types within an assembly - /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference - /// </summary> - /// <param name="assembly">The assembly.</param> - /// <returns>IEnumerable{Type}.</returns> - /// <exception cref="System.ArgumentNullException">assembly</exception> - private static IEnumerable<Type> GetTypes(Assembly assembly) - { - if (assembly == null) - { - throw new ArgumentNullException("assembly"); - } - - try - { - return assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - // If it fails we can still get a list of the Types it was able to resolve - return ex.Types.Where(t => t != null); - } + RestServices = ApplicationHost.GetExports<IRestfulService>(); + WebSocketListeners = ApplicationHost.GetExports<IWebSocketListener>(); + Plugins = ApplicationHost.GetExports<IPlugin>(); } /// <summary> @@ -612,7 +380,7 @@ namespace MediaBrowser.Common.Kernel try { - plugin.Initialize(this, Logger); + plugin.Initialize(this, _xmlSerializer, Logger); Logger.Info("{0} {1} initialized.", plugin.Name, plugin.Version); } @@ -654,12 +422,7 @@ namespace MediaBrowser.Common.Kernel if (dispose) { DisposeTcpManager(); - DisposeTaskManager(); DisposeHttpManager(); - - DisposeComposableParts(); - - _disposableParts.Clear(); } } @@ -676,18 +439,6 @@ namespace MediaBrowser.Common.Kernel } /// <summary> - /// Disposes the task manager. - /// </summary> - private void DisposeTaskManager() - { - if (TaskManager != null) - { - TaskManager.Dispose(); - TaskManager = null; - } - } - - /// <summary> /// Disposes the HTTP manager. /// </summary> private void DisposeHttpManager() @@ -700,17 +451,6 @@ namespace MediaBrowser.Common.Kernel } /// <summary> - /// Disposes all objects gathered through MEF composable parts - /// </summary> - protected virtual void DisposeComposableParts() - { - foreach (var part in _disposableParts) - { - part.Dispose(); - } - } - - /// <summary> /// Gets the current application version /// </summary> /// <value>The application version.</value> @@ -761,7 +501,7 @@ namespace MediaBrowser.Common.Kernel IsNetworkDeployed = ApplicationHost.CanSelfUpdate, WebSocketPortNumber = TcpManager.WebSocketPortNumber, SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket, - FailedPluginAssemblies = FailedPluginAssemblies.ToArray() + FailedPluginAssemblies = ApplicationHost.FailedAssemblies.ToArray() }; } @@ -777,7 +517,7 @@ namespace MediaBrowser.Common.Kernel { lock (_configurationSaveLock) { - XmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath); + _xmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath); } OnConfigurationUpdated(); @@ -787,7 +527,7 @@ namespace MediaBrowser.Common.Kernel /// Gets the application paths. /// </summary> /// <value>The application paths.</value> - BaseApplicationPaths IKernel.ApplicationPaths + IApplicationPaths IKernel.ApplicationPaths { get { return ApplicationPaths; } } @@ -798,6 +538,63 @@ namespace MediaBrowser.Common.Kernel 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 = ApplicationHost.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; } } } diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/Kernel/IApplicationHost.cs index fe2f00a12..4b564581b 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/Kernel/IApplicationHost.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Updates; using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -33,6 +34,26 @@ namespace MediaBrowser.Common.Kernel bool CanSelfUpdate { get; } /// <summary> + /// Gets the failed assemblies. + /// </summary> + /// <value>The failed assemblies.</value> + IEnumerable<string> FailedAssemblies { get; } + + /// <summary> + /// Gets all concrete types. + /// </summary> + /// <value>All concrete types.</value> + Type[] AllConcreteTypes { get; } + + /// <summary> + /// Gets the exports. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param> + /// <returns>IEnumerable{``0}.</returns> + IEnumerable<T> GetExports<T>(bool manageLiftime = true); + + /// <summary> /// Checks for update. /// </summary> /// <returns>Task{CheckForUpdateResult}.</returns> diff --git a/MediaBrowser.Common/Kernel/IApplicationPaths.cs b/MediaBrowser.Common/Kernel/IApplicationPaths.cs new file mode 100644 index 000000000..abb783642 --- /dev/null +++ b/MediaBrowser.Common/Kernel/IApplicationPaths.cs @@ -0,0 +1,76 @@ + +namespace MediaBrowser.Common.Kernel +{ + /// <summary> + /// Interface IApplicationPaths + /// </summary> + public interface IApplicationPaths + { + /// <summary> + /// Gets the path to the program data folder + /// </summary> + /// <value>The program data path.</value> + string ProgramDataPath { get; } + + /// <summary> + /// Gets the folder path to the data directory + /// </summary> + /// <value>The data directory.</value> + string DataPath { get; } + + /// <summary> + /// Gets the image cache path. + /// </summary> + /// <value>The image cache path.</value> + string ImageCachePath { get; } + + /// <summary> + /// Gets the path to the plugin directory + /// </summary> + /// <value>The plugins path.</value> + string PluginsPath { get; } + + /// <summary> + /// Gets the path to the plugin configurations directory + /// </summary> + /// <value>The plugin configurations path.</value> + string PluginConfigurationsPath { get; } + + /// <summary> + /// Gets the path to where temporary update files will be stored + /// </summary> + /// <value>The plugin configurations path.</value> + string TempUpdatePath { get; } + + /// <summary> + /// Gets the path to the log directory + /// </summary> + /// <value>The log directory path.</value> + string LogDirectoryPath { get; } + + /// <summary> + /// Gets the path to the application configuration root directory + /// </summary> + /// <value>The configuration directory path.</value> + string ConfigurationDirectoryPath { get; } + + /// <summary> + /// Gets the path to the system configuration file + /// </summary> + /// <value>The system configuration file path.</value> + string SystemConfigurationFilePath { get; } + + /// <summary> + /// Gets the folder path to the cache directory + /// </summary> + /// <value>The cache directory.</value> + string CachePath { get; } + + /// <summary> + /// Gets the folder path to the temp directory within the cache folder + /// </summary> + /// <value>The temp directory.</value> + string TempDirectory { get; } + } + +} diff --git a/MediaBrowser.Common/Kernel/IKernel.cs b/MediaBrowser.Common/Kernel/IKernel.cs index 253368f4f..fb629a24d 100644 --- a/MediaBrowser.Common/Kernel/IKernel.cs +++ b/MediaBrowser.Common/Kernel/IKernel.cs @@ -1,6 +1,5 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.System; using System; @@ -18,7 +17,7 @@ namespace MediaBrowser.Common.Kernel /// Gets the application paths. /// </summary> /// <value>The application paths.</value> - BaseApplicationPaths ApplicationPaths { get; } + IApplicationPaths ApplicationPaths { get; } /// <summary> /// Gets the configuration. @@ -33,12 +32,6 @@ namespace MediaBrowser.Common.Kernel KernelContext KernelContext { get; } /// <summary> - /// Gets the protobuf serializer. - /// </summary> - /// <value>The protobuf serializer.</value> - DynamicProtobufSerializer ProtobufSerializer { get; } - - /// <summary> /// Inits this instance. /// </summary> /// <returns>Task.</returns> @@ -156,5 +149,13 @@ namespace MediaBrowser.Common.Kernel /// 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); } } diff --git a/MediaBrowser.Common/Kernel/TcpManager.cs b/MediaBrowser.Common/Kernel/TcpManager.cs index 9a998823f..c04b77599 100644 --- a/MediaBrowser.Common/Kernel/TcpManager.cs +++ b/MediaBrowser.Common/Kernel/TcpManager.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Net; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using System; @@ -14,6 +13,7 @@ using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Common.Kernel { @@ -36,6 +36,12 @@ namespace MediaBrowser.Common.Kernel private IHttpServer HttpServer { get; set; } /// <summary> + /// Gets or sets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + private IJsonSerializer _jsonSerializer; + + /// <summary> /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it /// </summary> /// <value>The HTTP listener.</value> @@ -96,8 +102,10 @@ namespace MediaBrowser.Common.Kernel /// <param name="applicationHost">The application host.</param> /// <param name="kernel">The kernel.</param> /// <param name="networkManager">The network manager.</param> + /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> - public TcpManager(IApplicationHost applicationHost, IKernel kernel, INetworkManager networkManager, ILogger logger) + /// <exception cref="System.ArgumentNullException">applicationHost</exception> + public TcpManager(IApplicationHost applicationHost, IKernel kernel, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger) { if (applicationHost == null) { @@ -111,12 +119,17 @@ namespace MediaBrowser.Common.Kernel { throw new ArgumentNullException("networkManager"); } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } if (logger == null) { throw new ArgumentNullException("logger"); } _logger = logger; + _jsonSerializer = jsonSerializer; _kernel = kernel; _applicationHost = applicationHost; _networkManager = networkManager; @@ -203,7 +216,7 @@ namespace MediaBrowser.Common.Kernel /// <param name="e">The <see cref="WebSocketConnectEventArgs" /> instance containing the event data.</param> void HttpServer_WebSocketConnected(object sender, WebSocketConnectEventArgs e) { - var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, ProcessWebSocketMessageReceived, _logger); + var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, ProcessWebSocketMessageReceived, _jsonSerializer, _logger); _webSocketConnections.Add(connection); } @@ -342,7 +355,7 @@ namespace MediaBrowser.Common.Kernel _logger.Info("Sending web socket message {0}", messageType); var message = new WebSocketMessage<T> { MessageType = messageType, Data = dataFunction() }; - var bytes = JsonSerializer.SerializeToBytes(message); + var bytes = _jsonSerializer.SerializeToBytes(message); var tasks = connections.Select(s => Task.Run(() => { diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 28789a816..f9147141d 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -38,10 +38,6 @@ </ApplicationIcon> </PropertyGroup> <ItemGroup> - <Reference Include="protobuf-net, Version=2.0.0.621, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath> - </Reference> <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath> @@ -75,14 +71,12 @@ <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath> </Reference> <Reference Include="System" /> - <Reference Include="System.Configuration" /> <Reference Include="System.Core" /> <Reference Include="System.Net" /> <Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http.WebRequest" /> <Reference Include="System.Web" /> <Reference Include="Microsoft.CSharp" /> - <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="..\SharedVersion.cs"> @@ -98,8 +92,8 @@ <Compile Include="IO\IIsoMount.cs" /> <Compile Include="IO\ProgressStream.cs" /> <Compile Include="IO\StreamDefaults.cs" /> - <Compile Include="Kernel\BaseApplicationPaths.cs" /> <Compile Include="Kernel\BasePeriodicWebSocketListener.cs" /> + <Compile Include="Kernel\IApplicationPaths.cs" /> <Compile Include="Kernel\IWebSocketListener.cs" /> <Compile Include="Kernel\IApplicationHost.cs" /> <Compile Include="Kernel\IKernel.cs" /> @@ -116,7 +110,6 @@ <Compile Include="Net\IWebSocket.cs" /> <Compile Include="Net\IWebSocketServer.cs" /> <Compile Include="Net\MimeTypes.cs" /> - <Compile Include="Net\NativeWebSocket.cs" /> <Compile Include="Net\UdpMessageReceivedEventArgs.cs" /> <Compile Include="Net\WebSocketConnectEventArgs.cs" /> <Compile Include="Net\WebSocketConnection.cs" /> @@ -130,26 +123,18 @@ <DependentUpon>Resources.resx</DependentUpon> </Compile> <Compile Include="ScheduledTasks\ITaskManager.cs" /> - <Compile Include="ScheduledTasks\TaskManager.cs" /> - <Compile Include="ScheduledTasks\Tasks\ReloadLoggerTask.cs" /> + <Compile Include="ScheduledTasks\ITaskTrigger.cs" /> <Compile Include="ScheduledTasks\ScheduledTaskHelpers.cs" /> <Compile Include="ScheduledTasks\StartupTrigger.cs" /> <Compile Include="ScheduledTasks\SystemEventTrigger.cs" /> - <Compile Include="ScheduledTasks\Tasks\SystemUpdateTask.cs" /> - <Compile Include="Serialization\DynamicProtobufSerializer.cs" /> - <Compile Include="Serialization\JsonSerializer.cs" /> <Compile Include="Kernel\BaseKernel.cs" /> <Compile Include="Kernel\KernelContext.cs" /> <Compile Include="Net\Handlers\BaseHandler.cs" /> <Compile Include="Net\Handlers\BaseSerializationHandler.cs" /> <Compile Include="Plugins\BasePlugin.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Serialization\XmlSerializer.cs" /> <Compile Include="ScheduledTasks\BaseScheduledTask.cs" /> - <Compile Include="ScheduledTasks\BaseTaskTrigger.cs" /> <Compile Include="ScheduledTasks\DailyTrigger.cs" /> - <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" /> - <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" /> <Compile Include="ScheduledTasks\IntervalTrigger.cs" /> <Compile Include="ScheduledTasks\IScheduledTask.cs" /> <Compile Include="ScheduledTasks\WeeklyTrigger.cs" /> diff --git a/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs index 293cb6e98..a00152d78 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs @@ -1,6 +1,5 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Serialization; using System; using System.IO; using System.Threading.Tasks; @@ -104,15 +103,15 @@ namespace MediaBrowser.Common.Net.Handlers { return Task.Run(() => { - switch (SerializationFormat) - { - case SerializationFormat.Protobuf: - Kernel.ProtobufSerializer.SerializeToStream(_objectToSerialize, stream); - break; - default: - JsonSerializer.SerializeToStream(_objectToSerialize, stream); - break; - } + //switch (SerializationFormat) + //{ + // case SerializationFormat.Protobuf: + // Kernel.ProtobufSerializer.SerializeToStream(_objectToSerialize, stream); + // break; + // default: + // JsonSerializer.SerializeToStream(_objectToSerialize, stream); + // break; + //} }); } } diff --git a/MediaBrowser.Common/Net/IWebSocket.cs b/MediaBrowser.Common/Net/IWebSocket.cs index 96299e3b2..3fd4b1241 100644 --- a/MediaBrowser.Common/Net/IWebSocket.cs +++ b/MediaBrowser.Common/Net/IWebSocket.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Common.Net /// Gets or sets the receive action. /// </summary> /// <value>The receive action.</value> - Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; } + Action<byte[]> OnReceiveDelegate { get; set; } /// <summary> /// Sends the async. diff --git a/MediaBrowser.Common/Net/WebSocketConnection.cs b/MediaBrowser.Common/Net/WebSocketConnection.cs index ab691c823..6b22ef78e 100644 --- a/MediaBrowser.Common/Net/WebSocketConnection.cs +++ b/MediaBrowser.Common/Net/WebSocketConnection.cs @@ -1,7 +1,7 @@ -using MediaBrowser.Common.Serialization; +using System.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; -using System.Net; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; @@ -39,13 +39,20 @@ namespace MediaBrowser.Common.Net private readonly ILogger _logger; /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> /// Initializes a new instance of the <see cref="WebSocketConnection" /> class. /// </summary> /// <param name="socket">The socket.</param> /// <param name="remoteEndPoint">The remote end point.</param> /// <param name="receiveAction">The receive action.</param> + /// <param name="jsonSerializer">The json serializer.</param> + /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">socket</exception> - public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, ILogger logger) + public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, IJsonSerializer jsonSerializer, ILogger logger) { if (socket == null) { @@ -59,11 +66,16 @@ namespace MediaBrowser.Common.Net { throw new ArgumentNullException("receiveAction"); } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } if (logger == null) { throw new ArgumentNullException("logger"); } + _jsonSerializer = jsonSerializer; _socket = socket; _socket.OnReceiveDelegate = info => OnReceive(info, receiveAction); RemoteEndPoint = remoteEndPoint; @@ -73,12 +85,19 @@ namespace MediaBrowser.Common.Net /// <summary> /// Called when [receive]. /// </summary> - /// <param name="info">The info.</param> + /// <param name="bytes">The bytes.</param> /// <param name="callback">The callback.</param> - private void OnReceive(WebSocketMessageInfo info, Action<WebSocketMessageInfo> callback) + private void OnReceive(byte[] bytes, Action<WebSocketMessageInfo> callback) { try { + WebSocketMessageInfo info; + + using (var memoryStream = new MemoryStream(bytes)) + { + info = _jsonSerializer.DeserializeFromStream<WebSocketMessageInfo>(memoryStream); + } + info.Connection = this; callback(info); @@ -103,8 +122,8 @@ namespace MediaBrowser.Common.Net { throw new ArgumentNullException("message"); } - - var bytes = JsonSerializer.SerializeToBytes(message); + + var bytes = _jsonSerializer.SerializeToBytes(message); return SendAsync(bytes, cancellationToken); } diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index d089aa1b3..dad3867fc 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Plugins; using System; @@ -7,6 +6,7 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Common.Plugins { @@ -188,7 +188,7 @@ namespace MediaBrowser.Common.Plugins get { // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath, Logger) as TConfigurationType); + LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => Kernel.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath) as TConfigurationType); return _configuration; } protected set @@ -270,25 +270,37 @@ namespace MediaBrowser.Common.Plugins public ILogger Logger { get; private set; } /// <summary> + /// Gets the XML serializer. + /// </summary> + /// <value>The XML serializer.</value> + protected IXmlSerializer XmlSerializer { get; private set; } + + /// <summary> /// Starts the plugin. /// </summary> /// <param name="kernel">The kernel.</param> + /// <param name="xmlSerializer">The XML serializer.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">kernel</exception> - public void Initialize(IKernel kernel, ILogger logger) + public void Initialize(IKernel kernel, IXmlSerializer xmlSerializer, ILogger logger) { if (kernel == null) { throw new ArgumentNullException("kernel"); } + if (xmlSerializer == null) + { + throw new ArgumentNullException("xmlSerializer"); + } + if (logger == null) { throw new ArgumentNullException("logger"); } - + + XmlSerializer = xmlSerializer; Logger = logger; - Kernel = kernel; if (kernel.KernelContext == KernelContext.Server) diff --git a/MediaBrowser.Common/Plugins/IPlugin.cs b/MediaBrowser.Common/Plugins/IPlugin.cs index 198678491..1b25cdcb1 100644 --- a/MediaBrowser.Common/Plugins/IPlugin.cs +++ b/MediaBrowser.Common/Plugins/IPlugin.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Kernel; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Plugins; +using MediaBrowser.Model.Serialization; using System; namespace MediaBrowser.Common.Plugins @@ -107,9 +108,10 @@ namespace MediaBrowser.Common.Plugins /// Starts the plugin. /// </summary> /// <param name="kernel">The kernel.</param> + /// <param name="xmlSerializer">The XML serializer.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">kernel</exception> - void Initialize(IKernel kernel, ILogger logger); + void Initialize(IKernel kernel, IXmlSerializer xmlSerializer, ILogger logger); /// <summary> /// Disposes the plugins. Undos all actions performed during Init. diff --git a/MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs b/MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs index 845faf31a..09ceaa9ae 100644 --- a/MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs @@ -1,6 +1,5 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Tasks; using System; @@ -90,7 +89,7 @@ namespace MediaBrowser.Common.ScheduledTasks { try { - return JsonSerializer.DeserializeFromFile<TaskResult>(HistoryFilePath); + return TaskManager.GetLastExecutionResult(this); } catch (IOException) { @@ -110,74 +109,6 @@ namespace MediaBrowser.Common.ScheduledTasks } /// <summary> - /// The _scheduled tasks data directory - /// </summary> - private string _scheduledTasksDataDirectory; - /// <summary> - /// Gets the scheduled tasks data directory. - /// </summary> - /// <value>The scheduled tasks data directory.</value> - private string ScheduledTasksDataDirectory - { - get - { - if (_scheduledTasksDataDirectory == null) - { - _scheduledTasksDataDirectory = Path.Combine(Kernel.ApplicationPaths.DataPath, "ScheduledTasks"); - - if (!Directory.Exists(_scheduledTasksDataDirectory)) - { - Directory.CreateDirectory(_scheduledTasksDataDirectory); - } - } - return _scheduledTasksDataDirectory; - } - } - - /// <summary> - /// The _scheduled tasks configuration directory - /// </summary> - private string _scheduledTasksConfigurationDirectory; - /// <summary> - /// Gets the scheduled tasks configuration directory. - /// </summary> - /// <value>The scheduled tasks configuration directory.</value> - private string ScheduledTasksConfigurationDirectory - { - get - { - if (_scheduledTasksConfigurationDirectory == null) - { - _scheduledTasksConfigurationDirectory = Path.Combine(Kernel.ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); - - if (!Directory.Exists(_scheduledTasksConfigurationDirectory)) - { - Directory.CreateDirectory(_scheduledTasksConfigurationDirectory); - } - } - return _scheduledTasksConfigurationDirectory; - } - } - - /// <summary> - /// Gets the configuration file path. - /// </summary> - /// <value>The configuration file path.</value> - private string ConfigurationFilePath - { - get { return Path.Combine(ScheduledTasksConfigurationDirectory, Id + ".js"); } - } - - /// <summary> - /// Gets the history file path. - /// </summary> - /// <value>The history file path.</value> - private string HistoryFilePath - { - get { return Path.Combine(ScheduledTasksDataDirectory, Id + ".js"); } - } - - /// <summary> /// Gets the current cancellation token /// </summary> /// <value>The current cancellation token source.</value> @@ -217,7 +148,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// The _triggers /// </summary> - private IEnumerable<BaseTaskTrigger> _triggers; + private IEnumerable<ITaskTrigger> _triggers; /// <summary> /// The _triggers initialized /// </summary> @@ -231,24 +162,11 @@ namespace MediaBrowser.Common.ScheduledTasks /// </summary> /// <value>The triggers.</value> /// <exception cref="System.ArgumentNullException">value</exception> - public IEnumerable<BaseTaskTrigger> Triggers + public IEnumerable<ITaskTrigger> Triggers { get { - LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () => - { - try - { - return JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(ConfigurationFilePath) - .Select(ScheduledTaskHelpers.GetTrigger) - .ToList(); - } - catch (IOException) - { - // File doesn't exist. No biggie. Return defaults. - return GetDefaultTriggers(); - } - }); + LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () => TaskManager.LoadTriggers(this)); return _triggers; } @@ -271,7 +189,7 @@ namespace MediaBrowser.Common.ScheduledTasks ReloadTriggerEvents(false); - JsonSerializer.SerializeToFile(_triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), ConfigurationFilePath); + TaskManager.SaveTriggers(this, _triggers); } } @@ -279,7 +197,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected abstract IEnumerable<BaseTaskTrigger> GetDefaultTriggers(); + public abstract IEnumerable<ITaskTrigger> GetDefaultTriggers(); /// <summary> /// Returns the task to be executed @@ -314,6 +232,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// The _id /// </summary> private Guid? _id; + /// <summary> /// Gets the unique id. /// </summary> @@ -352,13 +271,19 @@ namespace MediaBrowser.Common.ScheduledTasks /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> - void trigger_Triggered(object sender, EventArgs e) + async void trigger_Triggered(object sender, EventArgs e) { - var trigger = (BaseTaskTrigger)sender; + var trigger = (ITaskTrigger)sender; Logger.Info("{0} fired for task: {1}", trigger.GetType().Name, Name); + trigger.Stop(); + TaskManager.QueueScheduledTask(this); + + await Task.Delay(1000).ConfigureAwait(false); + + trigger.Start(false); } /// <summary> @@ -404,10 +329,9 @@ namespace MediaBrowser.Common.ScheduledTasks status = TaskCompletionStatus.Failed; } + var startTime = CurrentExecutionStartTime; var endTime = DateTime.UtcNow; - LogResult(endTime, status); - Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult); progress.ProgressChanged -= progress_ProgressChanged; @@ -415,33 +339,7 @@ namespace MediaBrowser.Common.ScheduledTasks CurrentCancellationTokenSource = null; CurrentProgress = null; - TaskManager.OnTaskCompleted(this); - } - - /// <summary> - /// Logs the result. - /// </summary> - /// <param name="endTime">The end time.</param> - /// <param name="status">The status.</param> - private void LogResult(DateTime endTime, TaskCompletionStatus status) - { - var startTime = CurrentExecutionStartTime; - var elapsedTime = endTime - startTime; - - Logger.Info("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); - - var result = new TaskResult - { - StartTimeUtc = startTime, - EndTimeUtc = endTime, - Status = status, - Name = Name, - Id = Id - }; - - JsonSerializer.SerializeToFile(result, HistoryFilePath); - - LastExecutionResult = result; + TaskManager.OnTaskCompleted(this, startTime, endTime, status); } /// <summary> @@ -501,7 +399,7 @@ namespace MediaBrowser.Common.ScheduledTasks if (State == TaskState.Running) { - LogResult(DateTime.UtcNow, TaskCompletionStatus.Aborted); + TaskManager.OnTaskCompleted(this, CurrentExecutionStartTime, DateTime.UtcNow, TaskCompletionStatus.Aborted); } if (CurrentCancellationTokenSource != null) @@ -519,7 +417,7 @@ namespace MediaBrowser.Common.ScheduledTasks foreach (var trigger in Triggers) { trigger.Triggered -= trigger_Triggered; - trigger.Dispose(); + trigger.Stop(); } } } diff --git a/MediaBrowser.Common/ScheduledTasks/BaseTaskTrigger.cs b/MediaBrowser.Common/ScheduledTasks/BaseTaskTrigger.cs deleted file mode 100644 index ed302ed39..000000000 --- a/MediaBrowser.Common/ScheduledTasks/BaseTaskTrigger.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.ScheduledTasks -{ - /// <summary> - /// Use to indicate that a scheduled task should run - /// </summary> - public abstract class BaseTaskTrigger : IDisposable - { - /// <summary> - /// Fires when the trigger condition is satisfied and the task should run - /// </summary> - internal event EventHandler<EventArgs> Triggered; - - /// <summary> - /// Called when [triggered]. - /// </summary> - protected async void OnTriggered() - { - Stop(); - - if (Triggered != null) - { - Triggered(this, EventArgs.Empty); - } - - await Task.Delay(1000).ConfigureAwait(false); - - Start(false); - } - - /// <summary> - /// Stars waiting for the trigger action - /// </summary> - protected internal abstract void Start(bool isApplicationStartup); - - /// <summary> - /// Stops waiting for the trigger action - /// </summary> - protected internal abstract void Stop(); - - /// <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) - { - if (dispose) - { - Stop(); - } - } - } -} diff --git a/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs b/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs index fb749f77c..bfecadee7 100644 --- a/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs +++ b/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Represents a task trigger that fires everyday /// </summary> - public class DailyTrigger : BaseTaskTrigger + public class DailyTrigger : ITaskTrigger { /// <summary> /// Get the time of day to trigger the task to run @@ -24,7 +24,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Stars waiting for the trigger action /// </summary> /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param> - protected internal override void Start(bool isApplicationStartup) + public void Start(bool isApplicationStartup) { DisposeTimer(); @@ -39,33 +39,35 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Stops waiting for the trigger action /// </summary> - protected internal override void Stop() + public void Stop() { DisposeTimer(); } /// <summary> - /// Disposes this instance. + /// Disposes the timer. /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected override void Dispose(bool dispose) + private void DisposeTimer() { - if (dispose) + if (Timer != null) { - DisposeTimer(); + Timer.Dispose(); } - - base.Dispose(dispose); } /// <summary> - /// Disposes the timer. + /// Occurs when [triggered]. /// </summary> - private void DisposeTimer() + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Called when [triggered]. + /// </summary> + private void OnTriggered() { - if (Timer != null) + if (Triggered != null) { - Timer.Dispose(); + Triggered(this, EventArgs.Empty); } } } diff --git a/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs b/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs index cba5fc5d0..6f3a3857f 100644 --- a/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Gets the triggers. /// </summary> /// <value>The triggers.</value> - IEnumerable<BaseTaskTrigger> Triggers { get; set; } + IEnumerable<ITaskTrigger> Triggers { get; set; } /// <summary> /// Gets the last execution result. @@ -75,5 +75,11 @@ namespace MediaBrowser.Common.ScheduledTasks /// Cancels if running. /// </summary> void CancelIfRunning(); + + /// <summary> + /// Gets the default triggers. + /// </summary> + /// <returns>IEnumerable{BaseTaskTrigger}.</returns> + IEnumerable<ITaskTrigger> GetDefaultTriggers(); } }
\ No newline at end of file diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs index 430208869..42d7020e6 100644 --- a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs +++ b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs @@ -1,4 +1,5 @@ -using System; +using MediaBrowser.Model.Tasks; +using System; using System.Collections.Generic; namespace MediaBrowser.Common.ScheduledTasks @@ -41,6 +42,30 @@ namespace MediaBrowser.Common.ScheduledTasks /// Called when [task completed]. /// </summary> /// <param name="task">The task.</param> - void OnTaskCompleted(IScheduledTask task); + /// <param name="startTime">The start time.</param> + /// <param name="endTime">The end time.</param> + /// <param name="status">The status.</param> + void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status); + + /// <summary> + /// Gets the last execution result. + /// </summary> + /// <param name="task">The task.</param> + /// <returns>TaskResult.</returns> + TaskResult GetLastExecutionResult(IScheduledTask task); + + /// <summary> + /// Loads the triggers. + /// </summary> + /// <param name="task">The task.</param> + /// <returns>IEnumerable{BaseTaskTrigger}.</returns> + IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task); + + /// <summary> + /// Saves the triggers. + /// </summary> + /// <param name="task">The task.</param> + /// <param name="triggers">The triggers.</param> + void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers); } }
\ No newline at end of file diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs b/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs new file mode 100644 index 000000000..66701650e --- /dev/null +++ b/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs @@ -0,0 +1,26 @@ +using System; + +namespace MediaBrowser.Common.ScheduledTasks +{ + /// <summary> + /// Interface ITaskTrigger + /// </summary> + public interface ITaskTrigger + { + /// <summary> + /// Fires when the trigger condition is satisfied and the task should run + /// </summary> + event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Stars waiting for the trigger action + /// </summary> + /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param> + void Start(bool isApplicationStartup); + + /// <summary> + /// Stops waiting for the trigger action + /// </summary> + void Stop(); + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs index 759447b10..cac6d1fa3 100644 --- a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs +++ b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Represents a task trigger that runs repeatedly on an interval /// </summary> - public class IntervalTrigger : BaseTaskTrigger + public class IntervalTrigger : ITaskTrigger { /// <summary> /// Gets or sets the interval. @@ -24,7 +24,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Stars waiting for the trigger action /// </summary> /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param> - protected internal override void Start(bool isApplicationStartup) + public void Start(bool isApplicationStartup) { DisposeTimer(); @@ -34,33 +34,35 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Stops waiting for the trigger action /// </summary> - protected internal override void Stop() + public void Stop() { DisposeTimer(); } /// <summary> - /// Disposes this instance. + /// Disposes the timer. /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected override void Dispose(bool dispose) + private void DisposeTimer() { - if (dispose) + if (Timer != null) { - DisposeTimer(); + Timer.Dispose(); } - - base.Dispose(dispose); } /// <summary> - /// Disposes the timer. + /// Occurs when [triggered]. /// </summary> - private void DisposeTimer() + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Called when [triggered]. + /// </summary> + private void OnTriggered() { - if (Timer != null) + if (Triggered != null) { - Timer.Dispose(); + Triggered(this, EventArgs.Empty); } } } diff --git a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs index 9942da17f..e67eb3626 100644 --- a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs +++ b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// </summary> /// <param name="trigger">The trigger.</param> /// <returns>TaskTriggerInfo.</returns> - public static TaskTriggerInfo GetTriggerInfo(BaseTaskTrigger trigger) + public static TaskTriggerInfo GetTriggerInfo(ITaskTrigger trigger) { var info = new TaskTriggerInfo { @@ -81,7 +81,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <returns>BaseTaskTrigger.</returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentException">Invalid trigger type: + info.Type</exception> - public static BaseTaskTrigger GetTrigger(TaskTriggerInfo info) + public static ITaskTrigger GetTrigger(TaskTriggerInfo info) { if (info.Type.Equals(typeof(DailyTrigger).Name, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs b/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs index a254d2be9..e48551425 100644 --- a/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs +++ b/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs @@ -1,17 +1,18 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace MediaBrowser.Common.ScheduledTasks { /// <summary> /// Class StartupTaskTrigger /// </summary> - public class StartupTrigger : BaseTaskTrigger + public class StartupTrigger : ITaskTrigger { /// <summary> /// Stars waiting for the trigger action /// </summary> /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param> - protected internal async override void Start(bool isApplicationStartup) + public async void Start(bool isApplicationStartup) { if (isApplicationStartup) { @@ -24,8 +25,24 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Stops waiting for the trigger action /// </summary> - protected internal override void Stop() + public void Stop() { } + + /// <summary> + /// Occurs when [triggered]. + /// </summary> + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Called when [triggered]. + /// </summary> + private void OnTriggered() + { + if (Triggered != null) + { + Triggered(this, EventArgs.Empty); + } + } } } diff --git a/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs b/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs index 45d1fae8e..751da0ca5 100644 --- a/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs +++ b/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Tasks; using Microsoft.Win32; +using System; using System.Threading.Tasks; namespace MediaBrowser.Common.ScheduledTasks @@ -7,7 +8,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Class SystemEventTrigger /// </summary> - public class SystemEventTrigger : BaseTaskTrigger + public class SystemEventTrigger : ITaskTrigger { /// <summary> /// Gets or sets the system event. @@ -19,7 +20,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Stars waiting for the trigger action /// </summary> /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param> - protected internal override void Start(bool isApplicationStartup) + public void Start(bool isApplicationStartup) { switch (SystemEvent) { @@ -32,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Stops waiting for the trigger action /// </summary> - protected internal override void Stop() + public void Stop() { SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; } @@ -52,5 +53,21 @@ namespace MediaBrowser.Common.ScheduledTasks OnTriggered(); } } + + /// <summary> + /// Occurs when [triggered]. + /// </summary> + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Called when [triggered]. + /// </summary> + private void OnTriggered() + { + if (Triggered != null) + { + Triggered(this, EventArgs.Empty); + } + } } } diff --git a/MediaBrowser.Common/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common/ScheduledTasks/TaskManager.cs deleted file mode 100644 index 946c42d2e..000000000 --- a/MediaBrowser.Common/ScheduledTasks/TaskManager.cs +++ /dev/null @@ -1,159 +0,0 @@ -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Tasks; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MediaBrowser.Common.ScheduledTasks -{ - /// <summary> - /// Class TaskManager - /// </summary> - internal class TaskManager : ITaskManager - { - /// <summary> - /// Gets the list of Scheduled Tasks - /// </summary> - /// <value>The scheduled tasks.</value> - public IScheduledTask[] ScheduledTasks { get; private set; } - - /// <summary> - /// The _task queue - /// </summary> - private readonly List<Type> _taskQueue = new List<Type>(); - - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="TaskManager" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - public TaskManager(ILogger logger) - { - if (logger == null) - { - throw new ArgumentException("logger"); - } - - _logger = logger; - - ScheduledTasks = new IScheduledTask[] {}; - } - - /// <summary> - /// Cancels if running and queue. - /// </summary> - /// <typeparam name="T"></typeparam> - public void CancelIfRunningAndQueue<T>() - where T : IScheduledTask - { - ScheduledTasks.OfType<T>().First().CancelIfRunning(); - QueueScheduledTask<T>(); - } - - /// <summary> - /// Queues the scheduled task. - /// </summary> - /// <typeparam name="T"></typeparam> - public void QueueScheduledTask<T>() - where T : IScheduledTask - { - var scheduledTask = ScheduledTasks.OfType<T>().First(); - - QueueScheduledTask(scheduledTask); - } - - /// <summary> - /// Queues the scheduled task. - /// </summary> - /// <param name="task">The task.</param> - public void QueueScheduledTask(IScheduledTask task) - { - var type = task.GetType(); - - var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); - - lock (_taskQueue) - { - // If it's idle just execute immediately - if (scheduledTask.State == TaskState.Idle) - { - scheduledTask.Execute(); - return; - } - - if (!_taskQueue.Contains(type)) - { - _logger.Info("Queueing task {0}", type.Name); - _taskQueue.Add(type); - } - else - { - _logger.Info("Task already queued: {0}", type.Name); - } - } - } - - /// <summary> - /// Called when [task completed]. - /// </summary> - /// <param name="task">The task.</param> - public void OnTaskCompleted(IScheduledTask task) - { - // Execute queued tasks - lock (_taskQueue) - { - var copy = _taskQueue.ToList(); - - foreach (var type in copy) - { - var scheduledTask = ScheduledTasks.First(t => t.GetType() == type); - - if (scheduledTask.State == TaskState.Idle) - { - scheduledTask.Execute(); - - _taskQueue.Remove(type); - } - } - } - } - - /// <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) - { - foreach (var task in ScheduledTasks) - { - task.Dispose(); - } - } - - /// <summary> - /// Adds the tasks. - /// </summary> - /// <param name="tasks">The tasks.</param> - public void AddTasks(IEnumerable<IScheduledTask> tasks) - { - var myTasks = ScheduledTasks.ToList(); - - myTasks.AddRange(tasks); - - ScheduledTasks = myTasks.ToArray(); - } - } -} diff --git a/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs b/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs index afeacc2b3..cfb3f1fab 100644 --- a/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs +++ b/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Represents a task trigger that fires on a weekly basis /// </summary> - public class WeeklyTrigger : BaseTaskTrigger + public class WeeklyTrigger : ITaskTrigger { /// <summary> /// Get the time of day to trigger the task to run @@ -30,7 +30,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Stars waiting for the trigger action /// </summary> /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param> - protected internal override void Start(bool isApplicationStartup) + public void Start(bool isApplicationStartup) { DisposeTimer(); @@ -69,33 +69,35 @@ namespace MediaBrowser.Common.ScheduledTasks /// <summary> /// Stops waiting for the trigger action /// </summary> - protected internal override void Stop() + public void Stop() { DisposeTimer(); } /// <summary> - /// Disposes this instance. + /// Disposes the timer. /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected override void Dispose(bool dispose) + private void DisposeTimer() { - if (dispose) + if (Timer != null) { - DisposeTimer(); + Timer.Dispose(); } - - base.Dispose(dispose); } /// <summary> - /// Disposes the timer. + /// Occurs when [triggered]. /// </summary> - private void DisposeTimer() + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Called when [triggered]. + /// </summary> + private void OnTriggered() { - if (Timer != null) + if (Triggered != null) { - Timer.Dispose(); + Triggered(this, EventArgs.Empty); } } } diff --git a/MediaBrowser.Common/packages.config b/MediaBrowser.Common/packages.config index 0ebaf6297..ea25110aa 100644 --- a/MediaBrowser.Common/packages.config +++ b/MediaBrowser.Common/packages.config @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" /> <package id="ServiceStack" version="3.9.37" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" /> <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" /> diff --git a/MediaBrowser.Controller/Drawing/ImageManager.cs b/MediaBrowser.Controller/Drawing/ImageManager.cs index a0ba9d550..766d56115 100644 --- a/MediaBrowser.Controller/Drawing/ImageManager.cs +++ b/MediaBrowser.Controller/Drawing/ImageManager.cs @@ -1,12 +1,12 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; -using MediaBrowser.Common.Kernel; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Drawing /// <summary> /// Class ImageManager /// </summary> - public class ImageManager : BaseManager<Kernel> + public class ImageManager : IDisposable { /// <summary> /// Gets the image size cache. @@ -58,19 +58,31 @@ namespace MediaBrowser.Controller.Drawing private readonly ILogger _logger; /// <summary> + /// The _protobuf serializer + /// </summary> + private readonly IProtobufSerializer _protobufSerializer; + + /// <summary> + /// The _kernel + /// </summary> + private readonly Kernel _kernel; + + /// <summary> /// Initializes a new instance of the <see cref="ImageManager" /> class. /// </summary> /// <param name="kernel">The kernel.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> /// <param name="logger">The logger.</param> - public ImageManager(Kernel kernel, ILogger logger) - : base(kernel) + public ImageManager(Kernel kernel, IProtobufSerializer protobufSerializer, ILogger logger) { + _protobufSerializer = protobufSerializer; _logger = logger; + _kernel = kernel; - ImageSizeCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "image-sizes")); - ResizedImageCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "resized-images")); - CroppedImageCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "cropped-images")); - EnhancedImageCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "enhanced-images")); + ImageSizeCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "image-sizes")); + ResizedImageCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "resized-images")); + CroppedImageCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "cropped-images")); + EnhancedImageCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "enhanced-images")); } /// <summary> @@ -276,7 +288,7 @@ namespace MediaBrowser.Controller.Drawing try { - var result = Kernel.ProtobufSerializer.DeserializeFromFile<int[]>(fullCachePath); + var result = _protobufSerializer.DeserializeFromFile<int[]>(fullCachePath); return new ImageSize { Width = result[0], Height = result[1] }; } @@ -305,7 +317,7 @@ namespace MediaBrowser.Controller.Drawing { var output = new[] { width, height }; - Kernel.ProtobufSerializer.SerializeToFile(output, cachePath); + _protobufSerializer.SerializeToFile(output, cachePath); } /// <summary> @@ -472,7 +484,7 @@ namespace MediaBrowser.Controller.Drawing throw new ArgumentNullException("item"); } - var supportedEnhancers = Kernel.ImageEnhancers.Where(i => i.Supports(item, imageType)).ToList(); + var supportedEnhancers = _kernel.ImageEnhancers.Where(i => i.Supports(item, imageType)).ToList(); // No enhancement - don't cache if (supportedEnhancers.Count == 0) @@ -526,7 +538,7 @@ namespace MediaBrowser.Controller.Drawing var dateModified = GetImageDateModified(item, imagePath); - var supportedEnhancers = Kernel.ImageEnhancers.Where(i => i.Supports(item, imageType)); + var supportedEnhancers = _kernel.ImageEnhancers.Where(i => i.Supports(item, imageType)); return GetImageCacheTag(imagePath, dateModified, supportedEnhancers, item, imageType); } @@ -600,11 +612,16 @@ namespace MediaBrowser.Controller.Drawing return result; } + public void Dispose() + { + Dispose(true); + } + /// <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 override void Dispose(bool dispose) + protected void Dispose(bool dispose) { if (dispose) { @@ -613,8 +630,6 @@ namespace MediaBrowser.Controller.Drawing CroppedImageCache.Dispose(); EnhancedImageCache.Dispose(); } - - base.Dispose(dispose); } } } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 426e7f18e..5abd3e5a8 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -1,15 +1,13 @@ using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Serialization; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Tasks; using System; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Controller.Entities { @@ -170,7 +168,7 @@ namespace MediaBrowser.Controller.Entities get { // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration<UserConfiguration>(ConfigurationFilePath, Logger)); + LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => (UserConfiguration)Kernel.Instance.GetXmlConfiguration(typeof(UserConfiguration), ConfigurationFilePath)); return _configuration; } private set @@ -338,9 +336,9 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Saves the current configuration to the file system /// </summary> - public void SaveConfiguration() + public void SaveConfiguration(IXmlSerializer serializer) { - XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath); + serializer.SerializeToFile(Configuration, ConfigurationFilePath); } /// <summary> @@ -376,8 +374,9 @@ namespace MediaBrowser.Controller.Entities /// Updates the configuration. /// </summary> /// <param name="config">The config.</param> + /// <param name="serializer">The serializer.</param> /// <exception cref="System.ArgumentNullException">config</exception> - public void UpdateConfiguration(UserConfiguration config) + public void UpdateConfiguration(UserConfiguration config, IXmlSerializer serializer) { if (config == null) { @@ -387,7 +386,7 @@ namespace MediaBrowser.Controller.Entities var customLibraryChanged = config.UseCustomLibrary != Configuration.UseCustomLibrary; Configuration = config; - SaveConfiguration(); + SaveConfiguration(serializer); // Force these to be lazy loaded again if (customLibraryChanged) diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs new file mode 100644 index 000000000..b5fcdef28 --- /dev/null +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -0,0 +1,85 @@ +using MediaBrowser.Common.Kernel; + +namespace MediaBrowser.Controller +{ + public interface IServerApplicationPaths : IApplicationPaths + { + /// <summary> + /// Gets the path to the base root media directory + /// </summary> + /// <value>The root folder path.</value> + string RootFolderPath { get; } + + /// <summary> + /// Gets the path to the default user view directory. Used if no specific user view is defined. + /// </summary> + /// <value>The default user views path.</value> + string DefaultUserViewsPath { get; } + + /// <summary> + /// Gets the path to localization data. + /// </summary> + /// <value>The localization path.</value> + string LocalizationPath { get; } + + /// <summary> + /// Gets the path to the Images By Name directory + /// </summary> + /// <value>The images by name path.</value> + string ImagesByNamePath { get; } + + /// <summary> + /// Gets the path to the People directory + /// </summary> + /// <value>The people path.</value> + string PeoplePath { get; } + + /// <summary> + /// Gets the path to the Genre directory + /// </summary> + /// <value>The genre path.</value> + string GenrePath { get; } + + /// <summary> + /// Gets the path to the Studio directory + /// </summary> + /// <value>The studio path.</value> + string StudioPath { get; } + + /// <summary> + /// Gets the path to the Year directory + /// </summary> + /// <value>The year path.</value> + string YearPath { get; } + + /// <summary> + /// Gets the path to the General IBN directory + /// </summary> + /// <value>The general path.</value> + string GeneralPath { get; } + + /// <summary> + /// Gets the path to the Ratings IBN directory + /// </summary> + /// <value>The ratings path.</value> + string RatingsPath { get; } + + /// <summary> + /// Gets the path to the user configuration directory + /// </summary> + /// <value>The user configuration directory path.</value> + string UserConfigurationDirectoryPath { get; } + + /// <summary> + /// Gets the FF MPEG stream cache path. + /// </summary> + /// <value>The FF MPEG stream cache path.</value> + string FFMpegStreamCachePath { get; } + + /// <summary> + /// Gets the folder path to tools + /// </summary> + /// <value>The media tools path.</value> + string MediaToolsPath { get; } + } +}
\ No newline at end of file diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 5ee590bde..d879b888b 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Plugins; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; @@ -16,6 +17,7 @@ using MediaBrowser.Controller.Updates; using MediaBrowser.Controller.Weather; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using System; using System.Collections.Generic; @@ -28,7 +30,7 @@ namespace MediaBrowser.Controller /// <summary> /// Class Kernel /// </summary> - public class Kernel : BaseKernel<ServerConfiguration, ServerApplicationPaths> + public class Kernel : BaseKernel<ServerConfiguration, IServerApplicationPaths> { /// <summary> /// The MB admin URL @@ -291,17 +293,24 @@ namespace MediaBrowser.Controller get { return 7359; } } + private readonly ITaskManager _taskManager; + /// <summary> /// Creates a kernel based on a Data path, which is akin to our current programdata path /// </summary> /// <param name="appHost">The app host.</param> + /// <param name="appPaths">The app paths.</param> + /// <param name="xmlSerializer">The XML serializer.</param> + /// <param name="taskManager">The task manager.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">isoManager</exception> - public Kernel(IApplicationHost appHost, ILogger logger) - : base(appHost, logger) + public Kernel(IApplicationHost appHost, IServerApplicationPaths appPaths, IXmlSerializer xmlSerializer, ITaskManager taskManager, ILogger logger) + : base(appHost, appPaths, xmlSerializer, logger) { Instance = this; + _taskManager = taskManager; + // For now there's no real way to inject this properly BaseItem.Logger = logger; Ratings.Logger = logger; @@ -311,20 +320,9 @@ namespace MediaBrowser.Controller } /// <summary> - /// Composes the exported values. - /// </summary> - protected override void RegisterExportedValues() - { - ApplicationHost.RegisterSingleInstance(this); - - base.RegisterExportedValues(); - } - - /// <summary> /// Composes the parts with ioc container. /// </summary> - /// <param name="allTypes">All types.</param> - protected override void FindParts(Type[] allTypes) + protected override void FindParts() { InstallationManager = (InstallationManager)ApplicationHost.CreateInstance(typeof(InstallationManager)); FFMpegManager = (FFMpegManager)ApplicationHost.CreateInstance(typeof(FFMpegManager)); @@ -335,21 +333,21 @@ namespace MediaBrowser.Controller UserDataManager = (UserDataManager)ApplicationHost.CreateInstance(typeof(UserDataManager)); PluginSecurityManager = (PluginSecurityManager)ApplicationHost.CreateInstance(typeof(PluginSecurityManager)); - base.FindParts(allTypes); - - EntityResolutionIgnoreRules = GetExports<IResolutionIgnoreRule>(allTypes); - UserDataRepositories = GetExports<IUserDataRepository>(allTypes); - UserRepositories = GetExports<IUserRepository>(allTypes); - DisplayPreferencesRepositories = GetExports<IDisplayPreferencesRepository>(allTypes); - ItemRepositories = GetExports<IItemRepository>(allTypes); - WeatherProviders = GetExports<IWeatherProvider>(allTypes); - IntroProviders = GetExports<IIntroProvider>(allTypes); - PluginConfigurationPages = GetExports<IPluginConfigurationPage>(allTypes); - ImageEnhancers = GetExports<IImageEnhancer>(allTypes).OrderBy(e => e.Priority).ToArray(); - PluginFolderCreators = GetExports<IVirtualFolderCreator>(allTypes); - StringFiles = GetExports<LocalizedStringData>(allTypes); - EntityResolvers = GetExports<IBaseItemResolver>(allTypes).OrderBy(e => e.Priority).ToArray(); - MetadataProviders = GetExports<BaseMetadataProvider>(allTypes).OrderBy(e => e.Priority).ToArray(); + base.FindParts(); + + EntityResolutionIgnoreRules = ApplicationHost.GetExports<IResolutionIgnoreRule>(); + UserDataRepositories = ApplicationHost.GetExports<IUserDataRepository>(); + UserRepositories = ApplicationHost.GetExports<IUserRepository>(); + DisplayPreferencesRepositories = ApplicationHost.GetExports<IDisplayPreferencesRepository>(); + ItemRepositories = ApplicationHost.GetExports<IItemRepository>(); + WeatherProviders = ApplicationHost.GetExports<IWeatherProvider>(); + IntroProviders = ApplicationHost.GetExports<IIntroProvider>(); + PluginConfigurationPages = ApplicationHost.GetExports<IPluginConfigurationPage>(); + ImageEnhancers = ApplicationHost.GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray(); + PluginFolderCreators = ApplicationHost.GetExports<IVirtualFolderCreator>(); + StringFiles = ApplicationHost.GetExports<LocalizedStringData>(); + EntityResolvers = ApplicationHost.GetExports<IBaseItemResolver>().OrderBy(e => e.Priority).ToArray(); + MetadataProviders = ApplicationHost.GetExports<BaseMetadataProvider>().OrderBy(e => e.Priority).ToArray(); } /// <summary> @@ -471,7 +469,7 @@ namespace MediaBrowser.Controller { DisposeFileSystemManager(); - FileSystemManager = new FileSystemManager(this, Logger, TaskManager); + FileSystemManager = new FileSystemManager(this, Logger, _taskManager); FileSystemManager.StartWatchers(); } @@ -570,11 +568,11 @@ namespace MediaBrowser.Controller ProviderManager.ValidateCurrentlyRunningProviders(); // Any number of configuration settings could change the way the library is refreshed, so do that now - TaskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>(); + _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>(); if (refreshPeopleAfterUpdate) { - TaskManager.CancelIfRunningAndQueue<PeopleValidationTask>(); + _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>(); } }); } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 35540020e..1e901055e 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -110,6 +110,7 @@ <Compile Include="IO\FileSystem.cs" /> <Compile Include="IO\FileSystemManager.cs" /> <Compile Include="IO\NativeMethods.cs" /> + <Compile Include="IServerApplicationPaths.cs" /> <Compile Include="Library\ChildrenChangedEventArgs.cs" /> <Compile Include="Library\DtoBuilder.cs" /> <Compile Include="Library\Profiler.cs" /> @@ -183,7 +184,6 @@ <Compile Include="ScheduledTasks\PeopleValidationTask.cs" /> <Compile Include="ScheduledTasks\PluginUpdateTask.cs" /> <Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" /> - <Compile Include="ServerApplicationPaths.cs" /> <Compile Include="Library\ItemResolveArgs.cs" /> <Compile Include="IO\DirectoryWatchers.cs" /> <Compile Include="IO\FileData.cs" /> diff --git a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs index 9c9b0e9f2..0f535208b 100644 --- a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs +++ b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs @@ -1,12 +1,10 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Serialization; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.ComponentModel; @@ -23,7 +21,7 @@ namespace MediaBrowser.Controller.MediaInfo /// <summary> /// Class FFMpegManager /// </summary> - public class FFMpegManager : BaseManager<Kernel> + public class FFMpegManager : IDisposable { /// <summary> /// Gets or sets the video image cache. @@ -47,30 +45,66 @@ namespace MediaBrowser.Controller.MediaInfo /// Gets or sets the zip client. /// </summary> /// <value>The zip client.</value> - private IZipClient ZipClient { get; set; } + private readonly IZipClient _zipClient; /// <summary> /// The _logger /// </summary> + private readonly Kernel _kernel; + + /// <summary> + /// The _logger + /// </summary> private readonly ILogger _logger; /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// The _protobuf serializer + /// </summary> + private readonly IProtobufSerializer _protobufSerializer; + + /// <summary> /// Initializes a new instance of the <see cref="FFMpegManager" /> class. /// </summary> /// <param name="kernel">The kernel.</param> /// <param name="zipClient">The zip client.</param> + /// <param name="jsonSerializer">The json serializer.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">zipClient</exception> - public FFMpegManager(Kernel kernel, IZipClient zipClient, ILogger logger) - : base(kernel) + public FFMpegManager(Kernel kernel, IZipClient zipClient, IJsonSerializer jsonSerializer, IProtobufSerializer protobufSerializer, ILogger logger) { + if (kernel == null) + { + throw new ArgumentNullException("kernel"); + } if (zipClient == null) { throw new ArgumentNullException("zipClient"); } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + if (protobufSerializer == null) + { + throw new ArgumentNullException("protobufSerializer"); + } + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + _kernel = kernel; + _zipClient = zipClient; + _jsonSerializer = jsonSerializer; + _protobufSerializer = protobufSerializer; _logger = logger; - ZipClient = zipClient; // Not crazy about this but it's the only way to suppress ffmpeg crash dialog boxes SetErrorMode(ErrorModes.SEM_FAILCRITICALERRORS | ErrorModes.SEM_NOALIGNMENTFAULTEXCEPT | ErrorModes.SEM_NOGPFAULTERRORBOX | ErrorModes.SEM_NOOPENFILEERRORBOX); @@ -82,11 +116,16 @@ namespace MediaBrowser.Controller.MediaInfo Task.Run(() => VersionedDirectoryPath = GetVersionedDirectoryPath()); } + public void Dispose() + { + Dispose(true); + } + /// <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 override void Dispose(bool dispose) + protected void Dispose(bool dispose) { if (dispose) { @@ -95,8 +134,6 @@ namespace MediaBrowser.Controller.MediaInfo AudioImageCache.Dispose(); VideoImageCache.Dispose(); } - - base.Dispose(dispose); } /// <summary> @@ -186,7 +223,7 @@ namespace MediaBrowser.Controller.MediaInfo { if (_videoImagesDataPath == null) { - _videoImagesDataPath = Path.Combine(Kernel.ApplicationPaths.DataPath, "ffmpeg-video-images"); + _videoImagesDataPath = Path.Combine(_kernel.ApplicationPaths.DataPath, "ffmpeg-video-images"); if (!Directory.Exists(_videoImagesDataPath)) { @@ -212,7 +249,7 @@ namespace MediaBrowser.Controller.MediaInfo { if (_audioImagesDataPath == null) { - _audioImagesDataPath = Path.Combine(Kernel.ApplicationPaths.DataPath, "ffmpeg-audio-images"); + _audioImagesDataPath = Path.Combine(_kernel.ApplicationPaths.DataPath, "ffmpeg-audio-images"); if (!Directory.Exists(_audioImagesDataPath)) { @@ -238,7 +275,7 @@ namespace MediaBrowser.Controller.MediaInfo { if (_subtitleCachePath == null) { - _subtitleCachePath = Path.Combine(Kernel.ApplicationPaths.CachePath, "ffmpeg-subtitles"); + _subtitleCachePath = Path.Combine(_kernel.ApplicationPaths.CachePath, "ffmpeg-subtitles"); if (!Directory.Exists(_subtitleCachePath)) { @@ -265,7 +302,7 @@ namespace MediaBrowser.Controller.MediaInfo var filename = resource.Substring(resource.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) + prefix.Length); - var versionedDirectoryPath = Path.Combine(Kernel.ApplicationPaths.MediaToolsPath, Path.GetFileNameWithoutExtension(filename)); + var versionedDirectoryPath = Path.Combine(_kernel.ApplicationPaths.MediaToolsPath, Path.GetFileNameWithoutExtension(filename)); if (!Directory.Exists(versionedDirectoryPath)) { @@ -287,7 +324,7 @@ namespace MediaBrowser.Controller.MediaInfo { using (var resourceStream = assembly.GetManifestResourceStream(zipFileResourcePath)) { - ZipClient.ExtractAll(resourceStream, targetPath, false); + _zipClient.ExtractAll(resourceStream, targetPath, false); } } @@ -353,7 +390,7 @@ namespace MediaBrowser.Controller.MediaInfo // Avoid File.Exists by just trying to deserialize try { - return Task.FromResult(Kernel.ProtobufSerializer.DeserializeFromFile<FFProbeResult>(cacheFilePath)); + return Task.FromResult(_protobufSerializer.DeserializeFromFile<FFProbeResult>(cacheFilePath)); } catch (FileNotFoundException) { @@ -428,7 +465,7 @@ namespace MediaBrowser.Controller.MediaInfo process.BeginErrorReadLine(); } - result = JsonSerializer.DeserializeFromStream<FFProbeResult>(process.StandardOutput.BaseStream); + result = _jsonSerializer.DeserializeFromStream<FFProbeResult>(process.StandardOutput.BaseStream); if (extractChapters) { @@ -470,7 +507,7 @@ namespace MediaBrowser.Controller.MediaInfo AddChapters(result, standardError); } - Kernel.ProtobufSerializer.SerializeToFile(result, cacheFile); + _protobufSerializer.SerializeToFile(result, cacheFile); return result; } @@ -595,7 +632,7 @@ namespace MediaBrowser.Controller.MediaInfo if (saveItem && changesMade) { - await Kernel.ItemRepository.SaveItem(video, CancellationToken.None).ConfigureAwait(false); + await _kernel.ItemRepository.SaveItem(video, CancellationToken.None).ConfigureAwait(false); } } diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs index 443d28b67..8905656ef 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.MediaInfo; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.IO; @@ -28,29 +29,44 @@ namespace MediaBrowser.Controller.Providers.MediaInfo /// Gets or sets the bluray examiner. /// </summary> /// <value>The bluray examiner.</value> - private IBlurayExaminer BlurayExaminer { get; set; } + private readonly IBlurayExaminer _blurayExaminer; - /// <summary> + /// <summary> /// The _iso manager /// </summary> private readonly IIsoManager _isoManager; /// <summary> + /// The _protobuf serializer + /// </summary> + private readonly IProtobufSerializer _protobufSerializer; + + /// <summary> /// Initializes a new instance of the <see cref="FFProbeVideoInfoProvider" /> class. /// </summary> /// <param name="isoManager">The iso manager.</param> /// <param name="blurayExaminer">The bluray examiner.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> /// <exception cref="System.ArgumentNullException">blurayExaminer</exception> - public FFProbeVideoInfoProvider(IIsoManager isoManager, IBlurayExaminer blurayExaminer) + public FFProbeVideoInfoProvider(IIsoManager isoManager, IBlurayExaminer blurayExaminer, IProtobufSerializer protobufSerializer) : base() { + if (isoManager == null) + { + throw new ArgumentNullException("isoManager"); + } if (blurayExaminer == null) { throw new ArgumentNullException("blurayExaminer"); } + if (protobufSerializer == null) + { + throw new ArgumentNullException("protobufSerializer"); + } - BlurayExaminer = blurayExaminer; + _blurayExaminer = blurayExaminer; _isoManager = isoManager; + _protobufSerializer = protobufSerializer; BdInfoCache = new FileSystemRepository(Path.Combine(Kernel.Instance.ApplicationPaths.CachePath, "bdinfo")); } @@ -315,13 +331,13 @@ namespace MediaBrowser.Controller.Providers.MediaInfo try { - result = Kernel.Instance.ProtobufSerializer.DeserializeFromFile<BlurayDiscInfo>(cacheFile); + result = _protobufSerializer.DeserializeFromFile<BlurayDiscInfo>(cacheFile); } catch (FileNotFoundException) { result = GetBDInfo(inputPath); - Kernel.Instance.ProtobufSerializer.SerializeToFile(result, cacheFile); + _protobufSerializer.SerializeToFile(result, cacheFile); } cancellationToken.ThrowIfCancellationRequested(); @@ -400,7 +416,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo /// <returns>VideoStream.</returns> private BlurayDiscInfo GetBDInfo(string path) { - return BlurayExaminer.GetDiscInfo(path); + return _blurayExaminer.GetDiscInfo(path); } /// <summary> diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs index 72f8a3fc7..bc261de6d 100644 --- a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Serialization; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Model.Entities; @@ -15,6 +14,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Controller.Providers.Movies { @@ -31,6 +31,27 @@ namespace MediaBrowser.Controller.Providers.Movies public class MovieDbProvider : BaseMetadataProvider { /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + protected IJsonSerializer JsonSerializer { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="MovieDbProvider" /> class. + /// </summary> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">jsonSerializer</exception> + public MovieDbProvider(IJsonSerializer jsonSerializer) + : base() + { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + JsonSerializer = jsonSerializer; + } + + /// <summary> /// Gets the priority. /// </summary> /// <value>The priority.</value> @@ -93,7 +114,7 @@ namespace MediaBrowser.Controller.Providers.Movies { get { - LazyInitializer.EnsureInitialized(ref _tmdbSettingsTask, ref _tmdbSettingsTaskInitialized, ref _tmdbSettingsTaskSyncLock, GetTmdbSettings); + LazyInitializer.EnsureInitialized(ref _tmdbSettingsTask, ref _tmdbSettingsTaskInitialized, ref _tmdbSettingsTaskSyncLock, () => GetTmdbSettings(JsonSerializer)); return _tmdbSettingsTask; } } @@ -102,13 +123,13 @@ namespace MediaBrowser.Controller.Providers.Movies /// Gets the TMDB settings. /// </summary> /// <returns>Task{TmdbSettingsResult}.</returns> - private static async Task<TmdbSettingsResult> GetTmdbSettings() + private static async Task<TmdbSettingsResult> GetTmdbSettings(IJsonSerializer jsonSerializer) { try { using (var json = await Kernel.Instance.HttpManager.Get(String.Format(TmdbConfigUrl, ApiKey), Kernel.Instance.ResourcePools.MovieDb, CancellationToken.None).ConfigureAwait(false)) { - return JsonSerializer.DeserializeFromStream<TmdbSettingsResult>(json); + return jsonSerializer.DeserializeFromStream<TmdbSettingsResult>(json); } } catch (HttpException e) @@ -168,7 +189,7 @@ namespace MediaBrowser.Controller.Providers.Movies { //in addition to ours, we need to set the last refreshed time for the local data provider //so it won't see the new files we download and process them all over again - if (JsonProvider == null) JsonProvider = new MovieProviderFromJson(); + if (JsonProvider == null) JsonProvider = new MovieProviderFromJson(JsonSerializer); var data = item.ProviderData.GetValueOrDefault(JsonProvider.Id, new BaseProviderInfo { ProviderId = JsonProvider.Id }); data.LastRefreshed = value; item.ProviderData[JsonProvider.Id] = data; diff --git a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs index 45079ddda..5de17aab0 100644 --- a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs +++ b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Serialization; using System; using System.IO; using System.Threading; @@ -12,6 +12,10 @@ namespace MediaBrowser.Controller.Providers.Movies /// </summary> public class MovieProviderFromJson : MovieDbProvider { + public MovieProviderFromJson(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } + /// <summary> /// Gets the priority. /// </summary> diff --git a/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs b/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs index b4b4933e2..7517ec65c 100644 --- a/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs +++ b/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Serialization; using System; using System.IO; using System.Threading; @@ -12,6 +12,10 @@ namespace MediaBrowser.Controller.Providers.Movies /// </summary> class PersonProviderFromJson : TmdbPersonProvider { + public PersonProviderFromJson(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } + /// <summary> /// Supportses the specified item. /// </summary> diff --git a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs b/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs index 7b5d62fb0..32013614c 100644 --- a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs +++ b/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Net; using System; @@ -10,6 +9,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Controller.Providers.Movies { @@ -24,6 +24,27 @@ namespace MediaBrowser.Controller.Providers.Movies protected const string MetaFileName = "MBPerson.json"; /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + protected IJsonSerializer JsonSerializer { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="MovieDbProvider" /> class. + /// </summary> + /// <param name="jsonSerializer">The json serializer.</param> + /// <exception cref="System.ArgumentNullException">jsonSerializer</exception> + public TmdbPersonProvider(IJsonSerializer jsonSerializer) + : base() + { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + JsonSerializer = jsonSerializer; + } + + /// <summary> /// Supportses the specified item. /// </summary> /// <param name="item">The item.</param> @@ -56,7 +77,7 @@ namespace MediaBrowser.Controller.Providers.Movies protected override async Task<bool> FetchAsyncInternal(BaseItem item, bool force, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + var person = (Person)item; var tasks = new List<Task>(); @@ -169,7 +190,7 @@ namespace MediaBrowser.Controller.Providers.Movies } cancellationToken.ThrowIfCancellationRequested(); - + if (searchResult != null && searchResult.Biography != null) { ProcessInfo(person, searchResult); diff --git a/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs index 1a64bb853..536033719 100644 --- a/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs @@ -28,9 +28,9 @@ namespace MediaBrowser.Controller.ScheduledTasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { - return new BaseTaskTrigger[] + return new ITaskTrigger[] { new DailyTrigger { TimeOfDay = TimeSpan.FromHours(4) } }; diff --git a/MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs b/MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs index 8dd0895c9..7e0094a67 100644 --- a/MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs +++ b/MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs @@ -20,7 +20,8 @@ namespace MediaBrowser.Controller.ScheduledTasks /// Initializes a new instance of the <see cref="ImageCleanupTask" /> class. /// </summary> /// <param name="kernel">The kernel.</param> - /// <param name="logger"></param> + /// <param name="taskManager">The task manager.</param> + /// <param name="logger">The logger.</param> public ImageCleanupTask(Kernel kernel, ITaskManager taskManager, ILogger logger) : base(kernel, taskManager, logger) { @@ -30,9 +31,9 @@ namespace MediaBrowser.Controller.ScheduledTasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { - return new BaseTaskTrigger[] + return new ITaskTrigger[] { new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) } }; diff --git a/MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs b/MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs index ee55ff2e9..595de684d 100644 --- a/MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs +++ b/MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Controller.ScheduledTasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { - return new BaseTaskTrigger[] + return new ITaskTrigger[] { new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }, diff --git a/MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs b/MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs index 854c3b82f..7a1007f1b 100644 --- a/MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs +++ b/MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs @@ -29,9 +29,9 @@ namespace MediaBrowser.Controller.ScheduledTasks /// Creates the triggers that define when the task will run /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { - return new BaseTaskTrigger[] { + return new ITaskTrigger[] { // 1:30am new DailyTrigger { TimeOfDay = TimeSpan.FromHours(1.5) }, diff --git a/MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs b/MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs index 76e60f2ef..104b432f4 100644 --- a/MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs +++ b/MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs @@ -27,9 +27,9 @@ namespace MediaBrowser.Controller.ScheduledTasks /// Gets the default triggers. /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> - protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers() + public override IEnumerable<ITaskTrigger> GetDefaultTriggers() { - return new BaseTaskTrigger[] { + return new ITaskTrigger[] { new StartupTrigger(), diff --git a/MediaBrowser.Controller/Updates/InstallationManager.cs b/MediaBrowser.Controller/Updates/InstallationManager.cs index bef5a6472..af544dd51 100644 --- a/MediaBrowser.Controller/Updates/InstallationManager.cs +++ b/MediaBrowser.Controller/Updates/InstallationManager.cs @@ -1,18 +1,17 @@ -using System.Security.Cryptography; -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Progress; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Updates; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; @@ -32,8 +31,8 @@ namespace MediaBrowser.Controller.Updates /// <summary> /// The completed installations /// </summary> - public readonly ConcurrentBag<InstallationInfo> CompletedInstallations = new ConcurrentBag<InstallationInfo>(); - + public readonly ConcurrentBag<InstallationInfo> CompletedInstallations = new ConcurrentBag<InstallationInfo>(); + #region PluginUninstalled Event /// <summary> /// Occurs when [plugin uninstalled]. @@ -68,7 +67,7 @@ namespace MediaBrowser.Controller.Updates _logger.Info("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.version, newVersion.classification); EventHelper.QueueEventIfNotNull(PluginUpdated, this, new GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> { Argument = new Tuple<IPlugin, PackageVersionInfo>(plugin, newVersion) }, _logger); - + Kernel.NotifyPendingRestart(); } #endregion @@ -109,14 +108,21 @@ namespace MediaBrowser.Controller.Updates private readonly INetworkManager _networkManager; /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + protected IJsonSerializer JsonSerializer { get; private set; } + + /// <summary> /// Initializes a new instance of the <see cref="InstallationManager" /> class. /// </summary> /// <param name="kernel">The kernel.</param> /// <param name="zipClient">The zip client.</param> /// <param name="networkManager">The network manager.</param> + /// <param name="jsonSerializer"></param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">zipClient</exception> - public InstallationManager(Kernel kernel, IZipClient zipClient, INetworkManager networkManager, ILogger logger) + public InstallationManager(Kernel kernel, IZipClient zipClient, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger) : base(kernel) { if (zipClient == null) @@ -131,6 +137,12 @@ namespace MediaBrowser.Controller.Updates { throw new ArgumentNullException("logger"); } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + JsonSerializer = jsonSerializer; _networkManager = networkManager; _logger = logger; @@ -161,7 +173,7 @@ namespace MediaBrowser.Controller.Updates package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl)) .OrderByDescending(v => v.version).ToList(); } - + if (packageType.HasValue) { packages = packages.Where(p => p.type == packageType.Value).ToList(); @@ -178,7 +190,7 @@ namespace MediaBrowser.Controller.Updates // Remove packages with no versions packages = packages.Where(p => p.versions.Any()).ToList(); - + return packages; } } @@ -320,7 +332,7 @@ namespace MediaBrowser.Controller.Updates var innerCancellationTokenSource = new CancellationTokenSource(); var tuple = new Tuple<InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource); - + // Add it to the in-progress list lock (CurrentInstallations) { @@ -364,7 +376,7 @@ namespace MediaBrowser.Controller.Updates _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr); Kernel.TcpManager.SendWebSocketMessage("PackageInstallationCancelled", installationInfo); - + throw; } catch @@ -373,7 +385,7 @@ namespace MediaBrowser.Controller.Updates { CurrentInstallations.Remove(tuple); } - + Kernel.TcpManager.SendWebSocketMessage("PackageInstallationFailed", installationInfo); throw; @@ -421,7 +433,7 @@ namespace MediaBrowser.Controller.Updates } cancellationToken.ThrowIfCancellationRequested(); - + // Success - move it to the real target based on type if (isArchive) { @@ -435,7 +447,7 @@ namespace MediaBrowser.Controller.Updates throw; } - } + } else { try @@ -448,8 +460,8 @@ namespace MediaBrowser.Controller.Updates _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)); diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 372aefdc6..8e8f88c20 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -75,6 +75,9 @@ <Compile Include="Net\HttpException.cs" /> <Compile Include="Net\NetworkShare.cs" /> <Compile Include="Net\NetworkShareType.cs" /> + <Compile Include="Serialization\IJsonSerializer.cs" /> + <Compile Include="Serialization\IProtobufSerializer.cs" /> + <Compile Include="Serialization\IXmlSerializer.cs" /> <Compile Include="Updates\CheckForUpdateResult.cs" /> <Compile Include="Updates\InstallationInfo.cs" /> <Compile Include="Updates\PackageType.cs" /> diff --git a/MediaBrowser.Model/Serialization/IJsonSerializer.cs b/MediaBrowser.Model/Serialization/IJsonSerializer.cs new file mode 100644 index 000000000..056389d2e --- /dev/null +++ b/MediaBrowser.Model/Serialization/IJsonSerializer.cs @@ -0,0 +1,103 @@ +using System; +using System.IO; + +namespace MediaBrowser.Model.Serialization +{ + public interface IJsonSerializer + { + /// <summary> + /// Serializes to stream. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + /// <param name="stream">The stream.</param> + /// <exception cref="System.ArgumentNullException">obj</exception> + void SerializeToStream<T>(T obj, Stream stream) + where T : class; + + /// <summary> + /// Serializes to file. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + /// <param name="file">The file.</param> + /// <exception cref="System.ArgumentNullException">obj</exception> + void SerializeToFile<T>(T obj, string file) + where T : class; + + /// <summary> + /// Deserializes from file. + /// </summary> + /// <param name="type">The type.</param> + /// <param name="file">The file.</param> + /// <returns>System.Object.</returns> + /// <exception cref="System.ArgumentNullException">type</exception> + object DeserializeFromFile(Type type, string file); + + /// <summary> + /// Deserializes from file. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="file">The file.</param> + /// <returns>``0.</returns> + /// <exception cref="System.ArgumentNullException">file</exception> + T DeserializeFromFile<T>(string file) + where T : class; + + /// <summary> + /// Deserializes from stream. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="stream">The stream.</param> + /// <returns>``0.</returns> + /// <exception cref="System.ArgumentNullException">stream</exception> + T DeserializeFromStream<T>(Stream stream); + + /// <summary> + /// Deserializes from string. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="text">The text.</param> + /// <returns>``0.</returns> + /// <exception cref="System.ArgumentNullException">text</exception> + T DeserializeFromString<T>(string text); + + /// <summary> + /// Deserializes from stream. + /// </summary> + /// <param name="stream">The stream.</param> + /// <param name="type">The type.</param> + /// <returns>System.Object.</returns> + /// <exception cref="System.ArgumentNullException">stream</exception> + object DeserializeFromStream(Stream stream, Type type); + + /// <summary> + /// Deserializes from string. + /// </summary> + /// <param name="json">The json.</param> + /// <param name="type">The type.</param> + /// <returns>System.Object.</returns> + /// <exception cref="System.ArgumentNullException">json</exception> + object DeserializeFromString(string json, Type type); + + /// <summary> + /// Serializes to string. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + /// <returns>System.String.</returns> + /// <exception cref="System.ArgumentNullException">obj</exception> + string SerializeToString<T>(T obj) + where T : class; + + /// <summary> + /// Serializes to bytes. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + /// <returns>System.Byte[][].</returns> + /// <exception cref="System.ArgumentNullException">obj</exception> + byte[] SerializeToBytes<T>(T obj) + where T : class; + } +}
\ No newline at end of file diff --git a/MediaBrowser.Model/Serialization/IProtobufSerializer.cs b/MediaBrowser.Model/Serialization/IProtobufSerializer.cs new file mode 100644 index 000000000..4c3ef6960 --- /dev/null +++ b/MediaBrowser.Model/Serialization/IProtobufSerializer.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; + +namespace MediaBrowser.Model.Serialization +{ + public interface IProtobufSerializer + { + /// <summary> + /// Serializes to stream. + /// </summary> + /// <param name="obj">The obj.</param> + /// <param name="stream">The stream.</param> + /// <exception cref="System.ArgumentNullException">obj</exception> + void SerializeToStream(object obj, Stream stream); + + /// <summary> + /// Deserializes from stream. + /// </summary> + /// <param name="stream">The stream.</param> + /// <param name="type">The type.</param> + /// <returns>System.Object.</returns> + /// <exception cref="System.ArgumentNullException">stream</exception> + object DeserializeFromStream(Stream stream, Type type); + + /// <summary> + /// Deserializes from stream. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="stream">The stream.</param> + /// <returns>``0.</returns> + T DeserializeFromStream<T>(Stream stream) + where T : class; + + /// <summary> + /// Serializes to file. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + /// <param name="file">The file.</param> + /// <exception cref="System.ArgumentNullException">file</exception> + void SerializeToFile<T>(T obj, string file); + + /// <summary> + /// Deserializes from file. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="file">The file.</param> + /// <returns>``0.</returns> + /// <exception cref="System.ArgumentNullException">file</exception> + T DeserializeFromFile<T>(string file) + where T : class; + + /// <summary> + /// Serializes to bytes. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + /// <returns>System.Byte[][].</returns> + /// <exception cref="System.ArgumentNullException">obj</exception> + byte[] SerializeToBytes<T>(T obj) + where T : class; + } +}
\ No newline at end of file diff --git a/MediaBrowser.Model/Serialization/IXmlSerializer.cs b/MediaBrowser.Model/Serialization/IXmlSerializer.cs new file mode 100644 index 000000000..1d0e0302b --- /dev/null +++ b/MediaBrowser.Model/Serialization/IXmlSerializer.cs @@ -0,0 +1,69 @@ +using System; +using System.IO; + +namespace MediaBrowser.Model.Serialization +{ + public interface IXmlSerializer + { + /// <summary> + /// Deserializes from stream. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="stream">The stream.</param> + /// <returns>``0.</returns> + T DeserializeFromStream<T>(Stream stream); + + /// <summary> + /// Deserializes from stream. + /// </summary> + /// <param name="type">The type.</param> + /// <param name="stream">The stream.</param> + /// <returns>System.Object.</returns> + object DeserializeFromStream(Type type, Stream stream); + + /// <summary> + /// Serializes to stream. + /// </summary> + /// <param name="obj">The obj.</param> + /// <param name="stream">The stream.</param> + void SerializeToStream(object obj, Stream stream); + + /// <summary> + /// Deserializes from file. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="file">The file.</param> + /// <returns>``0.</returns> + T DeserializeFromFile<T>(string file); + + /// <summary> + /// Serializes to file. + /// </summary> + /// <param name="obj">The obj.</param> + /// <param name="file">The file.</param> + void SerializeToFile(object obj, string file); + + /// <summary> + /// Deserializes from file. + /// </summary> + /// <param name="type">The type.</param> + /// <param name="file">The file.</param> + /// <returns>System.Object.</returns> + object DeserializeFromFile(Type type, string file); + + /// <summary> + /// Deserializes from bytes. + /// </summary> + /// <param name="type">The type.</param> + /// <param name="buffer">The buffer.</param> + /// <returns>System.Object.</returns> + object DeserializeFromBytes(Type type, byte[] buffer); + + /// <summary> + /// Serializes to bytes. + /// </summary> + /// <param name="obj">The obj.</param> + /// <returns>System.Byte[][].</returns> + byte[] SerializeToBytes(object obj); + } +}
\ No newline at end of file diff --git a/MediaBrowser.Networking/MediaBrowser.Networking.csproj b/MediaBrowser.Networking/MediaBrowser.Networking.csproj index 7e4a0b160..41fd6ceab 100644 --- a/MediaBrowser.Networking/MediaBrowser.Networking.csproj +++ b/MediaBrowser.Networking/MediaBrowser.Networking.csproj @@ -112,6 +112,8 @@ <Compile Include="Management\NetworkManager.cs" /> <Compile Include="Management\NetworkShares.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Web\ServerFactory.cs" /> + <Compile Include="Web\NativeWebSocket.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> diff --git a/MediaBrowser.Networking/Web/HttpServer.cs b/MediaBrowser.Networking/Web/HttpServer.cs index c280abedf..ab4b8558f 100644 --- a/MediaBrowser.Networking/Web/HttpServer.cs +++ b/MediaBrowser.Networking/Web/HttpServer.cs @@ -4,6 +4,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using ServiceStack.Api.Swagger; using ServiceStack.Common.Web; using ServiceStack.Configuration; @@ -61,6 +62,12 @@ namespace MediaBrowser.Networking.Web private IDisposable HttpListener { get; set; } /// <summary> + /// Gets or sets the protobuf serializer. + /// </summary> + /// <value>The protobuf serializer.</value> + private IProtobufSerializer ProtobufSerializer { get; set; } + + /// <summary> /// Occurs when [web socket connected]. /// </summary> public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; @@ -82,17 +89,22 @@ namespace MediaBrowser.Networking.Web /// </summary> /// <param name="applicationHost">The application host.</param> /// <param name="kernel">The kernel.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> /// <param name="logger">The logger.</param> /// <param name="serverName">Name of the server.</param> /// <param name="defaultRedirectpath">The default redirectpath.</param> /// <exception cref="System.ArgumentNullException">urlPrefix</exception> - public HttpServer(IApplicationHost applicationHost, IKernel kernel, ILogger logger, string serverName, string defaultRedirectpath) + public HttpServer(IApplicationHost applicationHost, IKernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath) : base() { if (kernel == null) { throw new ArgumentNullException("kernel"); } + if (protobufSerializer == null) + { + throw new ArgumentNullException("protobufSerializer"); + } if (logger == null) { throw new ArgumentNullException("logger"); @@ -112,6 +124,7 @@ namespace MediaBrowser.Networking.Web ServerName = serverName; DefaultRedirectPath = defaultRedirectpath; + ProtobufSerializer = protobufSerializer; _logger = logger; ApplicationHost = applicationHost; @@ -121,7 +134,7 @@ namespace MediaBrowser.Networking.Web Kernel = kernel; EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager()); - ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => Kernel.ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => Kernel.ProtobufSerializer.DeserializeFromStream(stream, type)); + ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => ProtobufSerializer.DeserializeFromStream(stream, type)); Init(); } @@ -132,6 +145,10 @@ namespace MediaBrowser.Networking.Web /// <param name="container">The container.</param> public override void Configure(Container container) { + JsConfig.DateHandler = JsonDateHandler.ISO8601; + JsConfig.ExcludeTypeInfo = true; + JsConfig.IncludeNullValues = false; + SetConfig(new EndpointHostConfig { DefaultRedirectPath = DefaultRedirectPath, diff --git a/MediaBrowser.Common/Net/NativeWebSocket.cs b/MediaBrowser.Networking/Web/NativeWebSocket.cs index 23f3d4be3..ad28d1a7f 100644 --- a/MediaBrowser.Common/Net/NativeWebSocket.cs +++ b/MediaBrowser.Networking/Web/NativeWebSocket.cs @@ -1,7 +1,5 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Logging; using System; -using System.IO; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; @@ -79,19 +77,7 @@ namespace MediaBrowser.Common.Net if (OnReceiveDelegate != null) { - using (var memoryStream = new MemoryStream(bytes)) - { - try - { - var messageResult = JsonSerializer.DeserializeFromStream<WebSocketMessageInfo>(memoryStream); - - OnReceiveDelegate(messageResult); - } - catch (Exception ex) - { - _logger.ErrorException("Error processing web socket message", ex); - } - } + OnReceiveDelegate(bytes); } } } @@ -154,6 +140,6 @@ namespace MediaBrowser.Common.Net /// Gets or sets the receive action. /// </summary> /// <value>The receive action.</value> - public Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; } + public Action<byte[]> OnReceiveDelegate { get; set; } } } diff --git a/MediaBrowser.Networking/Web/ServerFactory.cs b/MediaBrowser.Networking/Web/ServerFactory.cs new file mode 100644 index 000000000..b93f2ca1c --- /dev/null +++ b/MediaBrowser.Networking/Web/ServerFactory.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; + +namespace MediaBrowser.Networking.Web +{ + /// <summary> + /// Class ServerFactory + /// </summary> + public static class ServerFactory + { + /// <summary> + /// Creates the server. + /// </summary> + /// <param name="applicationHost">The application host.</param> + /// <param name="kernel">The kernel.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> + /// <param name="logger">The logger.</param> + /// <param name="serverName">Name of the server.</param> + /// <param name="defaultRedirectpath">The default redirectpath.</param> + /// <returns>IHttpServer.</returns> + public static IHttpServer CreateServer(IApplicationHost applicationHost, IKernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath) + { + return new HttpServer(applicationHost, kernel, protobufSerializer, logger, serverName, defaultRedirectpath); + } + } +} diff --git a/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs b/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs index fbdb3186f..5eca1a78c 100644 --- a/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs +++ b/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs @@ -1,9 +1,9 @@ using Alchemy.Classes; using MediaBrowser.Common.Net; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Logging; using System; using System.Net.WebSockets; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -83,9 +83,9 @@ namespace MediaBrowser.Networking.WebSocket { try { - var messageResult = JsonSerializer.DeserializeFromString<WebSocketMessageInfo>(json); + var bytes = Encoding.UTF8.GetBytes(json); - OnReceiveDelegate(messageResult); + OnReceiveDelegate(bytes); } catch (Exception ex) { @@ -128,6 +128,6 @@ namespace MediaBrowser.Networking.WebSocket /// Gets or sets the receive action. /// </summary> /// <value>The receive action.</value> - public Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; } + public Action<byte[]> OnReceiveDelegate { get; set; } } } diff --git a/MediaBrowser.Server.Sqlite/MediaBrowser.Server.Sqlite.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 78ea39dd8..416a7d746 100644 --- a/MediaBrowser.Server.Sqlite/MediaBrowser.Server.Sqlite.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -4,11 +4,11 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProjectGuid>{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}</ProjectGuid> + <ProjectGuid>{2E781478-814D-4A48-9D80-BFF206441A65}</ProjectGuid> <OutputType>Library</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>MediaBrowser.Server.Sqlite</RootNamespace> - <AssemblyName>MediaBrowser.Server.Sqlite</AssemblyName> + <RootNamespace>MediaBrowser.Server.Implementations</RootNamespace> + <AssemblyName>MediaBrowser.Server.Implementations</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> @@ -31,9 +31,6 @@ <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> - <PropertyGroup> - <RunPostBuildEvent>Always</RunPostBuildEvent> - </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> @@ -43,33 +40,31 @@ <Reference Include="System.Data.SQLite.Linq"> <HintPath>..\packages\System.Data.SQLite.1.0.84.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath> </Reference> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="SQLiteDisplayPreferencesRepository.cs" /> - <Compile Include="SQLiteExtensions.cs" /> - <Compile Include="SQLiteItemRepository.cs" /> - <Compile Include="SQLiteRepository.cs" /> - <Compile Include="SQLiteUserDataRepository.cs" /> - <Compile Include="SQLiteUserRepository.cs" /> - </ItemGroup> - <ItemGroup> - <Content Include="x64\SQLite.Interop.dll"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> - </Content> - <Content Include="x86\SQLite.Interop.dll"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> - </Content> - </ItemGroup> - <ItemGroup> - <None Include="packages.config" /> + <Compile Include="ServerApplicationPaths.cs" /> + <Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" /> + <Compile Include="Sqlite\SQLiteExtensions.cs" /> + <Compile Include="Sqlite\SQLiteItemRepository.cs" /> + <Compile Include="Sqlite\SQLiteRepository.cs" /> + <Compile Include="Sqlite\SQLiteUserDataRepository.cs" /> + <Compile Include="Sqlite\SQLiteUserRepository.cs" /> + <Compile Include="WorldWeatherOnline\WeatherProvider.cs" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj"> + <Project>{c4d2573a-3fd3-441f-81af-174ac4cd4e1d}</Project> + <Name>MediaBrowser.Common.Implementations</Name> + </ProjectReference> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project> <Name>MediaBrowser.Common</Name> @@ -83,11 +78,20 @@ <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <Content Include="x64\SQLite.Interop.dll"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + <Content Include="x86\SQLite.Interop.dll"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> - <PropertyGroup> - <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\MediaBrowser.ServerApplication\CorePlugins\" /y</PostBuildEvent> - </PropertyGroup> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> diff --git a/MediaBrowser.Server.WorldWeatherOnline/Properties/AssemblyInfo.cs b/MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs index d5d94bafd..db656b934 100644 --- a/MediaBrowser.Server.WorldWeatherOnline/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs @@ -1,15 +1,14 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("MediaBrowser.Server.WorldWeatherOnline")] +[assembly: AssemblyTitle("MediaBrowser.Server.Implementations")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("MediaBrowser.Server.WorldWeatherOnline")] +[assembly: AssemblyProduct("MediaBrowser.Server.Implementations")] [assembly: AssemblyCopyright("Copyright © 2013")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +19,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c7b294dc-b3fd-4925-9ac3-8dd16803200c")] +[assembly: Guid("0537cdd3-a069-4d86-9318-d46d8b119903")] // Version information for an assembly consists of the following four values: // @@ -28,4 +27,4 @@ using System.Runtime.InteropServices; // Minor Version // Build Number // Revision -//
\ No newline at end of file +// diff --git a/MediaBrowser.Controller/ServerApplicationPaths.cs b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs index a376afed8..e473808f5 100644 --- a/MediaBrowser.Controller/ServerApplicationPaths.cs +++ b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs @@ -1,12 +1,13 @@ -using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Implementations; +using MediaBrowser.Controller; using System.IO; -namespace MediaBrowser.Controller +namespace MediaBrowser.Server.Implementations { /// <summary> /// Extends BaseApplicationPaths to add paths that are only applicable on the server /// </summary> - public class ServerApplicationPaths : BaseApplicationPaths + public class ServerApplicationPaths : BaseApplicationPaths, IServerApplicationPaths { /// <summary> /// The _root folder path diff --git a/MediaBrowser.Server.Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs index 80d389c94..53a467c1a 100644 --- a/MediaBrowser.Server.Sqlite/SQLiteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs @@ -1,8 +1,9 @@ -using MediaBrowser.Controller; +using MediaBrowser.Common.Kernel; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Data; @@ -10,7 +11,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.Sqlite +namespace MediaBrowser.Server.Implementations.Sqlite { /// <summary> /// Class SQLiteDisplayPreferencesRepository @@ -35,12 +36,36 @@ namespace MediaBrowser.Server.Sqlite } /// <summary> + /// The _protobuf serializer + /// </summary> + private readonly IProtobufSerializer _protobufSerializer; + + /// <summary> + /// The _app paths + /// </summary> + private readonly IApplicationPaths _appPaths; + + /// <summary> /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class. /// </summary> + /// <param name="appPaths">The app paths.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> /// <param name="logger">The logger.</param> - public SQLiteDisplayPreferencesRepository(ILogger logger) + /// <exception cref="System.ArgumentNullException">protobufSerializer</exception> + public SQLiteDisplayPreferencesRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogger logger) : base(logger) { + if (protobufSerializer == null) + { + throw new ArgumentNullException("protobufSerializer"); + } + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + + _protobufSerializer = protobufSerializer; + _appPaths = appPaths; } /// <summary> @@ -49,7 +74,7 @@ namespace MediaBrowser.Server.Sqlite /// <returns>Task.</returns> public async Task Initialize() { - var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "displaypreferences.db"); + var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db"); await ConnectToDB(dbFile).ConfigureAwait(false); @@ -104,7 +129,7 @@ namespace MediaBrowser.Server.Sqlite cmd.AddParam("@1", item.DisplayPrefsId); cmd.AddParam("@2", data.UserId); - cmd.AddParam("@3", Kernel.Instance.ProtobufSerializer.SerializeToBytes(data)); + cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data)); QueueCommand(cmd); } @@ -136,7 +161,7 @@ namespace MediaBrowser.Server.Sqlite { using (var stream = GetStream(reader, 0)) { - var data = Kernel.Instance.ProtobufSerializer.DeserializeFromStream<DisplayPreferences>(stream); + var data = _protobufSerializer.DeserializeFromStream<DisplayPreferences>(stream); if (data != null) { yield return data; diff --git a/MediaBrowser.Server.Sqlite/SQLiteExtensions.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs index f9f79a8b7..6aed8a352 100644 --- a/MediaBrowser.Server.Sqlite/SQLiteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs @@ -2,7 +2,7 @@ using System.Data; using System.Data.SQLite; -namespace MediaBrowser.Server.Sqlite +namespace MediaBrowser.Server.Implementations.Sqlite { /// <summary> /// Class SQLiteExtensions diff --git a/MediaBrowser.Server.Sqlite/SQLiteItemRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs index 58a924bc4..034cd2188 100644 --- a/MediaBrowser.Server.Sqlite/SQLiteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs @@ -1,8 +1,8 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller; +using MediaBrowser.Common.Kernel; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Data; @@ -10,7 +10,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.Sqlite +namespace MediaBrowser.Server.Implementations.Sqlite { /// <summary> /// Class SQLiteItemRepository @@ -40,12 +40,37 @@ namespace MediaBrowser.Server.Sqlite } /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// The _app paths + /// </summary> + private readonly IApplicationPaths _appPaths; + + /// <summary> /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class. /// </summary> + /// <param name="appPaths">The app paths.</param> + /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> - public SQLiteItemRepository(ILogger logger) + /// <exception cref="System.ArgumentNullException">appPaths</exception> + public SQLiteItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogger logger) : base(logger) { + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + _appPaths = appPaths; + _jsonSerializer = jsonSerializer; } /// <summary> @@ -54,7 +79,7 @@ namespace MediaBrowser.Server.Sqlite /// <returns>Task.</returns> public async Task Initialize() { - var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "library.db"); + var dbFile = Path.Combine(_appPaths.DataPath, "library.db"); await ConnectToDB(dbFile).ConfigureAwait(false); @@ -111,7 +136,7 @@ namespace MediaBrowser.Server.Sqlite return Task.Run(() => { - var serialized = JsonSerializer.SerializeToBytes(item); + var serialized = _jsonSerializer.SerializeToBytes(item); cancellationToken.ThrowIfCancellationRequested(); @@ -173,7 +198,7 @@ namespace MediaBrowser.Server.Sqlite return null; } - var item = JsonSerializer.DeserializeFromStream(stream, itemType); + var item = _jsonSerializer.DeserializeFromStream(stream, itemType); return item as BaseItem; } } @@ -213,7 +238,7 @@ namespace MediaBrowser.Server.Sqlite Logger.Error("Cannot find type {0}. Probably belongs to plug-in that is no longer loaded.", type); continue; } - var item = JsonSerializer.DeserializeFromStream(stream, itemType) as BaseItem; + var item = _jsonSerializer.DeserializeFromStream(stream, itemType) as BaseItem; if (item != null) { item.Parent = parent; diff --git a/MediaBrowser.Server.Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs index 1caae970e..dead97959 100644 --- a/MediaBrowser.Server.Sqlite/SQLiteRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs @@ -8,7 +8,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.Sqlite +namespace MediaBrowser.Server.Implementations.Sqlite { /// <summary> /// Class SqliteRepository diff --git a/MediaBrowser.Server.Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs index eaa89508a..5787a614a 100644 --- a/MediaBrowser.Server.Sqlite/SQLiteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs @@ -1,7 +1,8 @@ -using MediaBrowser.Controller; +using MediaBrowser.Common.Kernel; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Data; @@ -9,7 +10,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.Sqlite +namespace MediaBrowser.Server.Implementations.Sqlite { /// <summary> /// Class SQLiteUserDataRepository @@ -34,12 +35,36 @@ namespace MediaBrowser.Server.Sqlite } /// <summary> + /// The _protobuf serializer + /// </summary> + private readonly IProtobufSerializer _protobufSerializer; + + /// <summary> + /// The _app paths + /// </summary> + private readonly IApplicationPaths _appPaths; + + /// <summary> /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class. /// </summary> + /// <param name="appPaths">The app paths.</param> + /// <param name="protobufSerializer">The protobuf serializer.</param> /// <param name="logger">The logger.</param> - public SQLiteUserDataRepository(ILogger logger) + /// <exception cref="System.ArgumentNullException">protobufSerializer</exception> + public SQLiteUserDataRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogger logger) : base(logger) { + if (protobufSerializer == null) + { + throw new ArgumentNullException("protobufSerializer"); + } + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + + _protobufSerializer = protobufSerializer; + _appPaths = appPaths; } /// <summary> @@ -48,7 +73,7 @@ namespace MediaBrowser.Server.Sqlite /// <returns>Task.</returns> public async Task Initialize() { - var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "userdata.db"); + var dbFile = Path.Combine(_appPaths.DataPath, "userdata.db"); await ConnectToDB(dbFile).ConfigureAwait(false); @@ -103,7 +128,7 @@ namespace MediaBrowser.Server.Sqlite cmd.AddParam("@1", item.UserDataId); cmd.AddParam("@2", data.UserId); - cmd.AddParam("@3", Kernel.Instance.ProtobufSerializer.SerializeToBytes(data)); + cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data)); QueueCommand(cmd); } @@ -135,7 +160,7 @@ namespace MediaBrowser.Server.Sqlite { using (var stream = GetStream(reader, 0)) { - var data = Kernel.Instance.ProtobufSerializer.DeserializeFromStream<UserItemData>(stream); + var data = _protobufSerializer.DeserializeFromStream<UserItemData>(stream); if (data != null) { yield return data; diff --git a/MediaBrowser.Server.Sqlite/SQLiteUserRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs index 6c0de2161..1e6f370eb 100644 --- a/MediaBrowser.Server.Sqlite/SQLiteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs @@ -1,16 +1,16 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller; +using MediaBrowser.Common.Kernel; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Logging; -namespace MediaBrowser.Server.Sqlite +namespace MediaBrowser.Server.Implementations.Sqlite { /// <summary> /// Class SQLiteUserRepository @@ -35,12 +35,37 @@ namespace MediaBrowser.Server.Sqlite } /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> + /// The _app paths + /// </summary> + private readonly IApplicationPaths _appPaths; + + /// <summary> /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class. /// </summary> + /// <param name="appPaths">The app paths.</param> + /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> - public SQLiteUserRepository(ILogger logger) + /// <exception cref="System.ArgumentNullException">appPaths</exception> + public SQLiteUserRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogger logger) : base(logger) { + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + _appPaths = appPaths; + _jsonSerializer = jsonSerializer; } /// <summary> @@ -49,7 +74,7 @@ namespace MediaBrowser.Server.Sqlite /// <returns>Task.</returns> public async Task Initialize() { - var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "users.db"); + var dbFile = Path.Combine(_appPaths.DataPath, "users.db"); await ConnectToDB(dbFile).ConfigureAwait(false); @@ -88,7 +113,7 @@ namespace MediaBrowser.Server.Sqlite { cancellationToken.ThrowIfCancellationRequested(); - var serialized = JsonSerializer.SerializeToBytes(user); + var serialized = _jsonSerializer.SerializeToBytes(user); cancellationToken.ThrowIfCancellationRequested(); @@ -115,7 +140,7 @@ namespace MediaBrowser.Server.Sqlite { using (var stream = GetStream(reader, 0)) { - var user = JsonSerializer.DeserializeFromStream<User>(stream); + var user = _jsonSerializer.DeserializeFromStream<User>(stream); yield return user; } } diff --git a/MediaBrowser.Server.WorldWeatherOnline/WeatherProvider.cs b/MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs index c30a30455..1b75a58b8 100644 --- a/MediaBrowser.Server.WorldWeatherOnline/WeatherProvider.cs +++ b/MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs @@ -1,14 +1,14 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller; +using MediaBrowser.Controller; using MediaBrowser.Controller.Weather; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Weather; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.WorldWeatherOnline +namespace MediaBrowser.Server.Implementations.WorldWeatherOnline { /// <summary> /// Based on http://www.worldweatheronline.com/free-weather-feed.aspx @@ -23,17 +23,30 @@ namespace MediaBrowser.Server.WorldWeatherOnline private ILogger Logger { get; set; } /// <summary> + /// Gets the json serializer. + /// </summary> + /// <value>The json serializer.</value> + protected IJsonSerializer JsonSerializer { get; private set; } + + /// <summary> /// Initializes a new instance of the <see cref="WeatherProvider" /> class. /// </summary> + /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">logger</exception> - public WeatherProvider(ILogger logger) + public WeatherProvider(IJsonSerializer jsonSerializer, ILogger logger) { if (logger == null) { throw new ArgumentNullException("logger"); } + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } + + JsonSerializer = jsonSerializer; Logger = logger; } diff --git a/MediaBrowser.Server.Sqlite/packages.config b/MediaBrowser.Server.Implementations/packages.config index 106618814..106618814 100644 --- a/MediaBrowser.Server.Sqlite/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs index 1b6b6f98e..5808120ad 100644 --- a/MediaBrowser.ServerApplication/App.xaml.cs +++ b/MediaBrowser.ServerApplication/App.xaml.cs @@ -1,26 +1,13 @@ -using BDInfo; -using MediaBrowser.ClickOnce; -using MediaBrowser.Common.IO; +using MediaBrowser.ClickOnce; +using MediaBrowser.Common.Implementations.Serialization; using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Net; using MediaBrowser.Controller; -using MediaBrowser.IsoMounter; using MediaBrowser.Logging.Nlog; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Updates; -using MediaBrowser.Networking.Management; -using MediaBrowser.Networking.Udp; -using MediaBrowser.Networking.Web; -using MediaBrowser.Networking.WebSocket; using MediaBrowser.Server.Uninstall; -using MediaBrowser.ServerApplication.Implementations; using Microsoft.Win32; -using SimpleInjector; using System; using System.Diagnostics; -using System.IO; using System.Linq; using System.Net.Cache; using System.Threading; @@ -35,7 +22,7 @@ namespace MediaBrowser.ServerApplication /// <summary> /// Interaction logic for App.xaml /// </summary> - public partial class App : Application, IApplicationHost + public partial class App : Application { /// <summary> /// Defines the entry point of the application. @@ -78,16 +65,11 @@ namespace MediaBrowser.ServerApplication protected ILogger Logger { get; set; } /// <summary> - /// Gets or sets the log file path. + /// Gets or sets the composition root. /// </summary> - /// <value>The log file path.</value> - public string LogFilePath { get; private set; } - - /// <summary> - /// The container - /// </summary> - private Container _container = new Container(); - + /// <value>The composition root.</value> + protected ApplicationHost CompositionRoot { get; set; } + /// <summary> /// Initializes a new instance of the <see cref="App" /> class. /// </summary> @@ -136,12 +118,6 @@ namespace MediaBrowser.ServerApplication } /// <summary> - /// Gets or sets the iso manager. - /// </summary> - /// <value>The iso manager.</value> - private IIsoManager IsoManager { get; set; } - - /// <summary> /// Gets or sets a value indicating whether [last run at startup value]. /// </summary> /// <value><c>null</c> if [last run at startup value] contains no value, <c>true</c> if [last run at startup value]; otherwise, <c>false</c>.</value> @@ -198,13 +174,13 @@ namespace MediaBrowser.ServerApplication /// </summary> protected async void LoadKernel() { - Kernel = new Kernel(this, Logger); + CompositionRoot = new ApplicationHost(Logger); - RegisterResources(); + Kernel = CompositionRoot.Kernel; try { - new MainWindow(Logger).Show(); + new MainWindow(new JsonSerializer(), Logger).Show(); var now = DateTime.UtcNow; @@ -281,6 +257,7 @@ namespace MediaBrowser.ServerApplication base.OnExit(e); Kernel.Dispose(); + CompositionRoot.Dispose(); } /// <summary> @@ -392,17 +369,6 @@ namespace MediaBrowser.ServerApplication } /// <summary> - /// Reloads the logger. - /// </summary> - /// <exception cref="System.NotImplementedException"></exception> - public void ReloadLogger() - { - LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log"); - - NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging); - } - - /// <summary> /// Gets the image. /// </summary> /// <param name="uri">The URI.</param> @@ -477,143 +443,5 @@ namespace MediaBrowser.ServerApplication RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant); return bitmap; } - - /// <summary> - /// Gets or sets a value indicating whether this instance can self update. - /// </summary> - /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value> - public bool CanSelfUpdate - { - get { return ClickOnceHelper.IsNetworkDeployed; } - } - - /// <summary> - /// Checks for update. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task{CheckForUpdateResult}.</returns> - public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress) - { - return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress); - } - - /// <summary> - /// Updates the application. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress) - { - return new ApplicationUpdater().UpdateApplication(cancellationToken, progress); - } - - /// <summary> - /// Registers resources that classes will depend on - /// </summary> - private void RegisterResources() - { - RegisterSingleInstance<IApplicationHost>(this); - RegisterSingleInstance(Logger); - - IsoManager = new PismoIsoManager(Logger); - - RegisterSingleInstance(IsoManager); - RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer()); - RegisterSingleInstance<INetworkManager>(() => new NetworkManager()); - RegisterSingleInstance<IZipClient>(() => new DotNetZipClient()); - RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger)); - Register(typeof(IUdpServer), typeof(UdpServer)); - RegisterSingleInstance<IHttpServer>(() => new HttpServer(this, Kernel, Logger, "Media Browser", "index.html")); - } - - /// <summary> - /// Creates an instance of type and resolves all constructor dependancies - /// </summary> - /// <param name="type">The type.</param> - /// <returns>System.Object.</returns> - public object CreateInstance(Type type) - { - try - { - return _container.GetInstance(type); - } - catch - { - Logger.Error("Error creating {0}", type.Name); - - throw; - } - } - - /// <summary> - /// Registers the specified obj. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="obj">The obj.</param> - public void RegisterSingleInstance<T>(T obj) - where T : class - { - _container.RegisterSingle(obj); - } - - /// <summary> - /// Registers the specified func. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="func">The func.</param> - public void Register<T>(Func<T> func) - where T : class - { - _container.Register(func); - } - - /// <summary> - /// Registers the single instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="func">The func.</param> - public void RegisterSingleInstance<T>(Func<T> func) - where T : class - { - _container.RegisterSingle(func); - } - - /// <summary> - /// Resolves this instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T Resolve<T>() - { - return (T)_container.GetRegistration(typeof(T), true).GetInstance(); - } - - /// <summary> - /// Resolves this instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T TryResolve<T>() - { - var result = _container.GetRegistration(typeof(T), false); - - if (result == null) - { - return default(T); - } - return (T)result.GetInstance(); - } - - /// <summary> - /// Registers the specified service type. - /// </summary> - /// <param name="serviceType">Type of the service.</param> - /// <param name="implementation">Type of the concrete.</param> - public void Register(Type serviceType, Type implementation) - { - _container.Register(serviceType, implementation); - } } } diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs new file mode 100644 index 000000000..40e190756 --- /dev/null +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -0,0 +1,498 @@ +using BDInfo; +using MediaBrowser.ClickOnce; +using MediaBrowser.Common.Implementations.ScheduledTasks; +using MediaBrowser.Common.Implementations.Serialization; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Net; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller; +using MediaBrowser.IsoMounter; +using MediaBrowser.Logging.Nlog; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.System; +using MediaBrowser.Model.Updates; +using MediaBrowser.Networking.Management; +using MediaBrowser.Networking.Udp; +using MediaBrowser.Networking.Web; +using MediaBrowser.Networking.WebSocket; +using MediaBrowser.Server.Implementations; +using MediaBrowser.ServerApplication.Implementations; +using SimpleInjector; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.ServerApplication +{ + /// <summary> + /// Class CompositionRoot + /// </summary> + public class ApplicationHost : IApplicationHost, IDisposable + { + /// <summary> + /// Gets or sets the logger. + /// </summary> + /// <value>The logger.</value> + private ILogger Logger { get; set; } + + /// <summary> + /// Gets or sets the iso manager. + /// </summary> + /// <value>The iso manager.</value> + private IIsoManager IsoManager { get; set; } + + /// <summary> + /// Gets or sets the log file path. + /// </summary> + /// <value>The log file path.</value> + public string LogFilePath { get; private set; } + + /// <summary> + /// The container + /// </summary> + private readonly Container _container = new Container(); + + /// <summary> + /// Gets or sets the kernel. + /// </summary> + /// <value>The kernel.</value> + public Kernel Kernel { get; private set; } + + private readonly List<string> _failedAssemblies = new List<string>(); + /// <summary> + /// Gets assemblies that failed to load + /// </summary> + public IEnumerable<string> FailedAssemblies + { + get { return _failedAssemblies; } + } + + /// <summary> + /// Gets all types within all running assemblies + /// </summary> + /// <value>All types.</value> + public Type[] AllTypes { get; private set; } + + /// <summary> + /// Gets all concrete types. + /// </summary> + /// <value>All concrete types.</value> + public Type[] AllConcreteTypes { get; private set; } + + /// <summary> + /// The disposable parts + /// </summary> + private readonly List<IDisposable> _disposableParts = new List<IDisposable>(); + + /// <summary> + /// The json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer = new JsonSerializer(); + + /// <summary> + /// The _XML serializer + /// </summary> + private readonly IXmlSerializer _xmlSerializer = new XmlSerializer(); + + /// <summary> + /// The _application paths + /// </summary> + private readonly IServerApplicationPaths _applicationPaths = new ServerApplicationPaths(); + + /// <summary> + /// The _task manager + /// </summary> + private readonly ITaskManager _taskManager; + + /// <summary> + /// Initializes a new instance of the <see cref="ApplicationHost" /> class. + /// </summary> + /// <param name="logger">The logger.</param> + public ApplicationHost(ILogger logger) + { + Logger = logger; + + _taskManager = new TaskManager(_applicationPaths, _jsonSerializer, Logger); + + Kernel = new Kernel(this, _applicationPaths, _xmlSerializer, _taskManager, Logger); + + RegisterResources(); + + FindParts(); + } + + /// <summary> + /// Registers resources that classes will depend on + /// </summary> + internal void RegisterResources() + { + DiscoverTypes(); + + RegisterSingleInstance<IKernel>(Kernel); + RegisterSingleInstance(Kernel); + + RegisterSingleInstance<IApplicationHost>(this); + RegisterSingleInstance(Logger); + + IsoManager = new PismoIsoManager(Logger); + + RegisterSingleInstance(_applicationPaths); + RegisterSingleInstance<IApplicationPaths>(_applicationPaths); + + RegisterSingleInstance(IsoManager); + RegisterSingleInstance(_taskManager); + RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer()); + RegisterSingleInstance<INetworkManager>(() => new NetworkManager()); + RegisterSingleInstance<IZipClient>(() => new DotNetZipClient()); + RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger)); + RegisterSingleInstance(_jsonSerializer); + RegisterSingleInstance(_xmlSerializer); + RegisterSingleInstance<IProtobufSerializer>(() => ProtobufSerializer); + Register(typeof(IUdpServer), typeof(UdpServer)); + RegisterSingleInstance(() => ServerFactory.CreateServer(this, Kernel, ProtobufSerializer, Logger, "Media Browser", "index.html")); + } + + /// <summary> + /// Discovers the types. + /// </summary> + private void DiscoverTypes() + { + _failedAssemblies.Clear(); + + AllTypes = GetComposablePartAssemblies().SelectMany(GetTypes).ToArray(); + + AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray(); + } + + /// <summary> + /// Finds the parts. + /// </summary> + private void FindParts() + { + _taskManager.AddTasks(GetExports<IScheduledTask>(false)); + } + + /// <summary> + /// Gets a list of types within an assembly + /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference + /// </summary> + /// <param name="assembly">The assembly.</param> + /// <returns>IEnumerable{Type}.</returns> + /// <exception cref="System.ArgumentNullException">assembly</exception> + private IEnumerable<Type> GetTypes(Assembly assembly) + { + if (assembly == null) + { + throw new ArgumentNullException("assembly"); + } + + try + { + return assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + // If it fails we can still get a list of the Types it was able to resolve + return ex.Types.Where(t => t != null); + } + } + + /// <summary> + /// The _protobuf serializer initialized + /// </summary> + private bool _protobufSerializerInitialized; + /// <summary> + /// The _protobuf serializer sync lock + /// </summary> + private object _protobufSerializerSyncLock = new object(); + /// <summary> + /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection + /// </summary> + private ProtobufSerializer _protobufSerializer; + /// <summary> + /// Gets the protobuf serializer. + /// </summary> + /// <value>The protobuf serializer.</value> + public ProtobufSerializer ProtobufSerializer + { + get + { + // Lazy load + LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => ProtobufSerializer.Create(AllTypes)); + return _protobufSerializer; + } + private set + { + _protobufSerializer = value; + _protobufSerializerInitialized = value != null; + } + } + + /// <summary> + /// Creates an instance of type and resolves all constructor dependancies + /// </summary> + /// <param name="type">The type.</param> + /// <returns>System.Object.</returns> + public object CreateInstance(Type type) + { + try + { + return _container.GetInstance(type); + } + catch + { + Logger.Error("Error creating {0}", type.Name); + + throw; + } + } + + /// <summary> + /// Registers the specified obj. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="obj">The obj.</param> + public void RegisterSingleInstance<T>(T obj) + where T : class + { + _container.RegisterSingle(obj); + } + + /// <summary> + /// Registers the specified func. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func">The func.</param> + public void Register<T>(Func<T> func) + where T : class + { + _container.Register(func); + } + + /// <summary> + /// Registers the single instance. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func">The func.</param> + public void RegisterSingleInstance<T>(Func<T> func) + where T : class + { + _container.RegisterSingle(func); + } + + /// <summary> + /// Resolves this instance. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns>``0.</returns> + public T Resolve<T>() + { + return (T)_container.GetRegistration(typeof(T), true).GetInstance(); + } + + /// <summary> + /// Resolves this instance. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns>``0.</returns> + public T TryResolve<T>() + { + var result = _container.GetRegistration(typeof(T), false); + + if (result == null) + { + return default(T); + } + return (T)result.GetInstance(); + } + + /// <summary> + /// Registers the specified service type. + /// </summary> + /// <param name="serviceType">Type of the service.</param> + /// <param name="implementation">Type of the concrete.</param> + public void Register(Type serviceType, Type implementation) + { + _container.Register(serviceType, implementation); + } + + /// <summary> + /// Restarts this instance. + /// </summary> + /// <exception cref="System.NotImplementedException"></exception> + public void Restart() + { + App.Instance.Restart(); + } + + /// <summary> + /// Reloads the logger. + /// </summary> + /// <exception cref="System.NotImplementedException"></exception> + public void ReloadLogger() + { + LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log"); + + NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging); + } + + /// <summary> + /// Gets or sets a value indicating whether this instance can self update. + /// </summary> + /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value> + public bool CanSelfUpdate + { + get { return ClickOnceHelper.IsNetworkDeployed; } + } + + /// <summary> + /// Checks for update. + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <param name="progress">The progress.</param> + /// <returns>Task{CheckForUpdateResult}.</returns> + public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress) + { + return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress); + } + + /// <summary> + /// Updates the application. + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <param name="progress">The progress.</param> + /// <returns>Task.</returns> + public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress) + { + return new ApplicationUpdater().UpdateApplication(cancellationToken, progress); + } + + /// <summary> + /// Gets the composable part assemblies. + /// </summary> + /// <returns>IEnumerable{Assembly}.</returns> + private IEnumerable<Assembly> GetComposablePartAssemblies() + { + // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that + // This will prevent the .dll file from getting locked, and allow us to replace it when needed + foreach (var pluginAssembly in Directory + .EnumerateFiles(Kernel.ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) + .Select(LoadAssembly).Where(a => a != null)) + { + yield return pluginAssembly; + } + + var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); + var corePluginDirectory = Path.Combine(runningDirectory, "CorePlugins"); + + // This will prevent the .dll file from getting locked, and allow us to replace it when needed + foreach (var pluginAssembly in Directory + .EnumerateFiles(corePluginDirectory, "*.dll", SearchOption.TopDirectoryOnly) + .Select(LoadAssembly).Where(a => a != null)) + { + yield return pluginAssembly; + } + + // Include composable parts in the Model assembly + yield return typeof(SystemInfo).Assembly; + + // Include composable parts in the Common assembly + yield return typeof(IKernel).Assembly; + + // Include composable parts in the Controller assembly + yield return typeof(Kernel).Assembly; + + // Common implementations + yield return typeof(TaskManager).Assembly; + + // Server implementations + yield return typeof(ServerApplicationPaths).Assembly; + + // Include composable parts in the running assembly + yield return GetType().Assembly; + } + + /// <summary> + /// Loads the assembly. + /// </summary> + /// <param name="file">The file.</param> + /// <returns>Assembly.</returns> + private Assembly LoadAssembly(string file) + { + try + { + return Assembly.Load(File.ReadAllBytes((file))); + } + catch (Exception ex) + { + _failedAssemblies.Add(file); + Logger.ErrorException("Error loading assembly {0}", ex, file); + return null; + } + } + + /// <summary> + /// Gets the exports. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="allTypes">All types.</param> + /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param> + /// <returns>IEnumerable{``0}.</returns> + public IEnumerable<T> GetExports<T>(bool manageLiftime = true) + { + var currentType = typeof(T); + + Logger.Info("Composing instances of " + currentType.Name); + + var parts = AllConcreteTypes.Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray(); + + if (manageLiftime) + { + _disposableParts.AddRange(parts.OfType<IDisposable>()); + } + + return parts; + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + } + + /// <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) + { + IsoManager.Dispose(); + + foreach (var part in _disposableParts) + { + part.Dispose(); + } + + _disposableParts.Clear(); + } + } + + public class MyClass + { + public MyClass() + { + + } + } +} diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs index 02dd6fb9c..59961a941 100644 --- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs +++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs @@ -1,11 +1,12 @@ -using MediaBrowser.Common.Serialization; -using MediaBrowser.Controller; +using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Globalization; @@ -18,7 +19,6 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media.Imaging; -using MediaBrowser.Model.Logging; namespace MediaBrowser.ServerApplication { @@ -27,8 +27,10 @@ namespace MediaBrowser.ServerApplication /// </summary> public partial class LibraryExplorer : Window { - private ILogger _logger; + private readonly ILogger _logger; + private readonly IJsonSerializer _jsonSerializer; + /// <summary> /// The current user /// </summary> @@ -36,9 +38,10 @@ namespace MediaBrowser.ServerApplication /// <summary> /// Initializes a new instance of the <see cref="LibraryExplorer" /> class. /// </summary> - public LibraryExplorer(ILogger logger) + public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger) { _logger = logger; + _jsonSerializer = jsonSerializer; InitializeComponent(); lblVersion.Content = "Version: " + Kernel.Instance.ApplicationVersion; @@ -161,7 +164,7 @@ namespace MediaBrowser.ServerApplication lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Hidden; } - txtData.Text = FormatJson(JsonSerializer.SerializeToString(item)) + trailers + features; + txtData.Text = FormatJson(_jsonSerializer.SerializeToString(item)) + trailers + features; var previews = new List<PreviewItem>(); await Task.Run(() => diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs index 8a312e7ef..332bb1daa 100644 --- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs +++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using MediaBrowser.ServerApplication.Controls; using MediaBrowser.ServerApplication.Logging; using System; @@ -39,6 +40,11 @@ namespace MediaBrowser.ServerApplication private Timer NewItemTimer { get; set; } /// <summary> + /// The _json serializer + /// </summary> + private readonly IJsonSerializer _jsonSerializer; + + /// <summary> /// The _logger /// </summary> private readonly ILogger _logger; @@ -48,13 +54,18 @@ namespace MediaBrowser.ServerApplication /// </summary> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">logger</exception> - public MainWindow(ILogger logger) + public MainWindow(IJsonSerializer jsonSerializer, ILogger logger) { + if (jsonSerializer == null) + { + throw new ArgumentNullException("jsonSerializer"); + } if (logger == null) { throw new ArgumentNullException("logger"); } + _jsonSerializer = jsonSerializer; _logger = logger; InitializeComponent(); @@ -282,7 +293,7 @@ namespace MediaBrowser.ServerApplication /// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param> private void cmOpenExplorer_click(object sender, RoutedEventArgs e) { - (new LibraryExplorer(_logger)).Show(); + (new LibraryExplorer(_jsonSerializer, _logger)).Show(); } /// <summary> diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index b1c57949c..8a3a0b7af 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -128,36 +128,6 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\ThirdParty\UPnP\Libs\Platinum.Managed.dll</HintPath> </Reference> - <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite.SqlServer"> - <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Redis"> - <HintPath>..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath> - </Reference> <Reference Include="SimpleInjector, Version=2.0.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\SimpleInjector.2.0.0-beta5\lib\net40-client\SimpleInjector.dll</HintPath> @@ -220,6 +190,7 @@ <DependentUpon>App.xaml</DependentUpon> <SubType>Code</SubType> </Compile> + <Compile Include="ApplicationHost.cs" /> <Compile Include="Controls\ItemUpdateNotification.xaml.cs"> <DependentUpon>ItemUpdateNotification.xaml</DependentUpon> </Compile> @@ -279,6 +250,10 @@ <Project>{cc96bf3e-0bda-4809-bc4b-bb6d418f4a84}</Project> <Name>MediaBrowser.ClickOnce</Name> </ProjectReference> + <ProjectReference Include="..\MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj"> + <Project>{c4d2573a-3fd3-441f-81af-174ac4cd4e1d}</Project> + <Name>MediaBrowser.Common.Implementations</Name> + </ProjectReference> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project> <Name>MediaBrowser.Common</Name> @@ -303,6 +278,10 @@ <Project>{7c11010e-179a-49b7-bfb2-f1656f5e71ad}</Project> <Name>MediaBrowser.Networking</Name> </ProjectReference> + <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj"> + <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project> + <Name>MediaBrowser.Server.Implementations</Name> + </ProjectReference> <ProjectReference Include="..\MediaBrowser.Server.Uninstall\MediaBrowser.Server.Uninstall.csproj"> <Project>{5443422f-9548-417a-90dd-2fc91f2b5999}</Project> <Name>MediaBrowser.Server.Uninstall</Name> diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config index 28d6202f8..e1beae6da 100644 --- a/MediaBrowser.ServerApplication/packages.config +++ b/MediaBrowser.ServerApplication/packages.config @@ -3,11 +3,6 @@ <package id="DotNetZip" version="1.9.1.8" targetFramework="net45" /> <package id="Hardcodet.Wpf.TaskbarNotification" version="1.0.4.0" targetFramework="net45" /> <package id="NLog" version="2.0.0.2000" targetFramework="net45" /> - <package id="ServiceStack" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" /> <package id="SimpleInjector" version="2.0.0-beta5" targetFramework="net45" /> <package id="System.Data.SQLite" version="1.0.84.0" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index aca931306..b321cc8d9 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -1,7 +1,6 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.ScheduledTasks.Tasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; @@ -137,7 +136,7 @@ namespace MediaBrowser.WebDashboard.Api .Select(ScheduledTaskHelpers.GetTaskInfo) .ToArray(), - ApplicationUpdateTaskId = taskManager.ScheduledTasks.OfType<SystemUpdateTask>().First().Id, + ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id, ActiveConnections = connections, diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 3f053e2d8..9ce346417 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -20,8 +20,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Performance19.psess = Performance19.psess EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction.Javascript", "MediaBrowser.ApiInteraction.Javascript\MediaBrowser.ApiInteraction.Javascript.csproj", "{767B536E-D90C-4D74-A14B-8564B16F3499}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction", "MediaBrowser.ApiInteraction\MediaBrowser.ApiInteraction.csproj", "{921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction.Portable", "MediaBrowser.ApiInteraction.Portable\MediaBrowser.ApiInteraction.Portable.csproj", "{52E0C440-85C0-4A99-ACFE-07C87B2600BE}" @@ -41,10 +39,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.IsoMounter", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Installer", "MediaBrowser.Installer\MediaBrowser.Installer.csproj", "{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Sqlite", "MediaBrowser.Server.Sqlite\MediaBrowser.Server.Sqlite.csproj", "{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.WorldWeatherOnline", "MediaBrowser.Server.WorldWeatherOnline\MediaBrowser.Server.WorldWeatherOnline.csproj", "{973CA45C-8362-490B-8327-C68098FD4891}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Logging.NLog", "MediaBrowser.Logging.NLog\MediaBrowser.Logging.NLog.csproj", "{67310740-0EC4-4DC2-9921-33DF38B20167}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ClickOnce", "MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj", "{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}" @@ -53,6 +47,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Networking", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Uninstaller", "MediaBrowser.Uninstaller\MediaBrowser.Uninstaller.csproj", "{FACAF749-3E28-46DD-B613-654FCD434959}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common.Implementations", "MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj", "{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -163,21 +161,6 @@ Global {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x64.ActiveCfg = Release|Any CPU {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Any CPU.Build.0 = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Win32.ActiveCfg = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|x64.ActiveCfg = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|x86.ActiveCfg = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|x86.Build.0 = Debug|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Any CPU.ActiveCfg = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Any CPU.Build.0 = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Win32.ActiveCfg = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|x64.ActiveCfg = Release|Any CPU - {767B536E-D90C-4D74-A14B-8564B16F3499}.Release|x86.ActiveCfg = Release|Any CPU {921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}.Debug|Any CPU.Build.0 = Debug|Any CPU {921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -266,34 +249,6 @@ Global {3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Release|Win32.ActiveCfg = Release|Any CPU {3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Release|x64.ActiveCfg = Release|Any CPU {3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Release|x86.ActiveCfg = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Win32.ActiveCfg = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|x64.ActiveCfg = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|x86.ActiveCfg = Debug|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Any CPU.Build.0 = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Win32.ActiveCfg = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|x64.ActiveCfg = Release|Any CPU - {8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|x86.ActiveCfg = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|Any CPU.Build.0 = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|Win32.ActiveCfg = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|x64.ActiveCfg = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Debug|x86.ActiveCfg = Debug|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|Any CPU.ActiveCfg = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|Any CPU.Build.0 = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|Win32.ActiveCfg = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|x64.ActiveCfg = Release|Any CPU - {973CA45C-8362-490B-8327-C68098FD4891}.Release|x86.ActiveCfg = Release|Any CPU {67310740-0EC4-4DC2-9921-33DF38B20167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67310740-0EC4-4DC2-9921-33DF38B20167}.Debug|Any CPU.Build.0 = Debug|Any CPU {67310740-0EC4-4DC2-9921-33DF38B20167}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -350,6 +305,34 @@ Global {FACAF749-3E28-46DD-B613-654FCD434959}.Release|Win32.ActiveCfg = Release|Any CPU {FACAF749-3E28-46DD-B613-654FCD434959}.Release|x64.ActiveCfg = Release|Any CPU {FACAF749-3E28-46DD-B613-654FCD434959}.Release|x86.ActiveCfg = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Win32.ActiveCfg = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x64.ActiveCfg = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.Build.0 = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Win32.ActiveCfg = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x64.ActiveCfg = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Win32.ActiveCfg = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x64.ActiveCfg = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.Build.0 = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Win32.ActiveCfg = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x64.ActiveCfg = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |
