From 23fff6740cb8bb7d6cc83466935b36647dabb037 Mon Sep 17 00:00:00 2001 From: vitska Date: Sun, 23 Aug 2015 15:56:30 +0300 Subject: [PATCH 1/4] ByDateView has been added with some NUnit testing --- .gitignore | 1 + sdlna.sln | 10 ++- server/Views/ByDateView.cs | 63 ++++++++++++++++++ server/server.csproj | 1 + tests/ByDateViewTest.cs | 50 +++++++++++++++ tests/ByTitleViewTest.cs | 42 ++++++++++++ tests/Mocks/MediaFolder.cs | 88 +++++++++++++++++++++++++ tests/Mocks/MediaResource.cs | 45 +++++++++++++ tests/Mocks/View.cs | 36 +++++++++++ tests/Properties/AssemblyInfo.cs | 36 +++++++++++ tests/packages.config | 4 ++ tests/tests.csproj | 107 +++++++++++++++++++++++++++++++ util/util.csproj | 8 --- 13 files changed, 481 insertions(+), 10 deletions(-) create mode 100644 server/Views/ByDateView.cs create mode 100644 tests/ByDateViewTest.cs create mode 100644 tests/ByTitleViewTest.cs create mode 100644 tests/Mocks/MediaFolder.cs create mode 100644 tests/Mocks/MediaResource.cs create mode 100644 tests/Mocks/View.cs create mode 100644 tests/Properties/AssemblyInfo.cs create mode 100644 tests/packages.config create mode 100644 tests/tests.csproj diff --git a/.gitignore b/.gitignore index 9560bb6b..bd5add46 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ setup/Release setup/*.cmd pages/ cov-int* +/UpgradeLog.htm diff --git a/sdlna.sln b/sdlna.sln index 710aa9eb..c74e4a2b 100644 --- a/sdlna.sln +++ b/sdlna.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sdlna", "sdlna\sdlna.csproj", "{C99E77FD-0728-4A2F-A9C0-47AAC7CAEFED}" EndProject @@ -34,6 +34,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{311651 .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -70,6 +72,10 @@ Global {56667283-EBCD-4D63-BF61-FF319CB28A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU {56667283-EBCD-4D63-BF61-FF319CB28A0B}.Release|Any CPU.ActiveCfg = Release|Any CPU {56667283-EBCD-4D63-BF61-FF319CB28A0B}.Release|Any CPU.Build.0 = Release|Any CPU + {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/server/Views/ByDateView.cs b/server/Views/ByDateView.cs new file mode 100644 index 00000000..b43a1804 --- /dev/null +++ b/server/Views/ByDateView.cs @@ -0,0 +1,63 @@ +using NMaier.SimpleDlna.Server.Metadata; +using System.Linq; + +namespace NMaier.SimpleDlna.Server.Views +{ + internal sealed class ByDateView : BaseView + { + public override string Description + { + get + { + return "Reorganizes files into folders by date"; + } + } + + public override string Name + { + get + { + return "bydate"; + } + } + + private static void SortFolder(VirtualFolder folder, TitlesFolder titles) + { + folder.AllItems.GroupBy( + r => (r is IMetaInfo) ? ((r as IMetaInfo).InfoDate.ToString("yyyy-MMM")) : "Unknown", + r => r, + (k, g) => new { Key = k, Lst = g.ToList() } + ) + .ToList() + .ForEach(i => { + var tf = titles.GetFolder(i.Key); + i.Lst.ForEach(r => { + tf.AddResource(r); + folder.RemoveResource(r); + }); + }); + } + + public override IMediaFolder Transform(IMediaFolder Root) + { + var root = new VirtualClonedFolder(Root); + var titles = new TitlesFolder(root); + SortFolder(root, titles); + foreach (var i in root.ChildFolders.ToList()) { + root.ReleaseFolder(i); + } + foreach (var i in titles.ChildFolders.ToList()) { + root.AdoptFolder(i); + } + return root; + } + + private class TitlesFolder : KeyedVirtualFolder + { + public TitlesFolder(IMediaFolder aParent) + : base(aParent, "titles") + { + } + } + } +} diff --git a/server/server.csproj b/server/server.csproj index cba3a122..7461c244 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -141,6 +141,7 @@ + diff --git a/tests/ByDateViewTest.cs b/tests/ByDateViewTest.cs new file mode 100644 index 00000000..eaf04d4e --- /dev/null +++ b/tests/ByDateViewTest.cs @@ -0,0 +1,50 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.Server.Comparers; +using System.Linq; +using tests.Mocks; +using NMaier.SimpleDlna.Server.Metadata; +using System; + +namespace SimpleDlna.Tests +{ + /// + /// ByDateViewTest transformation tests + /// + [TestFixture] + public class ByDateViewTest + { + + public class MediaResourceMockWithInfo : MediaResource, IMetaInfo + { + public DateTime InfoDate { get; set; } + + public long? InfoSize { get; set; } + } + + [Test] + public void ByDateView_RegisterFolder_Test() + { + var ids = new Identifiers(ComparerRepository.Lookup("title"), false); + ids.AddView("bydate"); + var f = new MediaFolder(); + var addRes = new[] { + new MediaResource() { Path = @"C:\somepath\resrouceZ.mkv", Title = "Z" } + ,new MediaResource() { Path = @"C:\somepath\resrouceY.mkv", Title = "Y" } + ,new MediaResource() { Path = @"C:\somepath\resrouceV.mkv", Title = "V" } + ,new MediaResource() { Path = @"C:\somepath\resrouceO.mkv", Title = "O" } + ,new MediaResource() { Path = @"C:\somepath\resrouceP.mkv", Title = "P" } + ,new MediaResource() { Path = @"C:\somepath\resrouceQ.mkv", Title = "Q" } + ,new MediaResourceMockWithInfo() { Path = @"C:\somepath\resrouceM.mkv", Title = "M", InfoDate = new DateTime(2015,1,1) } + ,new MediaResource() { Path = @"C:\somepath\resrouceE.mkv", Title = "E" } + }; + f.AccessorChildItems.AddRange(addRes); + f.AccessorChildFolders.Add(new MediaFolder() { Path = @"C:\somepath" }); + ids.RegisterFolder("tempid", f); + var res = ids.Resources; + Assert.IsTrue(res.Select(r => r.Target).ToList().Contains(addRes[2]), "Not contains added resource"); + Assert.IsNotNull(ids.GetItemByPath("/:/:2015-Jan"), @"GetItemByPath(""/:/:2015-Jan"") failed"); + Assert.AreEqual(ids.GetItemById(addRes[2].Id), addRes[2], "GetItemById(addRes[2].Id) failed"); + } + } +} diff --git a/tests/ByTitleViewTest.cs b/tests/ByTitleViewTest.cs new file mode 100644 index 00000000..b03a804a --- /dev/null +++ b/tests/ByTitleViewTest.cs @@ -0,0 +1,42 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.Server.Comparers; +using System.Linq; +using tests.Mocks; + +namespace tests +{ + /// + /// ByTitleView transformation tests + /// + [TestFixture] + public class ByTitleViewTest + { + + [Test] + public void ByTitleView_RegisterFolder_Test() + { + var ids = new Identifiers(ComparerRepository.Lookup("title"), false); + ids.AddView("bytitle"); + var f = new MediaFolder(); + var addRes = new[] { + new MediaResource() { Path = @"C:\somepath\resrouceZ.mkv", Title = "Z" } + ,new MediaResource() { Path = @"C:\somepath\resrouceY.mkv", Title = "Y" } + ,new MediaResource() { Path = @"C:\somepath\resrouceV.mkv", Title = "V" } + ,new MediaResource() { Path = @"C:\somepath\resrouceO.mkv", Title = "O" } + ,new MediaResource() { Path = @"C:\somepath\resrouceP.mkv", Title = "P" } + ,new MediaResource() { Path = @"C:\somepath\resrouceQ.mkv", Title = "Q" } + ,new MediaResource() { Path = @"C:\somepath\resrouceM.mkv", Title = "M" } + ,new MediaResource() { Path = @"C:\somepath\resrouceE.mkv", Title = "E" } + }; + f.AccessorChildItems.AddRange(addRes); + f.AccessorChildFolders.Add(new MediaFolder() { Path = @"C:\somepath" }); + ids.RegisterFolder("tempid", f); + var res = ids.Resources; + Assert.IsTrue(res.Select(r => r.Target).ToList().Contains(addRes[2]), "Not contains added resource"); + Assert.IsNotNull(ids.GetItemByPath("/:/:Q"), "GetItemByPath(\"/:/:Q\") failed"); + Assert.AreEqual(ids.GetItemById(addRes[2].Id), addRes[2]); + //target.Load(); + } + } +} diff --git a/tests/Mocks/MediaFolder.cs b/tests/Mocks/MediaFolder.cs new file mode 100644 index 00000000..ee20cb84 --- /dev/null +++ b/tests/Mocks/MediaFolder.cs @@ -0,0 +1,88 @@ +using NMaier.SimpleDlna.Server; +using System; +using System.Collections.Generic; + +namespace tests.Mocks +{ + public class MediaFolder : IMediaFolder + { + public int ChildCount + { + get + { + throw new NotImplementedException(); + } + } + + public List AccessorChildFolders = new List(); + + public IEnumerable ChildFolders + { + get + { + return AccessorChildFolders; + } + } + + public List AccessorChildItems = new List(); + + public IEnumerable ChildItems + { + get + { + return AccessorChildItems; + } + } + + public string Id { get; set; } + + public IMediaFolder Parent { get; set; } + + public string Path { get; set; } + + public IHeaders Properties { get; set; } + + public string Title { get; set; } + + public int FullChildCount + { + get + { + throw new NotImplementedException(); + } + } + + public void AddResource(IMediaResource res) + { + throw new NotImplementedException(); + } + + public void Cleanup() + { + } + + public int CompareTo(IMediaItem other) + { + throw new NotImplementedException(); + } + + public bool Equals(IMediaItem other) + { + throw new NotImplementedException(); + } + + public void RemoveResource(IMediaResource res) + { + throw new NotImplementedException(); + } + + public void Sort(IComparer comparer, bool descending) + { + } + + public string ToComparableTitle() + { + throw new NotImplementedException(); + } + } +} diff --git a/tests/Mocks/MediaResource.cs b/tests/Mocks/MediaResource.cs new file mode 100644 index 00000000..d37727f7 --- /dev/null +++ b/tests/Mocks/MediaResource.cs @@ -0,0 +1,45 @@ +using NMaier.SimpleDlna.Server; +using System; +using System.IO; + +namespace tests.Mocks +{ + public class MediaResource : IMediaResource + { + public IMediaCoverResource Cover { get; set; } + + public string Id { get; set; } + + public DlnaMediaTypes MediaType { get; set; } + + public string Path { get; set; } + + public string PN { get; set; } + + public IHeaders Properties { get; set; } + + public string Title { get; set; } + + public DlnaMime Type { get; set; } + + public int CompareTo(IMediaItem other) + { + throw new NotImplementedException(); + } + + public Stream CreateContentStream() + { + throw new NotImplementedException(); + } + + public bool Equals(IMediaItem other) + { + throw new NotImplementedException(); + } + + public string ToComparableTitle() + { + return this.Title; + } + } +} diff --git a/tests/Mocks/View.cs b/tests/Mocks/View.cs new file mode 100644 index 00000000..1ad4692f --- /dev/null +++ b/tests/Mocks/View.cs @@ -0,0 +1,36 @@ +using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.Server.Views; +using NMaier.SimpleDlna.Utilities; +using System; + +namespace tests.Mocks +{ + public class View : IView + { + public string Description + { + get + { + return string.Format("[{0}] - Description", this.GetType().Name); + } + } + + public string Name + { + get + { + return this.GetType().Name; + } + } + + public void SetParameters(AttributeCollection parameters) + { + throw new NotImplementedException(); + } + + public IMediaFolder Transform(IMediaFolder root) + { + return root; + } + } +} diff --git a/tests/Properties/AssemblyInfo.cs b/tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..ce9534b8 --- /dev/null +++ b/tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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("tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("tests")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("ed38a2a8-c0e5-4881-8f8e-591b34fd2c06")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/packages.config b/tests/packages.config new file mode 100644 index 00000000..904dc42c --- /dev/null +++ b/tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/tests.csproj b/tests/tests.csproj new file mode 100644 index 00000000..b30a54b9 --- /dev/null +++ b/tests/tests.csproj @@ -0,0 +1,107 @@ + + + + Debug + AnyCPU + {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06} + Library + Properties + SimpleDlna.Tests + SimpleDLNA.Tests + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + {50e06b21-e11a-42f0-81e2-0911e771e861} + fsserver + + + {232a96f6-a2bf-44c8-b623-6e411f6296f2} + server + + + {a8960a7a-887c-40d7-9632-002e94bfc830} + util + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/util/util.csproj b/util/util.csproj index 3eb3b7ad..2f7caaf0 100644 --- a/util/util.csproj +++ b/util/util.csproj @@ -93,14 +93,6 @@ - - - Always - - - Always - - From 3b873f87a77d1ca7b480a12184442efbbb1b5469 Mon Sep 17 00:00:00 2001 From: vitska Date: Thu, 27 Aug 2015 00:26:52 +0300 Subject: [PATCH 2/4] A bit of restructuring, isolated SQLite FileStore, FileStore abstraction/interfaces not completed (needs proper datafiles deletion) isolated log4net to utilities assembly only added key-value store, raptorDB --- FileStoreRaptorDB/FileStore.cs | 92 +++ FileStoreRaptorDB/FileStoreRaptorDB.csproj | 77 ++ FileStoreRaptorDB/Properties/AssemblyInfo.cs | 36 + FileStoreRaptorDB/packages.config | 4 + FileStoreRaptorDB/sdlna.key.snk | Bin 0 -> 596 bytes {util => FileStoreSQLite}/App.config | 13 +- .../Files => FileStoreSQLite}/FileStore.cs | 249 +++--- FileStoreSQLite/FileStoreSQLite.csproj | 109 +++ .../FileStoreVacuumer.cs | 2 +- FileStoreSQLite/Properties/AssemblyInfo.cs | 36 + {util => FileStoreSQLite}/Sqlite.cs | 8 +- FileStoreSQLite/packages.config | 8 + FileStoreSQLite/sdlna.key.snk | Bin 0 -> 596 bytes NMaier.Windows.Forms/Form.cs | 1 - .../NMaier.Windows.Forms.csproj | 2 +- SimpleDLNA/FormAbout.cs | 2 - SimpleDLNA/FormMain.cs | 69 +- SimpleDLNA/FormServer.Designer.cs | 154 ++-- SimpleDLNA/FormServer.cs | 19 +- SimpleDLNA/Properties/Settings.Designer.cs | 6 +- SimpleDLNA/Properties/Settings.settings | 2 +- SimpleDLNA/ServerDescription.cs | 3 + SimpleDLNA/ServerListViewItem.cs | 13 +- SimpleDLNA/SimpleDLNA.csproj | 35 +- SimpleDLNA/SimpleDLNA_TemporaryKey.pfx | Bin 0 -> 1660 bytes SimpleDLNA/app.config | 2 +- SimpleDLNA/public.pk | Bin 0 -> 160 bytes fsserver/BackgroundCacher.cs | 10 +- fsserver/FileServer.cs | 50 +- fsserver/FileStoreReader.cs | 99 +++ fsserver/FileStoreRepository.cs | 8 + fsserver/FileStoreWriter.cs | 49 ++ fsserver/Files/AudioFile.cs | 12 +- fsserver/Files/BaseFile.cs | 19 +- fsserver/Files/Cover.cs | 2 +- fsserver/Files/FileReadStream.cs | 8 +- fsserver/Files/ImageFile.cs | 10 +- fsserver/Files/VideoFile.cs | 12 +- fsserver/IFileStore.cs | 16 + fsserver/IStoreItem.cs | 10 + fsserver/Properties/AssemblyInfo.cs | 6 + fsserver/SerializeHelper.cs | 6 + fsserver/fsserver.csproj | 18 +- fsserver/packages.config | 1 - sdlna.sln | 14 + sdlna/Program.cs | 22 +- sdlna/sdlna.csproj | 2 +- server/Handlers/MediaMount.cs | 16 +- server/Handlers/MediaMount_SOAP.cs | 5 +- server/Http/HTTPServer.cs | 35 +- server/Http/HttpAuthorizer.cs | 13 +- server/Http/HttpClient.cs | 41 +- server/Http/IPAddressAuthorizer.cs | 9 +- server/Http/MacAuthorizer.cs | 9 +- server/Http/UserAgentAuthorizer.cs | 9 +- server/Responses/ItemResponse.cs | 9 +- server/Responses/ResourceResponse.cs | 7 +- server/Ssdp/Datagram.cs | 7 +- server/Ssdp/SsdpHandler.cs | 31 +- server/Types/Identifiers.cs | 7 +- server/Types/SubTitle.cs | 10 +- server/Views/BaseView.cs | 4 +- server/Views/ByTitleView.cs | 6 +- server/Views/FilterView.cs | 3 +- server/Views/LargeView.cs | 1 - server/packages.config | 4 - server/server.csproj | 7 +- tests/App.config | 24 + tests/ByTitleViewTest.cs | 2 +- tests/FileStoreReaderWriterTest.cs | 105 +++ tests/FileStoreTest.cs | 66 ++ tests/Mocks/StoreItem.cs | 19 + tests/ServerDescriptionTest.cs | 55 ++ tests/Utilities/ReflectionHelperTest.cs | 34 + tests/Utilities/RepositoryBaseTest.cs | 22 + tests/Utilities/RepositoryTest.cs | 67 ++ tests/img/Patern_test.jpg | Bin 0 -> 36623 bytes tests/packages.config | 6 + tests/sdlna.key.snk | Bin 0 -> 596 bytes tests/tests.csproj | 66 ++ thumbs/ThumbnailMaker.cs | 7 +- thumbs/packages.config | 4 - thumbs/thumbs.csproj | 7 +- util/DataPath.cs | 51 ++ util/ILogging.cs | 769 ++++++++++++++++++ util/Logging.cs | 20 +- util/ReflectionHelper.cs | 49 ++ util/Repository.cs | 7 +- util/RepositoryBase.cs | 33 + util/XmlHelper.cs | 26 + util/packages.config | 5 - util/util.csproj | 28 +- 92 files changed, 2533 insertions(+), 488 deletions(-) create mode 100644 FileStoreRaptorDB/FileStore.cs create mode 100644 FileStoreRaptorDB/FileStoreRaptorDB.csproj create mode 100644 FileStoreRaptorDB/Properties/AssemblyInfo.cs create mode 100644 FileStoreRaptorDB/packages.config create mode 100644 FileStoreRaptorDB/sdlna.key.snk rename {util => FileStoreSQLite}/App.config (53%) rename {fsserver/Files => FileStoreSQLite}/FileStore.cs (60%) create mode 100644 FileStoreSQLite/FileStoreSQLite.csproj rename {fsserver/Files => FileStoreSQLite}/FileStoreVacuumer.cs (98%) create mode 100644 FileStoreSQLite/Properties/AssemblyInfo.cs rename {util => FileStoreSQLite}/Sqlite.cs (94%) create mode 100644 FileStoreSQLite/packages.config create mode 100644 FileStoreSQLite/sdlna.key.snk create mode 100644 SimpleDLNA/SimpleDLNA_TemporaryKey.pfx create mode 100644 SimpleDLNA/public.pk create mode 100644 fsserver/FileStoreReader.cs create mode 100644 fsserver/FileStoreRepository.cs create mode 100644 fsserver/FileStoreWriter.cs create mode 100644 fsserver/IFileStore.cs create mode 100644 fsserver/IStoreItem.cs create mode 100644 fsserver/SerializeHelper.cs delete mode 100644 server/packages.config create mode 100644 tests/App.config create mode 100644 tests/FileStoreReaderWriterTest.cs create mode 100644 tests/FileStoreTest.cs create mode 100644 tests/Mocks/StoreItem.cs create mode 100644 tests/ServerDescriptionTest.cs create mode 100644 tests/Utilities/ReflectionHelperTest.cs create mode 100644 tests/Utilities/RepositoryBaseTest.cs create mode 100644 tests/Utilities/RepositoryTest.cs create mode 100644 tests/img/Patern_test.jpg create mode 100644 tests/sdlna.key.snk delete mode 100644 thumbs/packages.config create mode 100644 util/DataPath.cs create mode 100644 util/ILogging.cs create mode 100644 util/ReflectionHelper.cs create mode 100644 util/RepositoryBase.cs create mode 100644 util/XmlHelper.cs delete mode 100644 util/packages.config diff --git a/FileStoreRaptorDB/FileStore.cs b/FileStoreRaptorDB/FileStore.cs new file mode 100644 index 00000000..cef86bfc --- /dev/null +++ b/FileStoreRaptorDB/FileStore.cs @@ -0,0 +1,92 @@ +using NMaier.SimpleDlna.FileMediaServer; +using NMaier.SimpleDlna.Utilities; +using System; +using System.Linq; +using System.IO; +using RaptorDB; + +namespace NMaier.SimpleDlna.FileStore.RaptorDB +{///Logging, + public sealed class FileStore : IFileStore, IDisposable + { + public string Description + { + get + { + return "RaptorDB file cache"; + } + } + + public string Name + { + get + { + return "RaptorDB"; + } + } + + FileInfo _storeFile; + public string StoreFile { get { return _storeFile.FullName; } } + + private static readonly ILogging Logger = Logging.GetLogger(); + + public void Dispose() + { + _db.Shutdown(); + _db.Dispose(); + } + + public override string ToString() + { + return string.Format("{0} - {1}", Name, Description); + } + + public bool HasCover(IStoreItem file) + { + return MaybeGetCover(file) != null; + } + + RaptorDB _db; + + public const string DefaultFileName = "sdlna.cache.raptor.db"; + + public void Init() + { + var storePath = _parameters.Keys.Contains("file") ? Convert.ToString(_parameters.GetValuesForKey("file").First()):DefaultFileName; + if (!Path.IsPathRooted(storePath)) storePath = DataPath.Combine(storePath); + _storeFile = new FileInfo(storePath); + Logger.NoticeFormat("Opening [{0}] Store...", _storeFile); + _db = RaptorDB.Open(_storeFile.FullName, false); + } + + public const string CoverPrefix = "Cover$$"; + + public byte[] MaybeGetCover(IStoreItem file) + { + byte[] data; + _db.Get(CoverPrefix + file.Item.FullName, out data); + return data; + } + + public byte[] MaybeGetFile(FileInfo info) + { + byte[] data; + _db.Get(info.FullName, out data); + return data; + } + + public void MaybeStoreFile(IStoreItem file, byte[] data, byte[] coverData) + { + Logger.NoticeFormat("MaybeStoreFile [{0}][{1}][{2}]", file.Item.Name, (data == null)?0:data.Length, (coverData == null)?0:coverData.Length); + _db.Set(file.Item.FullName, data); + _db.Set(CoverPrefix + file.Item.FullName, coverData); + } + + AttributeCollection _parameters = new AttributeCollection(); + + public void SetParameters(AttributeCollection parameters) + { + _parameters = parameters; + } + } +} diff --git a/FileStoreRaptorDB/FileStoreRaptorDB.csproj b/FileStoreRaptorDB/FileStoreRaptorDB.csproj new file mode 100644 index 00000000..bc13cc51 --- /dev/null +++ b/FileStoreRaptorDB/FileStoreRaptorDB.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {6961F1C2-41E9-4E7F-8E88-7D4A259B3DF8} + Library + Properties + NMaier.SimpleDlna.FileStore.RaptorDB + SimpleDlna.FileStore.RaptorDB + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + bin\Release\ + TRACE + prompt + 4 + + + false + + + sdlna.key.snk + + + + ..\packages\RaptorDB.2.6\lib\net40\RaptorDB.dll + True + + + + + + + + + + + + + + + + {50e06b21-e11a-42f0-81e2-0911e771e861} + fsserver + + + {a8960a7a-887c-40d7-9632-002e94bfc830} + util + + + + + + + + + \ No newline at end of file diff --git a/FileStoreRaptorDB/Properties/AssemblyInfo.cs b/FileStoreRaptorDB/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..cfc71ae8 --- /dev/null +++ b/FileStoreRaptorDB/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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("FileStoreRaptorDB")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FileStoreRaptorDB")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("6961f1c2-41e9-4e7f-8e88-7d4a259b3df8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FileStoreRaptorDB/packages.config b/FileStoreRaptorDB/packages.config new file mode 100644 index 00000000..e687bd46 --- /dev/null +++ b/FileStoreRaptorDB/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/FileStoreRaptorDB/sdlna.key.snk b/FileStoreRaptorDB/sdlna.key.snk new file mode 100644 index 0000000000000000000000000000000000000000..7e30ff02411640e5807b8ad0cd32d48cb745a656 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098wMZfhN->^Nl!3Q5v`Qf>P>)O;|H|uoq zuPj4V8M{Ea1kspx>7m=~Ae!YB7=t~Qz7(eePd3*)*b-~%a=s#O%-qg-@GPL*z6kU% z_rZ(=MtAVlNt1D>hD!9B=erFs`79ybW%gd3zM6N_Iz>{qvKFQq3-ak6OzAl8eiW^5 zOmPO^+X<^b0=H&n5wTcZ@h~o%(e5cR`ANyM%ct%9+9zyuRGC)FvaweMtNrl97Qn?s zamy#uD|T9Fa{c1Xe}>8%>_pA#h$%?caA9j1AF}orjgSmyI)uGpHuDJnF1OsUd=E1f zk2K3S76+h```Oc3U-Wme{HL>gKQqG%c4rE&?-jpk?Bd~E{~Iw+B~Ie<1%V#pR@X6h zUL0C=sJ5rU`+_8=T9L8`X>Kum>Bx}^(cTRDci3P0&#SZP`)nVOm(7?_n}f*+*Mp7U zmFRHUQ!6(|%D+=Co!{Q0Z~W}FwtXwCa7kH`hx=NoeGPF&^xO(LADYK>4*RHvW)k>x z|D7R^sunBQ6`EaX1o|FX8_=_^$?&Ia*X5JrY%JL}CCd})RcW>S)I30*%)=lme~(fB zxem@c$eEzgW0%I70=#Mmb6fA5FbAk;x{*bL8hUCD9;m6A>$BHKjd@@%*%&I!(*-hm zqlVmC +
- - + - + - + + + + + + \ No newline at end of file diff --git a/fsserver/Files/FileStore.cs b/FileStoreSQLite/FileStore.cs similarity index 60% rename from fsserver/Files/FileStore.cs rename to FileStoreSQLite/FileStore.cs index 7d1d0437..69315873 100644 --- a/fsserver/Files/FileStore.cs +++ b/FileStoreSQLite/FileStore.cs @@ -1,63 +1,81 @@ -using NMaier.SimpleDlna.Server; using NMaier.SimpleDlna.Utilities; +using NMaier.SimpleDlna.FileMediaServer; using System; using System.Data; using System.Data.Common; using System.IO; using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters; -using System.Runtime.Serialization.Formatters.Binary; using System.Threading; +using System.Linq; -namespace NMaier.SimpleDlna.FileMediaServer -{ - internal sealed class FileStore : Logging, IDisposable +namespace NMaier.SimpleDlna.FileStore.SQLite +{//Logging, + public class FileStore : IFileStore { private const uint SCHEMA = 0x20140818; - private readonly IDbConnection connection; + private IDbConnection connection; - private readonly IDbCommand insert; + private IDbCommand insert; - private readonly IDbDataParameter insertCover; + private IDbDataParameter insertCover; - private readonly IDbDataParameter insertData; + private IDbDataParameter insertData; - private readonly IDbDataParameter insertKey; + private IDbDataParameter insertKey; - private readonly IDbDataParameter insertSize; + private IDbDataParameter insertSize; - private readonly IDbDataParameter insertTime; + private IDbDataParameter insertTime; - private readonly IDbCommand select; + private IDbCommand select; - private readonly IDbCommand selectCover; + private IDbCommand selectCover; - private readonly IDbDataParameter selectCoverKey; + private IDbDataParameter selectCoverKey; - private readonly IDbDataParameter selectCoverSize; + private IDbDataParameter selectCoverSize; - private readonly IDbDataParameter selectCoverTime; + private IDbDataParameter selectCoverTime; - private readonly IDbDataParameter selectKey; + private IDbDataParameter selectKey; - private readonly IDbDataParameter selectSize; + private IDbDataParameter selectSize; - private readonly IDbDataParameter selectTime; + private IDbDataParameter selectTime; private static readonly FileStoreVacuumer vacuumer = new FileStoreVacuumer(); + protected static readonly ILogging Logger = Logging.GetLogger(); + private readonly static object globalLock = new object(); - public readonly FileInfo StoreFile; + FileInfo _storeFile; + public string StoreFile { get { return _storeFile.FullName; } } - internal FileStore(FileInfo storeFile) + public string Description { - StoreFile = storeFile; + get + { + return "SQLite database file cache"; + } + } - OpenConnection(storeFile, out connection); + public string Name + { + get + { + return "SQLite"; + } + } + + public const string DefaultFileName = "sdlna.cache.sqlite"; + + public void Init() { + _storeFile = new FileInfo(_parameters.Keys.Contains("file") ? Convert.ToString(_parameters.GetValuesForKey("file").First()):DefaultFileName); + + OpenConnection(_storeFile, out connection); SetupDatabase(); select = connection.CreateCommand(); @@ -100,11 +118,15 @@ internal FileStore(FileInfo storeFile) insertCover.DbType = DbType.Binary; insertCover.ParameterName = "@cover"; - InfoFormat("FileStore at {0} is ready", storeFile.FullName); + Logger.InfoFormat("FileStore at {0} is ready", StoreFile); vacuumer.Add(connection); } + public FileStore() + { + } + private void OpenConnection(FileInfo storeFile, out IDbConnection newConnection) { @@ -120,7 +142,7 @@ private void OpenConnection(FileInfo storeFile, } } catch (Exception ex) { - NoticeFormat( + Logger.NoticeFormat( "Recreating database, schema update. ({0})", ex.Message ); @@ -170,7 +192,7 @@ private void SetupDatabase() } } - internal bool HasCover(BaseFile file) + public bool HasCover(IStoreItem file) { if (connection == null) { return false; @@ -186,105 +208,108 @@ internal bool HasCover(BaseFile file) return (data as byte[]) != null; } catch (DbException ex) { - Error("Failed to lookup file cover existence from store", ex); + Logger.Error("Failed to lookup file cover existence from store", ex); return false; } } } - internal Cover MaybeGetCover(BaseFile file) + public byte[] MaybeGetCover(IStoreItem file) { if (connection == null) { return null; } var info = file.Item; - byte[] data; + //byte[] data; lock (connection) { selectCoverKey.Value = info.FullName; selectCoverSize.Value = info.Length; selectCoverTime.Value = info.LastWriteTimeUtc.Ticks; try { - data = selectCover.ExecuteScalar() as byte[]; + return selectCover.ExecuteScalar() as byte[]; } catch (DbException ex) { - Error("Failed to lookup file cover from store", ex); + Logger.Error("Failed to lookup file cover from store", ex); return null; } } - if (data == null) { - return null; - } - try { - using (var s = new MemoryStream(data)) { - var ctx = new StreamingContext( - StreamingContextStates.Persistence, - new DeserializeInfo(null, info, DlnaMime.ImageJPEG) - ); - var formatter = new BinaryFormatter(null, ctx) { - TypeFormat = FormatterTypeStyle.TypesWhenNeeded, - AssemblyFormat = FormatterAssemblyStyle.Simple - }; - var rv = formatter.Deserialize(s) as Cover; - return rv; - } - } - catch (SerializationException ex) { - Debug("Failed to deserialize a cover", ex); - return null; - } - catch (Exception ex) { - Fatal("Failed to deserialize a cover", ex); - throw; - } + //if (data == null) { + // return null; + //} + //try { + // using (var s = new MemoryStream(data)) { + // var ctx = new StreamingContext( + // StreamingContextStates.Persistence, + // new DeserializeInfo(null, info, DlnaMime.ImageJPEG) + // ); + // var formatter = new BinaryFormatter(null, ctx) { + // TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + // AssemblyFormat = FormatterAssemblyStyle.Simple + // }; + // var rv = formatter.Deserialize(s) as Cover; + // return rv; + // } + //} + //catch (SerializationException ex) { + // Debug("Failed to deserialize a cover", ex); + // return null; + //} + //catch (Exception ex) { + // Fatal("Failed to deserialize a cover", ex); + // throw; + //} } - internal BaseFile MaybeGetFile(FileServer server, FileInfo info, - DlnaMime type) + public byte[] MaybeGetFile( + //FileServer server, + FileInfo info//, + //DlnaMime type + ) { if (connection == null) { return null; } - byte[] data; + //byte[] data; lock (connection) { selectKey.Value = info.FullName; selectSize.Value = info.Length; selectTime.Value = info.LastWriteTimeUtc.Ticks; try { - data = select.ExecuteScalar() as byte[]; + return select.ExecuteScalar() as byte[]; } catch (DbException ex) { - Error("Failed to lookup file from store", ex); + Logger.Error("Failed to lookup file from store", ex); return null; } } - if (data == null) { - return null; - } - try { - using (var s = new MemoryStream(data)) { - var ctx = new StreamingContext( - StreamingContextStates.Persistence, - new DeserializeInfo(server, info, type)); - var formatter = new BinaryFormatter(null, ctx) { - TypeFormat = FormatterTypeStyle.TypesWhenNeeded, - AssemblyFormat = FormatterAssemblyStyle.Simple - }; - var rv = formatter.Deserialize(s) as BaseFile; - rv.Item = info; - return rv; - } - } - catch (Exception ex) { - if (ex is TargetInvocationException || ex is SerializationException) { - Debug("Failed to deserialize an item", ex); - return null; - } - throw; - } + //if (data == null) { + // return null; + //} + //try { + // using (var s = new MemoryStream(data)) { + // var ctx = new StreamingContext( + // StreamingContextStates.Persistence, + // new DeserializeInfo(server, info, type)); + // var formatter = new BinaryFormatter(null, ctx) { + // TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + // AssemblyFormat = FormatterAssemblyStyle.Simple + // }; + // var rv = formatter.Deserialize(s) as BaseFile; + // rv.Item = info; + // return rv; + // } + //} + //catch (Exception ex) { + // if (ex is TargetInvocationException || ex is SerializationException) { + // Debug("Failed to deserialize an item", ex); + // return null; + // } + // throw; + //} } - internal void MaybeStoreFile(BaseFile file) + public void MaybeStoreFile(IStoreItem file, byte[] data, byte[] coverData) { if (connection == null) { return; @@ -293,48 +318,27 @@ internal void MaybeStoreFile(BaseFile file) return; } try { - using (var s = new MemoryStream()) { - var ctx = new StreamingContext( - StreamingContextStates.Persistence, - null - ); - var formatter = new BinaryFormatter(null, ctx) { - TypeFormat = FormatterTypeStyle.TypesWhenNeeded, - AssemblyFormat = FormatterAssemblyStyle.Simple - }; - formatter.Serialize(s, file); + lock (connection) { insertKey.Value = file.Item.FullName; insertSize.Value = file.Item.Length; insertTime.Value = file.Item.LastWriteTimeUtc.Ticks; - insertData.Value = s.ToArray(); + insertData.Value = data; - insertCover.Value = null; - try { - var cover = file.MaybeGetCover(); - if (cover != null) { - using (var c = new MemoryStream()) { - formatter.Serialize(c, cover); - insertCover.Value = c.ToArray(); - } - } - } - catch (NotSupportedException) { - // Ignore and store null. - } + insertCover.Value = coverData; try { insert.ExecuteNonQuery(); } catch (DbException ex) { - Error("Failed to put file cover into store", ex); + Logger.Error("Failed to put file cover into store", ex); return; } } - } + } catch (Exception ex) { - Error("Failed to serialize an object of type " + file.GetType(), ex); + Logger.Error("Failed to serialize an object of type " + file.GetType(), ex); throw; } } @@ -353,5 +357,18 @@ public void Dispose() connection.Dispose(); } } + + AttributeCollection _parameters = new AttributeCollection(); + + public void SetParameters(AttributeCollection parameters) + { + _parameters = parameters; + } + + public override string ToString() + { + return string.Format("{0} - {1}", Name, Description); + } + } } diff --git a/FileStoreSQLite/FileStoreSQLite.csproj b/FileStoreSQLite/FileStoreSQLite.csproj new file mode 100644 index 00000000..704760dd --- /dev/null +++ b/FileStoreSQLite/FileStoreSQLite.csproj @@ -0,0 +1,109 @@ + + + + + Debug + AnyCPU + {25741114-7F31-421E-8D2B-357A3155CEE2} + Library + Properties + NMaier.SimpleDlna.FileStore.SQLite + SimpleDlna.FileStore.SQLite + v4.0 + 512 + Client + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + sdlna.key.snk + + + + ..\packages\EntityFramework.6.0.0\lib\net40\EntityFramework.dll + True + + + ..\packages\EntityFramework.6.0.0\lib\net40\EntityFramework.SqlServer.dll + True + + + + + + ..\packages\System.Data.SQLite.Core.1.0.98.1\lib\net40\System.Data.SQLite.dll + True + + + ..\packages\System.Data.SQLite.EF6.1.0.98.1\lib\net40\System.Data.SQLite.EF6.dll + True + + + ..\packages\System.Data.SQLite.Linq.1.0.98.1\lib\net40\System.Data.SQLite.Linq.dll + True + + + + + + + + + + + + + + + + {50e06b21-e11a-42f0-81e2-0911e771e861} + fsserver + + + {a8960a7a-887c-40d7-9632-002e94bfc830} + util + + + + + Designer + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/fsserver/Files/FileStoreVacuumer.cs b/FileStoreSQLite/FileStoreVacuumer.cs similarity index 98% rename from fsserver/Files/FileStoreVacuumer.cs rename to FileStoreSQLite/FileStoreVacuumer.cs index 57c6e45b..80b50fce 100644 --- a/fsserver/Files/FileStoreVacuumer.cs +++ b/FileStoreSQLite/FileStoreVacuumer.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using System.Timers; -namespace NMaier.SimpleDlna.FileMediaServer +namespace NMaier.SimpleDlna.FileStore.SQLite { internal sealed class FileStoreVacuumer : Logging, IDisposable { diff --git a/FileStoreSQLite/Properties/AssemblyInfo.cs b/FileStoreSQLite/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..9f3aa9f7 --- /dev/null +++ b/FileStoreSQLite/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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("FileStoreSQLite")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FileStoreSQLite")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("25741114-7f31-421e-8d2b-357a3155cee2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/util/Sqlite.cs b/FileStoreSQLite/Sqlite.cs similarity index 94% rename from util/Sqlite.cs rename to FileStoreSQLite/Sqlite.cs index 3cc56d2d..ca722d65 100644 --- a/util/Sqlite.cs +++ b/FileStoreSQLite/Sqlite.cs @@ -1,10 +1,10 @@ -using System; +using NMaier.SimpleDlna.Utilities; +using System; using System.Data; using System.IO; using System.Reflection; -using System.Runtime.InteropServices; -namespace NMaier.SimpleDlna.Utilities +namespace NMaier.SimpleDlna.FileStore.SQLite { public static class Sqlite { @@ -55,7 +55,7 @@ private static IDbConnection GetDatabaseConnectionSDS(string cs) rv.SetChunkSize(GROW_SIZE); } catch (Exception ex) { - log4net.LogManager.GetLogger(typeof(Sqlite)).Error( + Logging.GetLogger(typeof(Sqlite)).Error( "Failed to sqlite control", ex); } diff --git a/FileStoreSQLite/packages.config b/FileStoreSQLite/packages.config new file mode 100644 index 00000000..e4c8fd6c --- /dev/null +++ b/FileStoreSQLite/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/FileStoreSQLite/sdlna.key.snk b/FileStoreSQLite/sdlna.key.snk new file mode 100644 index 0000000000000000000000000000000000000000..7e30ff02411640e5807b8ad0cd32d48cb745a656 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098wMZfhN->^Nl!3Q5v`Qf>P>)O;|H|uoq zuPj4V8M{Ea1kspx>7m=~Ae!YB7=t~Qz7(eePd3*)*b-~%a=s#O%-qg-@GPL*z6kU% z_rZ(=MtAVlNt1D>hD!9B=erFs`79ybW%gd3zM6N_Iz>{qvKFQq3-ak6OzAl8eiW^5 zOmPO^+X<^b0=H&n5wTcZ@h~o%(e5cR`ANyM%ct%9+9zyuRGC)FvaweMtNrl97Qn?s zamy#uD|T9Fa{c1Xe}>8%>_pA#h$%?caA9j1AF}orjgSmyI)uGpHuDJnF1OsUd=E1f zk2K3S76+h```Oc3U-Wme{HL>gKQqG%c4rE&?-jpk?Bd~E{~Iw+B~Ie<1%V#pR@X6h zUL0C=sJ5rU`+_8=T9L8`X>Kum>Bx}^(cTRDci3P0&#SZP`)nVOm(7?_n}f*+*Mp7U zmFRHUQ!6(|%D+=Co!{Q0Z~W}FwtXwCa7kH`hx=NoeGPF&^xO(LADYK>4*RHvW)k>x z|D7R^sunBQ6`EaX1o|FX8_=_^$?&Ia*X5JrY%JL}CCd})RcW>S)I30*%)=lme~(fB zxem@c$eEzgW0%I70=#Mmb6fA5FbAk;x{*bL8hUCD9;m6A>$BHKjd@@%*%&I!(*-hm zqlVmC4 - pdbonly + none true bin\Release\ TRACE diff --git a/SimpleDLNA/FormAbout.cs b/SimpleDLNA/FormAbout.cs index c624d56d..f9266116 100644 --- a/SimpleDLNA/FormAbout.cs +++ b/SimpleDLNA/FormAbout.cs @@ -1,8 +1,6 @@ using NMaier.SimpleDlna.Utilities; using System; -using System.Drawing; using System.Text; -using System.Windows.Forms; namespace NMaier.SimpleDlna.GUI { diff --git a/SimpleDLNA/FormMain.cs b/SimpleDLNA/FormMain.cs index 5d1c8a97..87a1ab88 100644 --- a/SimpleDLNA/FormMain.cs +++ b/SimpleDLNA/FormMain.cs @@ -4,6 +4,7 @@ using log4net.Core; using log4net.Layout; using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -28,14 +29,14 @@ public partial class FormMain : NMaier.Windows.Forms.Form, IAppender, IDisposabl Properties.Settings.Default; private readonly FileInfo cacheFile = - new FileInfo(Path.Combine(cacheDir, "sdlna.cache")); + new FileInfo(DataPath.Combine("sdlna.cache")); #if DEBUG private readonly FileInfo logFile = - new FileInfo(Path.Combine(cacheDir, "sdlna.dbg.log")); + new FileInfo(DataPath.Combine("sdlna.dbg.log")); #else private readonly FileInfo logFile = - new FileInfo(Path.Combine(cacheDir, "sdlna.log")); + new FileInfo(DataPath.Combine("sdlna.log")); #endif private readonly object appenderLock = new object(); @@ -56,6 +57,11 @@ public partial class FormMain : NMaier.Windows.Forms.Form, IAppender, IDisposabl public FormMain() { + var rv = Config.cache; + if (!string.IsNullOrWhiteSpace(rv) && Directory.Exists(rv)) { + DataPath.Path = rv; + } + HandleCreated += (o, e) => { logging = true; @@ -100,41 +106,6 @@ public FormMain() private delegate void logDelegate(string level, string logger, string msg, string ex); - private static string cacheDir - { - get - { - var rv = Config.cache; - if (!string.IsNullOrWhiteSpace(rv) && Directory.Exists(rv)) { - return rv; - } - try { - try { - rv = Environment.GetFolderPath( - Environment.SpecialFolder.LocalApplicationData); - if (string.IsNullOrEmpty(rv)) { - throw new IOException("Cannot get LocalAppData"); - } - } - catch (Exception) { - rv = Environment.GetFolderPath( - Environment.SpecialFolder.ApplicationData); - if (string.IsNullOrEmpty(rv)) { - throw new IOException("Cannot get LocalAppData"); - } - } - rv = Path.Combine(rv, "SimpleDLNA"); - if (!Directory.Exists(rv)) { - Directory.CreateDirectory(rv); - } - return rv; - } - catch (Exception) { - return Path.GetTempPath(); - } - } - } - public override string Text { get @@ -381,11 +352,7 @@ private ServerListViewItem[] LoadDescriptors() { List rv; try { - var serializer = new XmlSerializer(typeof(List)); - using (var reader = new StreamReader( - Path.Combine(cacheDir, descriptorFile))) { - rv = serializer.Deserialize(reader) as List; - } + rv = XmlHelper.FromFile>(DataPath.Combine(descriptorFile)); } catch (Exception) { rv = Config.Descriptors; @@ -476,15 +443,13 @@ private void SaveConfig() try { var descs = (from ServerListViewItem item in listDescriptions.Items select item.Description).ToArray(); - var serializer = new XmlSerializer(descs.GetType()); - var file = new FileInfo( - Path.Combine(cacheDir, descriptorFile + ".tmp")); - using (var writer = new StreamWriter(file.FullName)) { - serializer.Serialize(writer, descs); - } - var outfile = Path.Combine(cacheDir, descriptorFile); - File.Copy(file.FullName, outfile, true); - file.Delete(); + + var file = DataPath.Combine(descriptorFile + ".tmp"); + XmlHelper.ToFile(descs, file); + + var outfile = DataPath.Combine(descriptorFile); + File.Copy(file, outfile, true); + File.Delete(file); } catch (Exception ex) { log.Error("Failed to write descriptors", ex); diff --git a/SimpleDLNA/FormServer.Designer.cs b/SimpleDLNA/FormServer.Designer.cs index 415a1edf..492b0cf5 100644 --- a/SimpleDLNA/FormServer.Designer.cs +++ b/SimpleDLNA/FormServer.Designer.cs @@ -65,6 +65,8 @@ private void InitializeComponent() this.colRestrictionType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.buttonRemoveRestriction = new System.Windows.Forms.Button(); this.buttonAddRestriction = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.comboCache = new System.Windows.Forms.ComboBox(); this.groupName.SuspendLayout(); this.groupOrder.SuspendLayout(); this.groupTypes.SuspendLayout(); @@ -73,6 +75,7 @@ private void InitializeComponent() this.tabbedOptions.SuspendLayout(); this.tabPageViews.SuspendLayout(); this.tabPageRestrictions.SuspendLayout(); + this.groupBox1.SuspendLayout(); this.SuspendLayout(); // // groupName @@ -80,9 +83,9 @@ private void InitializeComponent() this.groupName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.groupName.Controls.Add(this.textName); - this.groupName.Location = new System.Drawing.Point(12, 12); + this.groupName.Location = new System.Drawing.Point(14, 14); this.groupName.Name = "groupName"; - this.groupName.Size = new System.Drawing.Size(520, 46); + this.groupName.Size = new System.Drawing.Size(607, 53); this.groupName.TabIndex = 2; this.groupName.TabStop = false; this.groupName.Text = "Name"; @@ -91,9 +94,9 @@ private void InitializeComponent() // this.textName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textName.Location = new System.Drawing.Point(6, 19); + this.textName.Location = new System.Drawing.Point(7, 22); this.textName.Name = "textName"; - this.textName.Size = new System.Drawing.Size(485, 20); + this.textName.Size = new System.Drawing.Size(565, 23); this.textName.TabIndex = 0; this.textName.Validating += new System.ComponentModel.CancelEventHandler(this.textName_Validating); // @@ -103,9 +106,9 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.groupOrder.Controls.Add(this.checkOrderDescending); this.groupOrder.Controls.Add(this.comboOrder); - this.groupOrder.Location = new System.Drawing.Point(12, 64); + this.groupOrder.Location = new System.Drawing.Point(14, 74); this.groupOrder.Name = "groupOrder"; - this.groupOrder.Size = new System.Drawing.Size(520, 46); + this.groupOrder.Size = new System.Drawing.Size(607, 53); this.groupOrder.TabIndex = 3; this.groupOrder.TabStop = false; this.groupOrder.Text = "Order"; @@ -114,9 +117,9 @@ private void InitializeComponent() // this.checkOrderDescending.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.checkOrderDescending.AutoSize = true; - this.checkOrderDescending.Location = new System.Drawing.Point(431, 19); + this.checkOrderDescending.Location = new System.Drawing.Point(511, 22); this.checkOrderDescending.Name = "checkOrderDescending"; - this.checkOrderDescending.Size = new System.Drawing.Size(83, 17); + this.checkOrderDescending.Size = new System.Drawing.Size(88, 19); this.checkOrderDescending.TabIndex = 1; this.checkOrderDescending.Text = "Descending"; this.checkOrderDescending.UseVisualStyleBackColor = true; @@ -127,9 +130,9 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.comboOrder.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboOrder.FormattingEnabled = true; - this.comboOrder.Location = new System.Drawing.Point(6, 19); + this.comboOrder.Location = new System.Drawing.Point(7, 22); this.comboOrder.Name = "comboOrder"; - this.comboOrder.Size = new System.Drawing.Size(419, 21); + this.comboOrder.Size = new System.Drawing.Size(488, 23); this.comboOrder.TabIndex = 0; // // groupTypes @@ -139,9 +142,9 @@ private void InitializeComponent() this.groupTypes.Controls.Add(this.checkImages); this.groupTypes.Controls.Add(this.checkAudio); this.groupTypes.Controls.Add(this.checkVideo); - this.groupTypes.Location = new System.Drawing.Point(12, 116); + this.groupTypes.Location = new System.Drawing.Point(14, 134); this.groupTypes.Name = "groupTypes"; - this.groupTypes.Size = new System.Drawing.Size(520, 46); + this.groupTypes.Size = new System.Drawing.Size(607, 53); this.groupTypes.TabIndex = 4; this.groupTypes.TabStop = false; this.groupTypes.Text = "Types"; @@ -150,9 +153,9 @@ private void InitializeComponent() // checkImages // this.checkImages.AutoSize = true; - this.checkImages.Location = new System.Drawing.Point(133, 19); + this.checkImages.Location = new System.Drawing.Point(155, 22); this.checkImages.Name = "checkImages"; - this.checkImages.Size = new System.Drawing.Size(60, 17); + this.checkImages.Size = new System.Drawing.Size(64, 19); this.checkImages.TabIndex = 2; this.checkImages.Text = "Images"; this.checkImages.UseVisualStyleBackColor = true; @@ -160,9 +163,9 @@ private void InitializeComponent() // checkAudio // this.checkAudio.AutoSize = true; - this.checkAudio.Location = new System.Drawing.Point(74, 19); + this.checkAudio.Location = new System.Drawing.Point(86, 22); this.checkAudio.Name = "checkAudio"; - this.checkAudio.Size = new System.Drawing.Size(53, 17); + this.checkAudio.Size = new System.Drawing.Size(58, 19); this.checkAudio.TabIndex = 1; this.checkAudio.Text = "Audio"; this.checkAudio.UseVisualStyleBackColor = true; @@ -170,9 +173,9 @@ private void InitializeComponent() // checkVideo // this.checkVideo.AutoSize = true; - this.checkVideo.Location = new System.Drawing.Point(15, 19); + this.checkVideo.Location = new System.Drawing.Point(17, 22); this.checkVideo.Name = "checkVideo"; - this.checkVideo.Size = new System.Drawing.Size(53, 17); + this.checkVideo.Size = new System.Drawing.Size(56, 19); this.checkVideo.TabIndex = 0; this.checkVideo.Text = "Video"; this.checkVideo.UseVisualStyleBackColor = true; @@ -186,9 +189,9 @@ private void InitializeComponent() this.groupDirectories.Controls.Add(this.buttonRemoveDirectory); this.groupDirectories.Controls.Add(this.buttonAddDirectory); this.groupDirectories.Controls.Add(this.listDirectories); - this.groupDirectories.Location = new System.Drawing.Point(13, 334); + this.groupDirectories.Location = new System.Drawing.Point(15, 385); this.groupDirectories.Name = "groupDirectories"; - this.groupDirectories.Size = new System.Drawing.Size(519, 138); + this.groupDirectories.Size = new System.Drawing.Size(605, 170); this.groupDirectories.TabIndex = 6; this.groupDirectories.TabStop = false; this.groupDirectories.Text = "Directories"; @@ -196,17 +199,17 @@ private void InitializeComponent() // listDirectoriesAnchor // this.listDirectoriesAnchor.AutoSize = true; - this.listDirectoriesAnchor.Location = new System.Drawing.Point(441, 74); + this.listDirectoriesAnchor.Location = new System.Drawing.Point(514, 85); this.listDirectoriesAnchor.Name = "listDirectoriesAnchor"; - this.listDirectoriesAnchor.Size = new System.Drawing.Size(0, 13); + this.listDirectoriesAnchor.Size = new System.Drawing.Size(0, 15); this.listDirectoriesAnchor.TabIndex = 2; // // buttonRemoveDirectory // this.buttonRemoveDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonRemoveDirectory.Location = new System.Drawing.Point(438, 48); + this.buttonRemoveDirectory.Location = new System.Drawing.Point(511, 55); this.buttonRemoveDirectory.Name = "buttonRemoveDirectory"; - this.buttonRemoveDirectory.Size = new System.Drawing.Size(75, 23); + this.buttonRemoveDirectory.Size = new System.Drawing.Size(87, 27); this.buttonRemoveDirectory.TabIndex = 2; this.buttonRemoveDirectory.Text = "Remove"; this.buttonRemoveDirectory.UseVisualStyleBackColor = true; @@ -215,9 +218,9 @@ private void InitializeComponent() // buttonAddDirectory // this.buttonAddDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonAddDirectory.Location = new System.Drawing.Point(438, 19); + this.buttonAddDirectory.Location = new System.Drawing.Point(511, 22); this.buttonAddDirectory.Name = "buttonAddDirectory"; - this.buttonAddDirectory.Size = new System.Drawing.Size(75, 23); + this.buttonAddDirectory.Size = new System.Drawing.Size(87, 27); this.buttonAddDirectory.TabIndex = 0; this.buttonAddDirectory.Text = "Add"; this.buttonAddDirectory.UseVisualStyleBackColor = true; @@ -230,9 +233,9 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.listDirectories.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.colDirectory}); - this.listDirectories.Location = new System.Drawing.Point(6, 19); + this.listDirectories.Location = new System.Drawing.Point(7, 22); this.listDirectories.Name = "listDirectories"; - this.listDirectories.Size = new System.Drawing.Size(429, 113); + this.listDirectories.Size = new System.Drawing.Size(500, 141); this.listDirectories.Sorting = System.Windows.Forms.SortOrder.Ascending; this.listDirectories.TabIndex = 3; this.listDirectories.UseCompatibleStateImageBehavior = false; @@ -248,9 +251,9 @@ private void InitializeComponent() // this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(457, 478); + this.buttonCancel.Location = new System.Drawing.Point(533, 631); this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.Size = new System.Drawing.Size(87, 27); this.buttonCancel.TabIndex = 1; this.buttonCancel.Text = "&Cancel"; this.buttonCancel.UseVisualStyleBackColor = true; @@ -259,9 +262,9 @@ private void InitializeComponent() // this.buttonAccept.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonAccept.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonAccept.Location = new System.Drawing.Point(376, 478); + this.buttonAccept.Location = new System.Drawing.Point(439, 631); this.buttonAccept.Name = "buttonAccept"; - this.buttonAccept.Size = new System.Drawing.Size(75, 23); + this.buttonAccept.Size = new System.Drawing.Size(87, 27); this.buttonAccept.TabIndex = 0; this.buttonAccept.Text = "&OK"; this.buttonAccept.UseVisualStyleBackColor = true; @@ -275,10 +278,10 @@ private void InitializeComponent() // this.tabbedOptions.Controls.Add(this.tabPageViews); this.tabbedOptions.Controls.Add(this.tabPageRestrictions); - this.tabbedOptions.Location = new System.Drawing.Point(12, 168); + this.tabbedOptions.Location = new System.Drawing.Point(14, 194); this.tabbedOptions.Name = "tabbedOptions"; this.tabbedOptions.SelectedIndex = 0; - this.tabbedOptions.Size = new System.Drawing.Size(520, 160); + this.tabbedOptions.Size = new System.Drawing.Size(607, 185); this.tabbedOptions.TabIndex = 6; // // tabPageViews @@ -289,10 +292,10 @@ private void InitializeComponent() this.tabPageViews.Controls.Add(this.buttonRemoveView); this.tabPageViews.Controls.Add(this.buttonAddView); this.tabPageViews.Controls.Add(this.listViews); - this.tabPageViews.Location = new System.Drawing.Point(4, 22); + this.tabPageViews.Location = new System.Drawing.Point(4, 24); this.tabPageViews.Name = "tabPageViews"; this.tabPageViews.Padding = new System.Windows.Forms.Padding(3); - this.tabPageViews.Size = new System.Drawing.Size(512, 134); + this.tabPageViews.Size = new System.Drawing.Size(599, 157); this.tabPageViews.TabIndex = 0; this.tabPageViews.Text = "Views"; this.tabPageViews.UseVisualStyleBackColor = true; @@ -303,17 +306,17 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.comboNewView.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboNewView.FormattingEnabled = true; - this.comboNewView.Location = new System.Drawing.Point(6, 6); + this.comboNewView.Location = new System.Drawing.Point(7, 7); this.comboNewView.Name = "comboNewView"; - this.comboNewView.Size = new System.Drawing.Size(419, 21); + this.comboNewView.Size = new System.Drawing.Size(488, 23); this.comboNewView.TabIndex = 0; // // buttonViewDown // this.buttonViewDown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonViewDown.Location = new System.Drawing.Point(431, 102); + this.buttonViewDown.Location = new System.Drawing.Point(503, 118); this.buttonViewDown.Name = "buttonViewDown"; - this.buttonViewDown.Size = new System.Drawing.Size(75, 23); + this.buttonViewDown.Size = new System.Drawing.Size(87, 27); this.buttonViewDown.TabIndex = 4; this.buttonViewDown.Text = "Down"; this.buttonViewDown.UseVisualStyleBackColor = true; @@ -321,9 +324,9 @@ private void InitializeComponent() // buttonViewUp // this.buttonViewUp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonViewUp.Location = new System.Drawing.Point(431, 73); + this.buttonViewUp.Location = new System.Drawing.Point(503, 84); this.buttonViewUp.Name = "buttonViewUp"; - this.buttonViewUp.Size = new System.Drawing.Size(75, 23); + this.buttonViewUp.Size = new System.Drawing.Size(87, 27); this.buttonViewUp.TabIndex = 3; this.buttonViewUp.Text = "Up"; this.buttonViewUp.UseVisualStyleBackColor = true; @@ -331,9 +334,9 @@ private void InitializeComponent() // buttonRemoveView // this.buttonRemoveView.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonRemoveView.Location = new System.Drawing.Point(431, 35); + this.buttonRemoveView.Location = new System.Drawing.Point(503, 40); this.buttonRemoveView.Name = "buttonRemoveView"; - this.buttonRemoveView.Size = new System.Drawing.Size(75, 23); + this.buttonRemoveView.Size = new System.Drawing.Size(87, 27); this.buttonRemoveView.TabIndex = 2; this.buttonRemoveView.Text = "Remove"; this.buttonRemoveView.UseVisualStyleBackColor = true; @@ -342,9 +345,9 @@ private void InitializeComponent() // buttonAddView // this.buttonAddView.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonAddView.Location = new System.Drawing.Point(431, 6); + this.buttonAddView.Location = new System.Drawing.Point(503, 7); this.buttonAddView.Name = "buttonAddView"; - this.buttonAddView.Size = new System.Drawing.Size(75, 23); + this.buttonAddView.Size = new System.Drawing.Size(87, 27); this.buttonAddView.TabIndex = 1; this.buttonAddView.Text = "Add"; this.buttonAddView.UseVisualStyleBackColor = true; @@ -359,9 +362,9 @@ private void InitializeComponent() this.colViewName, this.colViewDesc}); this.listViews.FullRowSelect = true; - this.listViews.Location = new System.Drawing.Point(6, 33); + this.listViews.Location = new System.Drawing.Point(7, 38); this.listViews.Name = "listViews"; - this.listViews.Size = new System.Drawing.Size(419, 95); + this.listViews.Size = new System.Drawing.Size(488, 109); this.listViews.TabIndex = 5; this.listViews.UseCompatibleStateImageBehavior = false; this.listViews.View = System.Windows.Forms.View.Details; @@ -383,10 +386,10 @@ private void InitializeComponent() this.tabPageRestrictions.Controls.Add(this.listRestrictions); this.tabPageRestrictions.Controls.Add(this.buttonRemoveRestriction); this.tabPageRestrictions.Controls.Add(this.buttonAddRestriction); - this.tabPageRestrictions.Location = new System.Drawing.Point(4, 22); + this.tabPageRestrictions.Location = new System.Drawing.Point(4, 24); this.tabPageRestrictions.Name = "tabPageRestrictions"; this.tabPageRestrictions.Padding = new System.Windows.Forms.Padding(3); - this.tabPageRestrictions.Size = new System.Drawing.Size(512, 134); + this.tabPageRestrictions.Size = new System.Drawing.Size(599, 157); this.tabPageRestrictions.TabIndex = 1; this.tabPageRestrictions.Text = "Restrictions"; this.tabPageRestrictions.UseVisualStyleBackColor = true; @@ -395,9 +398,9 @@ private void InitializeComponent() // this.textRestriction.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textRestriction.Location = new System.Drawing.Point(6, 6); + this.textRestriction.Location = new System.Drawing.Point(7, 7); this.textRestriction.Name = "textRestriction"; - this.textRestriction.Size = new System.Drawing.Size(274, 20); + this.textRestriction.Size = new System.Drawing.Size(319, 23); this.textRestriction.TabIndex = 0; // // comboNewRestriction @@ -409,9 +412,9 @@ private void InitializeComponent() "MAC", "IP", "User-Agent"}); - this.comboNewRestriction.Location = new System.Drawing.Point(305, 6); + this.comboNewRestriction.Location = new System.Drawing.Point(356, 7); this.comboNewRestriction.Name = "comboNewRestriction"; - this.comboNewRestriction.Size = new System.Drawing.Size(120, 21); + this.comboNewRestriction.Size = new System.Drawing.Size(139, 23); this.comboNewRestriction.TabIndex = 1; // // listRestrictions @@ -423,9 +426,9 @@ private void InitializeComponent() this.colRestriction, this.colRestrictionType}); this.listRestrictions.FullRowSelect = true; - this.listRestrictions.Location = new System.Drawing.Point(6, 33); + this.listRestrictions.Location = new System.Drawing.Point(7, 38); this.listRestrictions.Name = "listRestrictions"; - this.listRestrictions.Size = new System.Drawing.Size(419, 95); + this.listRestrictions.Size = new System.Drawing.Size(488, 109); this.listRestrictions.TabIndex = 4; this.listRestrictions.UseCompatibleStateImageBehavior = false; this.listRestrictions.View = System.Windows.Forms.View.Details; @@ -443,9 +446,9 @@ private void InitializeComponent() // buttonRemoveRestriction // this.buttonRemoveRestriction.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonRemoveRestriction.Location = new System.Drawing.Point(431, 35); + this.buttonRemoveRestriction.Location = new System.Drawing.Point(503, 40); this.buttonRemoveRestriction.Name = "buttonRemoveRestriction"; - this.buttonRemoveRestriction.Size = new System.Drawing.Size(75, 23); + this.buttonRemoveRestriction.Size = new System.Drawing.Size(87, 27); this.buttonRemoveRestriction.TabIndex = 3; this.buttonRemoveRestriction.Text = "Remove"; this.buttonRemoveRestriction.UseVisualStyleBackColor = true; @@ -454,22 +457,46 @@ private void InitializeComponent() // buttonAddRestriction // this.buttonAddRestriction.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonAddRestriction.Location = new System.Drawing.Point(431, 6); + this.buttonAddRestriction.Location = new System.Drawing.Point(503, 7); this.buttonAddRestriction.Name = "buttonAddRestriction"; - this.buttonAddRestriction.Size = new System.Drawing.Size(75, 23); + this.buttonAddRestriction.Size = new System.Drawing.Size(87, 27); this.buttonAddRestriction.TabIndex = 2; this.buttonAddRestriction.Text = "Add"; this.buttonAddRestriction.UseVisualStyleBackColor = true; this.buttonAddRestriction.Click += new System.EventHandler(this.buttonAddRestriction_Click); // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.comboCache); + this.groupBox1.Location = new System.Drawing.Point(14, 561); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(607, 53); + this.groupBox1.TabIndex = 8; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Cache"; + // + // comboCache + // + this.comboCache.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboCache.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboCache.FormattingEnabled = true; + this.comboCache.Location = new System.Drawing.Point(7, 22); + this.comboCache.Name = "comboCache"; + this.comboCache.Size = new System.Drawing.Size(488, 23); + this.comboCache.TabIndex = 0; + // // FormServer // this.AcceptButton = this.buttonAccept; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoValidate = System.Windows.Forms.AutoValidate.EnableAllowFocusChange; this.CancelButton = this.buttonCancel; - this.ClientSize = new System.Drawing.Size(544, 508); + this.ClientSize = new System.Drawing.Size(635, 665); + this.Controls.Add(this.groupBox1); this.Controls.Add(this.tabbedOptions); this.Controls.Add(this.buttonAccept); this.Controls.Add(this.buttonCancel); @@ -496,6 +523,7 @@ private void InitializeComponent() this.tabPageViews.ResumeLayout(false); this.tabPageRestrictions.ResumeLayout(false); this.tabPageRestrictions.PerformLayout(); + this.groupBox1.ResumeLayout(false); this.ResumeLayout(false); } @@ -539,5 +567,7 @@ private void InitializeComponent() private System.Windows.Forms.ColumnHeader colRestrictionType; private System.Windows.Forms.Button buttonRemoveRestriction; private System.Windows.Forms.Button buttonAddRestriction; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ComboBox comboCache; } } \ No newline at end of file diff --git a/SimpleDLNA/FormServer.cs b/SimpleDLNA/FormServer.cs index 4b1132b7..bf29767f 100644 --- a/SimpleDLNA/FormServer.cs +++ b/SimpleDLNA/FormServer.cs @@ -1,4 +1,5 @@ -using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.FileMediaServer; +using NMaier.SimpleDlna.Server; using NMaier.SimpleDlna.Server.Comparers; using NMaier.SimpleDlna.Server.Views; using NMaier.SimpleDlna.Utilities; @@ -41,6 +42,12 @@ public FormServer(ServerDescription description) break; } } + foreach (var i in comboCache.Items) { + if ((i is IFileStore) && (((IFileStore)i).Name == description.FileStore)) { + comboCache.SelectedItem = i; + break; + } + } checkOrderDescending.Checked = description.OrderDescending; foreach (var v in description.Views) { @@ -106,6 +113,7 @@ public ServerDescription Description var rv = new ServerDescription() { Name = textName.Text, Order = ((IItemComparer)comboOrder.SelectedItem).Name, + FileStore = (comboCache.SelectedItem is IFileStore) ? ((IFileStore)comboCache.SelectedItem).Name : null, OrderDescending = checkOrderDescending.Checked, Types = types, Views = views, @@ -131,6 +139,14 @@ orderby v.Key } } + private void AddCacheItems() + { + var items = FileStoreRepository.ListItems().OrderBy(l => l.Key).ToList(); + comboCache.Items.Clear(); + comboCache.Items.Add(string.Empty); + comboCache.Items.AddRange(items.Select(i => i.Value).ToArray()); + } + private void AddViewItems() { var items = from v in ViewRepository.ListItems() @@ -245,6 +261,7 @@ private void Init() Icon = Properties.Resources.server; AddOrderItems(); AddViewItems(); + AddCacheItems(); comboNewRestriction.SelectedIndex = 0; } diff --git a/SimpleDLNA/Properties/Settings.Designer.cs b/SimpleDLNA/Properties/Settings.Designer.cs index db06330a..91a650a9 100644 --- a/SimpleDLNA/Properties/Settings.Designer.cs +++ b/SimpleDLNA/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,7 +12,7 @@ namespace NMaier.SimpleDlna.GUI.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -25,7 +25,7 @@ public static Settings Default { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] + [global::System.Configuration.DefaultSettingValueAttribute("cache.db")] public string cache { get { return ((string)(this["cache"])); diff --git a/SimpleDLNA/Properties/Settings.settings b/SimpleDLNA/Properties/Settings.settings index 8a76ab1f..c1490052 100644 --- a/SimpleDLNA/Properties/Settings.settings +++ b/SimpleDLNA/Properties/Settings.settings @@ -3,7 +3,7 @@ - + cache.db 0 diff --git a/SimpleDLNA/ServerDescription.cs b/SimpleDLNA/ServerDescription.cs index 36ba6c0c..2afab9ed 100644 --- a/SimpleDLNA/ServerDescription.cs +++ b/SimpleDLNA/ServerDescription.cs @@ -31,6 +31,8 @@ public ServerDescription() public string[] Views { get; set; } + public string FileStore { get; set; } + public void AdoptInfo(ServerDescription other) { if (other == null) { @@ -39,6 +41,7 @@ public void AdoptInfo(ServerDescription other) Directories = other.Directories; Name = other.Name; Order = other.Order; + FileStore = other.FileStore; OrderDescending = other.OrderDescending; Types = other.Types; Views = other.Views; diff --git a/SimpleDLNA/ServerListViewItem.cs b/SimpleDLNA/ServerListViewItem.cs index 4fcc465e..4d6d8f50 100644 --- a/SimpleDLNA/ServerListViewItem.cs +++ b/SimpleDLNA/ServerListViewItem.cs @@ -99,11 +99,14 @@ where d.Exists fileServer = new FileServer(Description.Types, ids, dirs) { FriendlyName = Description.Name }; -#if !DEBUG - if (cacheFile != null) { - fileServer.SetCacheFile(cacheFile); +//#if !DEBUG + if(!string.IsNullOrEmpty(Description.FileStore)) { + fileServer.SetCacheFile(FileStoreRepository.Lookup(Description.FileStore)); } -#endif + //if (cacheFile != null) { + // fileServer.SetCacheFile(); + //} +//#endif fileServer.Changing += (o, e) => { state = State.Refreshing; @@ -138,7 +141,7 @@ where d.Exists ); } catch (Exception ex) { - server.ErrorFormat("Failed to start {0}, {1}", Description.Name, ex); + server.Logger.ErrorFormat("Failed to start {0}, {1}", Description.Name, ex); Description.ToggleActive(); state = State.Stopped; } diff --git a/SimpleDLNA/SimpleDLNA.csproj b/SimpleDLNA/SimpleDLNA.csproj index 6548defa..6d8e5c31 100644 --- a/SimpleDLNA/SimpleDLNA.csproj +++ b/SimpleDLNA/SimpleDLNA.csproj @@ -13,7 +13,10 @@ v4.0 Client 512 - publish\ + false + ..\ + true + C:\work\temp\deploy\simpleDLNA\ true Disk false @@ -23,13 +26,11 @@ false false true - 0 + 1 1.0.0.%2a - false false + true true - ..\ - true sdlna.ico @@ -51,7 +52,7 @@ bin\Release\ TRACE true - pdbonly + none AnyCPU bin\Release\SimpleDLNA.exe.CodeAnalysisLog.xml true @@ -60,6 +61,7 @@ ..\sdlna.ruleset false true + false true @@ -67,6 +69,18 @@ sdlna.key.snk + + 0B33F26E32F5937FB76E80B63014F6A0902E11E2 + + + SimpleDLNA_TemporaryKey.pfx + + + true + + + true + False @@ -161,6 +175,7 @@ + @@ -208,6 +223,14 @@ + + {6961f1c2-41e9-4e7f-8e88-7d4a259b3df8} + FileStoreRaptorDB + + + {25741114-7f31-421e-8d2b-357a3155cee2} + FileStoreSQLite + {50E06B21-E11A-42F0-81E2-0911E771E861} fsserver diff --git a/SimpleDLNA/SimpleDLNA_TemporaryKey.pfx b/SimpleDLNA/SimpleDLNA_TemporaryKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..0eab6f921b674c4ba95cca7c27a78afbc46377a7 GIT binary patch literal 1660 zcmY+Dc~s0@7{~7{{ibHLQ7M|tG!?CWEo#y_(WX^sqnIXbD27VWHl_47VnS1r(r!+q zg-WH8(4sez$P|$wFPc_jc;8=+m*d>?-1~h#&-2`K|F~b61sz7CFfa=;f+Vz39a29@ zqHw4}7Nm}4L1Y9IVHW24A0&NP5&b>(n4!_Qek==pN}Y|4+!7^YENi9MuyDV?Q1JDD!vgEE-i;ElQ>@d@qh)kTs?twcS~YM}n9V-oH5rtk$9as7=ve1!S({~pn$7uetEvabw4!*T zu(a_OHMm_HCsitpeQlqoB}mZM$c!?nVx zH*~EgCTCN{+oa4aW{JhzSHp$KE%qac-NH+A5!~MPF_G4}YR9sP?9&2SH+$;sU0+1FE>f*ph07AW^#KMz^|)P&sU+ z0=YCECEcS-xuEVSaI<(EXk<5DkbTirl~Zfd`tWw7bao#`{8+EDL_MWxdG<=1NM_x-}F8L-}^Z8YfpH}*jwNE+r`biJq zWxu|;guFh4#i9TJ@b=$OPTy6<85{w2fCdbZWdmTa4j2PnU0J zz=&G+v#O5}Q?L=3AVCEiKpgA`NoYeTEQ)0!i_&*jaRn|Q6fgi2M1X@x1c5_<1hydi zA_)hPkTV(uki+(O z1@(trp+&n^iMc5f2Kb4Kc1>iV6Q;05+DV{*GX!pIr5wiSZS zDRb;uy07oex0mgGoLM5B;(@eWy$nY)aJgl;Kdmk3ZoSF0kf67Bi-JMpa>DsBZ-u{u zdyba3oF(&cvcil5PHRPQ#25QjjcHkqR_-fzx*W{svco0bz2qf(n!mqz+^@JQm{=^& z)nttL%UDvTXDVj_PjXC5_QXu$_7Sy#u2gzm?Y$?(?+1FQkSCkxL#ykm8@<+T{&J0O zlDn2lKqB^jYe~=@orKWX@l@P;X<8HNc{fe6$5gRjJM5*mtMu-{=m%t388u+h=nWO- zhOX+7WiM6js&wPmCW|IBMLt!@JL5Wh7;n6f8wSO{$_&W+bo+MZaF&OZ4r&KJHNAv( z+H2k=12e}Nb~{@&_|dz5z+XoA&^_^E)py2SzNK!+m7!6JjTxg;aZQH<`ycj|Bu!0Q zMJEG{Pu0?|dbHWCn&~EE{RMpn8kh`?sLQ&R59b>R(@wU_@I%en33i>egkp4@&n<{4V?mN+-U zilfUvZs$dD$PqLZweXBLNYlBmL!Fd1_cgZ#QcqM2@A$5~qzqLLo58DK93-YKg+Z^t z%C((U%WePkD4UKYo*rz9P>Y=?`wJ_V!*dcgU&_UHD339F*QjXh4?nbH@nii52EDO8 literal 0 HcmV?d00001 diff --git a/SimpleDLNA/app.config b/SimpleDLNA/app.config index a3471e29..ca663e6b 100644 --- a/SimpleDLNA/app.config +++ b/SimpleDLNA/app.config @@ -8,7 +8,7 @@ - + cache.db 0 diff --git a/SimpleDLNA/public.pk b/SimpleDLNA/public.pk new file mode 100644 index 0000000000000000000000000000000000000000..500d95147d262273289b30b703117f0077265924 GIT binary patch literal 160 zcmV;R0AK$ABme*efB*oL000060ssI2Bme+XQ$aBR1ONa50098wMZfhN->^Nl!3Q5v z`Qf>P>)O;|H|uoquPj4V8M{Ea1kspx>7m=~Ae!YB7=t~Qz7(eePd3*)*b-~%a=s#O z%-qg-@GPL*z6kU%_rZ(=MtAVlNt1D>hD!9B=erFs`79ybW%gd3zM6N_Iz>{qvKFQq O3-ak6OzAl8eiW_rfkv+Y literal 0 HcmV?d00001 diff --git a/fsserver/BackgroundCacher.cs b/fsserver/BackgroundCacher.cs index 9f1bf92d..cdfe5bf3 100644 --- a/fsserver/BackgroundCacher.cs +++ b/fsserver/BackgroundCacher.cs @@ -1,9 +1,9 @@ using NMaier.SimpleDlna.Server.Metadata; +using NMaier.SimpleDlna.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; -using System.Threading.Tasks; namespace NMaier.SimpleDlna.FileMediaServer { @@ -23,9 +23,10 @@ private static BlockingCollection CreateQueue() return new BlockingCollection(new ConcurrentQueue()); } + private readonly static ILogging logger = Logging.GetLogger(); + private static void Run() { - var logger = log4net.LogManager.GetLogger(typeof(BackgroundCacher)); logger.Debug("started"); var loadedSubTitles = 0ul; try { @@ -35,8 +36,9 @@ private static void Run() continue; } var item = queue.Take(); - var store = item.Store.Target as FileStore; + var store = item.Store.Target as IFileStore; var file = item.File.Target as BaseFile; + logger.NoticeFormat("Processing [{0}]", file.Item.Name); if (store == null || file == null) { continue; } @@ -62,7 +64,7 @@ private static void Run() } } - public static void AddFiles(FileStore store, + public static void AddFiles(IFileStore store, IEnumerable items) { var storeRef = new WeakReference(store); diff --git a/fsserver/FileServer.cs b/fsserver/FileServer.cs index e3f3bdb7..f4415568 100644 --- a/fsserver/FileServer.cs +++ b/fsserver/FileServer.cs @@ -46,7 +46,9 @@ public sealed class FileServer private readonly Identifiers ids; - private FileStore store = null; + private IFileStore _store = null; + private FileStoreReader _storeReader = null; + private FileStoreWriter _storeWriter = null; private readonly DlnaMediaTypes types; @@ -182,10 +184,10 @@ private void DoRoot() private void OnChanged(Object source, FileSystemEventArgs e) { try { - if (store != null && - icomparer.Equals(e.FullPath, store.StoreFile.FullName)) { - return; - } + //if (_store != null && + // icomparer.Equals(e.FullPath, _store.StoreFile.FullName)) { + // return; + //} var ext = string.IsNullOrEmpty(e.FullPath) ? Path.GetExtension(e.FullPath) : string.Empty; @@ -289,7 +291,7 @@ private void RescanTimer(object sender, ElapsedEventArgs e) private void Thumbnail() { - if (store == null) { + if (_store == null) { lock (this) { pendingFiles.Clear(); } @@ -298,7 +300,7 @@ private void Thumbnail() lock (this) { DebugFormat( "Passing {0} files to background cacher", pendingFiles.Count); - BackgroundCacher.AddFiles(store, pendingFiles); + BackgroundCacher.AddFiles(_store, pendingFiles); pendingFiles.Clear(); } } @@ -338,8 +340,8 @@ internal void DelayedRescan(WatcherChangeTypes changeType) internal Cover GetCover(BaseFile file) { - if (store != null) { - return store.MaybeGetCover(file); + if (_storeReader != null) { + return _storeReader.GetCover(file); } return null; } @@ -363,8 +365,8 @@ internal BaseFile GetFile(PlainFolder aParent, FileInfo info) var type = DlnaMaps.Ext2Dlna[ext]; var mediaType = DlnaMaps.Ext2Media[ext]; - if (store != null) { - item = store.MaybeGetFile(this, info, type); + if (_store != null) { + item = _storeReader.GetFile(info, this, type); if (item != null) { lock (this) { pendingFiles.Add(new WeakReference(item)); @@ -382,8 +384,8 @@ internal BaseFile GetFile(PlainFolder aParent, FileInfo info) internal void UpdateFileCache(BaseFile aFile) { - if (store != null) { - store.MaybeStoreFile(aFile); + if (_storeWriter != null) { + _storeWriter.StoreFile(aFile); } } @@ -398,8 +400,8 @@ public void Dispose() if (watchTimer != null) { watchTimer.Dispose(); } - if (store != null) { - store.Dispose(); + if (_store != null) { + _store.Dispose(); } FileStreamCache.Clear(); } @@ -442,17 +444,23 @@ public void Rescan() RescanInternal(); } - public void SetCacheFile(FileInfo info) + public void SetCacheFile(IFileStore store) { - if (store != null) { - store.Dispose(); - store = null; + if (_store != null) { + _store.Dispose(); + _store = null; + _storeReader = null; + _storeWriter = null; } try { - store = new FileStore(info); + _store = store; + if (_store == null) return; + _store.Init(); + _storeReader = new FileStoreReader(store); + _storeWriter = new FileStoreWriter(store); } catch (Exception ex) { - Warn("FileStore is not available; failed to load SQLite Adapter", ex); + WarnFormat("FileStore is not available; failed to load [{0}]:{1}", store, ex); store = null; } } diff --git a/fsserver/FileStoreReader.cs b/fsserver/FileStoreReader.cs new file mode 100644 index 00000000..b614dc2a --- /dev/null +++ b/fsserver/FileStoreReader.cs @@ -0,0 +1,99 @@ +using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.Utilities; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters; +using System.Runtime.Serialization.Formatters.Binary; + +namespace NMaier.SimpleDlna.FileMediaServer +{ + public class FileStoreReader : Logging + { + IFileStore _store; + + public FileStoreReader(IFileStore store) { + _store = store; + } + /* ------------------ BaseFile serialize ------------------ + using (var s = new MemoryStream()) { + var ctx = new StreamingContext( + StreamingContextStates.Persistence, + null + ); + var formatter = new BinaryFormatter(null, ctx) { + TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + AssemblyFormat = FormatterAssemblyStyle.Simple + }; + formatter.Serialize(s, file); + } + */ + /* + using (var s = new MemoryStream(data)) { + var ctx = new StreamingContext( + StreamingContextStates.Persistence, + new DeserializeInfo(null, info, DlnaMime.ImageJPEG) + ); + var formatter = new BinaryFormatter(null, ctx) { + TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + AssemblyFormat = FormatterAssemblyStyle.Simple + }; + var rv = formatter.Deserialize(s) as Cover; + return rv; + } */ + + /* ------------------ Cover deserialize ------------------ + using (var s = new MemoryStream(data)) { + var ctx = new StreamingContext( + StreamingContextStates.Persistence, + new DeserializeInfo(null, info, DlnaMime.ImageJPEG) + ); + var formatter = new BinaryFormatter(null, ctx) { + TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + AssemblyFormat = FormatterAssemblyStyle.Simple + }; + var rv = formatter.Deserialize(s) as Cover; + return rv; + } + */ + /* ------------------ BaseFile deserialize ------------------ + using (var s = new MemoryStream(data)) { + var ctx = new StreamingContext( + StreamingContextStates.Persistence, + new DeserializeInfo(server, info, type)); + var formatter = new BinaryFormatter(null, ctx) { + TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + AssemblyFormat = FormatterAssemblyStyle.Simple + }; + var rv = formatter.Deserialize(s) as BaseFile; + rv.Item = info; + return rv; + } + */ + + private static T Decode(byte[] data, DeserializeInfo dinfo) where T : class { + if (data == null) return (T)null; + using (var s = new MemoryStream(data)) { + var ctx = new StreamingContext(StreamingContextStates.Persistence,dinfo); + var formatter = new BinaryFormatter(null, ctx) { + TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + AssemblyFormat = FormatterAssemblyStyle.Simple + }; + return formatter.Deserialize(s) as T; + } + } + + public Cover GetCover(IStoreItem file) { + try { + return Decode(_store.MaybeGetCover(file), new DeserializeInfo(null, file.Item, DlnaMime.ImageJPEG)); + } + catch (SerializationException ex) { + Debug("Failed to deserialize a cover", ex); + return null; + } + } + + public BaseFile GetFile(FileInfo info, FileServer server, DlnaMime type) { + return Decode(_store.MaybeGetFile(info), new DeserializeInfo(server, info, type)); + } + } +} diff --git a/fsserver/FileStoreRepository.cs b/fsserver/FileStoreRepository.cs new file mode 100644 index 00000000..7b44d9db --- /dev/null +++ b/fsserver/FileStoreRepository.cs @@ -0,0 +1,8 @@ +using NMaier.SimpleDlna.Utilities; + +namespace NMaier.SimpleDlna.FileMediaServer +{ + public sealed class FileStoreRepository : Repository + { + } +} diff --git a/fsserver/FileStoreWriter.cs b/fsserver/FileStoreWriter.cs new file mode 100644 index 00000000..25862a52 --- /dev/null +++ b/fsserver/FileStoreWriter.cs @@ -0,0 +1,49 @@ +using NMaier.SimpleDlna.Utilities; +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters; +using System.Runtime.Serialization.Formatters.Binary; + +namespace NMaier.SimpleDlna.FileMediaServer +{ + public class FileStoreWriter : Logging + { + IFileStore _store; + + public FileStoreWriter(IFileStore store) { + _store = store; + } + + private static byte[] Encode(object obj) { + using (var s = new MemoryStream()) { + var ctx = new StreamingContext( + StreamingContextStates.Persistence, + null + ); + var formatter = new BinaryFormatter(null, ctx) { + TypeFormat = FormatterTypeStyle.TypesWhenNeeded, + AssemblyFormat = FormatterAssemblyStyle.Simple + }; + formatter.Serialize(s, obj); + return s.ToArray(); + } + } + + /* + , byte[] coverData + */ + + public void StoreFile(BaseFile file) { + byte[] coverData = null; + try { + coverData = Encode(file.MaybeGetCover()); + } + catch (Exception) { + // Ignore and store null. + } + + _store.MaybeStoreFile(file, Encode(file), coverData); + } + } +} diff --git a/fsserver/Files/AudioFile.cs b/fsserver/Files/AudioFile.cs index fb3a0bf9..b4c7a6b5 100644 --- a/fsserver/Files/AudioFile.cs +++ b/fsserver/Files/AudioFile.cs @@ -211,7 +211,7 @@ private void InitCover(TagLib.Tag tag) cover = new Cover(Item, pic.Data.ToStream()); } catch (Exception ex) { - Debug("Failed to generate thumb for " + Item.FullName, ex); + Logger.Debug("Failed to generate thumb for " + Item.FullName, ex); } } } @@ -231,7 +231,7 @@ private void MaybeInit() } } catch (Exception ex) { - Debug("Failed to transpose Properties props", ex); + Logger.Debug("Failed to transpose Properties props", ex); } try { @@ -240,7 +240,7 @@ private void MaybeInit() InitCover(t); } catch (Exception ex) { - Debug("Failed to transpose Tag props", ex); + Logger.Debug("Failed to transpose Tag props", ex); } } @@ -249,17 +249,17 @@ private void MaybeInit() Server.UpdateFileCache(this); } catch (TagLib.CorruptFileException ex) { - Debug( + Logger.Debug( "Failed to read meta data via taglib for file " + Item.FullName, ex); initialized = true; } catch (TagLib.UnsupportedFormatException ex) { - Debug( + Logger.Debug( "Failed to read meta data via taglib for file " + Item.FullName, ex); initialized = true; } catch (Exception ex) { - Warn( + Logger.Warn( "Unhandled exception reading meta data for file " + Item.FullName, ex); } diff --git a/fsserver/Files/BaseFile.cs b/fsserver/Files/BaseFile.cs index 741eb2be..139e9f22 100644 --- a/fsserver/Files/BaseFile.cs +++ b/fsserver/Files/BaseFile.cs @@ -7,8 +7,8 @@ namespace NMaier.SimpleDlna.FileMediaServer { using CoverCache = LeastRecentlyUsedDictionary; - - internal class BaseFile : Logging, IMediaResource, IMediaCover, IMetaInfo + [Serializable] //Logging, + public class BaseFile : IStoreItem, IMediaResource, IMediaCover, IMetaInfo { private string comparableTitle; @@ -16,6 +16,7 @@ internal class BaseFile : Logging, IMediaResource, IMediaCover, IMetaInfo private long? length = null; + [NonSerialized] private readonly FileServer server; private readonly string title; @@ -27,6 +28,8 @@ internal class BaseFile : Logging, IMediaResource, IMediaCover, IMetaInfo private static readonly StringComparer comparer = new NaturalStringComparer(false); + protected static readonly ILogging Logger = Logging.GetLogger(); + protected BaseFile(FileServer server, FileInfo file, DlnaMime type, DlnaMediaTypes mediaType) { @@ -80,7 +83,7 @@ protected FileServer Server } } - internal FileInfo Item + public FileInfo Item { get; set; @@ -168,7 +171,7 @@ public virtual IHeaders Properties } } catch (Exception ex) { - Debug("Failed to access cover", ex); + Logger.Debug("Failed to access cover", ex); } return rv; } @@ -209,7 +212,7 @@ internal static BaseFile GetFile(PlainFolder parentFolder, FileInfo file, } } - internal Cover MaybeGetCover() + public Cover MaybeGetCover() { return cover; } @@ -228,17 +231,17 @@ public Stream CreateContentStream() return FileStreamCache.Get(Item); } catch (FileNotFoundException ex) { - Error("Failed to access: " + Item.FullName, ex); + Logger.Error("Failed to access: " + Item.FullName, ex); server.DelayedRescan(WatcherChangeTypes.Deleted); throw; } catch (UnauthorizedAccessException ex) { - Error("Failed to access: " + Item.FullName, ex); + Logger.Error("Failed to access: " + Item.FullName, ex); server.DelayedRescan(WatcherChangeTypes.Changed); throw; } catch (IOException ex) { - Error("Failed to access: " + Item.FullName, ex); + Logger.Error("Failed to access: " + Item.FullName, ex); server.DelayedRescan(WatcherChangeTypes.Changed); throw; } diff --git a/fsserver/Files/Cover.cs b/fsserver/Files/Cover.cs index a41ba15a..e0d23a0c 100644 --- a/fsserver/Files/Cover.cs +++ b/fsserver/Files/Cover.cs @@ -9,7 +9,7 @@ namespace NMaier.SimpleDlna.FileMediaServer { [Serializable] - internal sealed class Cover + public sealed class Cover : Logging, IMediaCoverResource, IMetaInfo, ISerializable { private byte[] bytes; diff --git a/fsserver/Files/FileReadStream.cs b/fsserver/Files/FileReadStream.cs index dae38199..ccc67443 100644 --- a/fsserver/Files/FileReadStream.cs +++ b/fsserver/Files/FileReadStream.cs @@ -1,8 +1,6 @@ -using log4net; using NMaier.SimpleDlna.Utilities; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Threading; @@ -10,8 +8,7 @@ namespace NMaier.SimpleDlna.FileMediaServer { internal class FileStreamCache { - private readonly static ILog logger = - LogManager.GetLogger(typeof(FileReadStream)); + private readonly static ILogging logger = Logging.GetLogger(); private class CacheItem { @@ -100,8 +97,7 @@ internal sealed class FileReadStream : FileStream private readonly FileInfo info; - private readonly static ILog logger = - LogManager.GetLogger(typeof(FileReadStream)); + private readonly static ILogging logger = Logging.GetLogger(); private bool killed = false; diff --git a/fsserver/Files/ImageFile.cs b/fsserver/Files/ImageFile.cs index f4f9ca1b..6780d58a 100644 --- a/fsserver/Files/ImageFile.cs +++ b/fsserver/Files/ImageFile.cs @@ -127,7 +127,7 @@ private void MaybeInit() height = tl.Properties.PhotoHeight; } catch (Exception ex) { - Debug("Failed to transpose Properties props", ex); + Logger.Debug("Failed to transpose Properties props", ex); } try { @@ -146,7 +146,7 @@ private void MaybeInit() } } catch (Exception ex) { - Debug("Failed to transpose Tag props", ex); + Logger.Debug("Failed to transpose Tag props", ex); } } @@ -156,17 +156,17 @@ private void MaybeInit() Server.UpdateFileCache(this); } catch (TagLib.CorruptFileException ex) { - Debug( + Logger.Debug( "Failed to read meta data via taglib for file " + Item.FullName, ex); initialized = true; } catch (TagLib.UnsupportedFormatException ex) { - Debug( + Logger.Debug( "Failed to read meta data via taglib for file " + Item.FullName, ex); initialized = true; } catch (Exception ex) { - Warn( + Logger.Warn( "Unhandled exception reading meta data for file " + Item.FullName, ex); } diff --git a/fsserver/Files/VideoFile.cs b/fsserver/Files/VideoFile.cs index 0ce826e5..e97f24db 100644 --- a/fsserver/Files/VideoFile.cs +++ b/fsserver/Files/VideoFile.cs @@ -198,7 +198,7 @@ public Subtitle Subtitle } } catch (Exception ex) { - Error("Failed to look up subtitle", ex); + Logger.Error("Failed to look up subtitle", ex); subTitle = new Subtitle(); } return subTitle; @@ -233,7 +233,7 @@ private void MaybeInit() height = tl.Properties.VideoHeight; } catch (Exception ex) { - Debug("Failed to transpose Properties props", ex); + Logger.Debug("Failed to transpose Properties props", ex); } try { @@ -257,7 +257,7 @@ private void MaybeInit() } } catch (Exception ex) { - Debug("Failed to transpose Tag props", ex); + Logger.Debug("Failed to transpose Tag props", ex); } } @@ -266,17 +266,17 @@ private void MaybeInit() Server.UpdateFileCache(this); } catch (TagLib.CorruptFileException ex) { - Debug( + Logger.Debug( "Failed to read meta data via taglib for file " + Item.FullName, ex); initialized = true; } catch (TagLib.UnsupportedFormatException ex) { - Debug( + Logger.Debug( "Failed to read meta data via taglib for file " + Item.FullName, ex); initialized = true; } catch (Exception ex) { - Warn( + Logger.Warn( "Unhandled exception reading meta data for file " + Item.FullName, ex); } diff --git a/fsserver/IFileStore.cs b/fsserver/IFileStore.cs new file mode 100644 index 00000000..65886bbf --- /dev/null +++ b/fsserver/IFileStore.cs @@ -0,0 +1,16 @@ +using NMaier.SimpleDlna.Utilities; +using System; +using System.IO; + +namespace NMaier.SimpleDlna.FileMediaServer +{ + public interface IFileStore : IDisposable, IRepositoryItem + { + void Init(); + string StoreFile { get; } + bool HasCover(IStoreItem file); + byte[] MaybeGetCover(IStoreItem file); + byte[] MaybeGetFile(FileInfo info); + void MaybeStoreFile(IStoreItem file, byte[] data, byte[] coverData); + } +} diff --git a/fsserver/IStoreItem.cs b/fsserver/IStoreItem.cs new file mode 100644 index 00000000..91694daa --- /dev/null +++ b/fsserver/IStoreItem.cs @@ -0,0 +1,10 @@ +using System.IO; + +namespace NMaier.SimpleDlna.FileMediaServer +{ + public interface IStoreItem + { + FileInfo Item { get; set; } + Cover MaybeGetCover(); + } +} diff --git a/fsserver/Properties/AssemblyInfo.cs b/fsserver/Properties/AssemblyInfo.cs index 1b1f278c..c48005ac 100644 --- a/fsserver/Properties/AssemblyInfo.cs +++ b/fsserver/Properties/AssemblyInfo.cs @@ -1,6 +1,12 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("File Server class library")] [assembly: AssemblyDescription("")] [assembly: Guid("0c898974-f4a3-4aa9-a096-5cd8a3bdd9d5")] +[assembly: InternalsVisibleTo("SimpleDLNA.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e345bff51cdfb0"+ +"3db6c1071f51f9e1b983ebdad46137eb74f1af2c435519bb40b904d19877e9a1dbec209ae51518"+ +"833d96be14a7034f36d73cd8126bea72be226fccdcce79f02ca0dcbe08f430f7c18c044677f0d5"+ +"499371a7864af49ae7bb0d30f92c21dd65f65e9dbe9a77d33a4552b7b216a61a0bf2e91e4ce938"+ +"ee7e14ad")] \ No newline at end of file diff --git a/fsserver/SerializeHelper.cs b/fsserver/SerializeHelper.cs new file mode 100644 index 00000000..bd8dd722 --- /dev/null +++ b/fsserver/SerializeHelper.cs @@ -0,0 +1,6 @@ +namespace NMaier.SimpleDlna.FileMediaServer +{ + internal static class SerializeHelper + { + } +} diff --git a/fsserver/fsserver.csproj b/fsserver/fsserver.csproj index a860fa22..ecf32a9f 100644 --- a/fsserver/fsserver.csproj +++ b/fsserver/fsserver.csproj @@ -27,7 +27,7 @@ AnyCPU - pdbonly + none true bin\Release\ TRACE @@ -45,10 +45,6 @@ sdlna.key.snk - - False - ..\packages\log4net.2.0.3\lib\net40-client\log4net.dll - @@ -63,23 +59,27 @@ Properties\GlobalAssemblyInfo.cs + + + - - + + + @@ -96,7 +96,9 @@ - + + Designer + diff --git a/fsserver/packages.config b/fsserver/packages.config index a1ab14d6..65653459 100644 --- a/fsserver/packages.config +++ b/fsserver/packages.config @@ -1,5 +1,4 @@  - \ No newline at end of file diff --git a/sdlna.sln b/sdlna.sln index c74e4a2b..17833f88 100644 --- a/sdlna.sln +++ b/sdlna.sln @@ -36,6 +36,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{311651 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileStoreSQLite", "FileStoreSQLite\FileStoreSQLite.csproj", "{25741114-7F31-421E-8D2B-357A3155CEE2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileStoreRaptorDB", "FileStoreRaptorDB\FileStoreRaptorDB.csproj", "{6961F1C2-41E9-4E7F-8E88-7D4A259B3DF8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{1A8B9EDC-A2A5-4132-B274-736431F411AA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -76,6 +82,14 @@ Global {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED38A2A8-C0E5-4881-8F8E-591B34FD2C06}.Release|Any CPU.Build.0 = Release|Any CPU + {25741114-7F31-421E-8D2B-357A3155CEE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25741114-7F31-421E-8D2B-357A3155CEE2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25741114-7F31-421E-8D2B-357A3155CEE2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25741114-7F31-421E-8D2B-357A3155CEE2}.Release|Any CPU.Build.0 = Release|Any CPU + {6961F1C2-41E9-4E7F-8E88-7D4A259B3DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6961F1C2-41E9-4E7F-8E88-7D4A259B3DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6961F1C2-41E9-4E7F-8E88-7D4A259B3DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6961F1C2-41E9-4E7F-8E88-7D4A259B3DF8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdlna/Program.cs b/sdlna/Program.cs index 951e832a..bc224630 100644 --- a/sdlna/Program.cs +++ b/sdlna/Program.cs @@ -117,29 +117,29 @@ private static void Main(string[] args) var types = options.Types[0]; foreach (var t in options.Types) { types = types | t; - server.InfoFormat("Enabled type {0}", t); + server.Logger.InfoFormat("Enabled type {0}", t); } var friendlyName = "sdlna"; if (options.Seperate) { foreach (var d in options.Directories) { - server.InfoFormat("Mounting FileServer for {0}", d.FullName); + server.Logger.InfoFormat("Mounting FileServer for {0}", d.FullName); var fs = SetupFileServer( options, types, new DirectoryInfo[] { d }); friendlyName = fs.FriendlyName; server.RegisterMediaServer(fs); - server.NoticeFormat("{0} mounted", d.FullName); + server.Logger.NoticeFormat("{0} mounted", d.FullName); } } else { - server.InfoFormat( + server.Logger.InfoFormat( "Mounting FileServer for {0} ({1})", options.Directories[0], options.Directories.Length); var fs = SetupFileServer(options, types, options.Directories); friendlyName = fs.FriendlyName; server.RegisterMediaServer(fs); - server.NoticeFormat( + server.Logger.NoticeFormat( "{0} ({1}) mounted", options.Directories[0], options.Directories.Length); } @@ -167,11 +167,11 @@ private static void Main(string[] args) private static void Run(HttpServer server) { - server.Info("CTRL-C to terminate"); + server.Logger.Info("CTRL-C to terminate"); BlockEvent.WaitOne(); - server.Info("Going down!"); - server.Info("Closed!"); + server.Logger.Info("Going down!"); + server.Logger.Info("Closed!"); } private static FileServer SetupFileServer(Options options, @@ -193,9 +193,9 @@ private static FileServer SetupFileServer(Options options, fs.FriendlyName = options.FriendlyName; } try { - if (options.CacheFile != null) { - fs.SetCacheFile(options.CacheFile); - } + //if (options.CacheFile != null) { + // fs.SetCacheFile(options.CacheFile); + //} fs.Load(); if (!options.Rescanning) { fs.Rescanning = false; diff --git a/sdlna/sdlna.csproj b/sdlna/sdlna.csproj index 25104c21..a5e988d7 100644 --- a/sdlna/sdlna.csproj +++ b/sdlna/sdlna.csproj @@ -53,7 +53,7 @@ ..\sdlna.ruleset - D:\bin\ + bin\Release\ TRACE true pdbonly diff --git a/server/Handlers/MediaMount.cs b/server/Handlers/MediaMount.cs index e33bee53..91ad283e 100644 --- a/server/Handlers/MediaMount.cs +++ b/server/Handlers/MediaMount.cs @@ -7,9 +7,9 @@ using System.Xml; namespace NMaier.SimpleDlna.Server -{ +{//Logging, internal sealed partial class MediaMount - : Logging, IMediaServer, IPrefixHandler + : IMediaServer, IPrefixHandler { private readonly Dictionary guidsForAddresses = new Dictionary(); @@ -75,7 +75,7 @@ public Guid Uuid private void ChangedServer(object sender, EventArgs e) { soapCache.Clear(); - InfoFormat("Rescanned mount {0}", Uuid); + Logger.InfoFormat("Rescanned mount {0}", Uuid); systemID++; } @@ -147,7 +147,7 @@ public IResponse HandleRequest(IRequest request) } var path = request.Path.Substring(prefix.Length); - Debug(path); + Logger.Debug(path); if (path == "description.xml") { return new StringResponse( HttpCode.Ok, @@ -181,19 +181,19 @@ public IResponse HandleRequest(IRequest request) } if (path.StartsWith("file/", StringComparison.Ordinal)) { var id = path.Split('/')[1]; - InfoFormat("Serving file {0}", id); + Logger.InfoFormat("Serving file {0}", id); var item = GetItem(id) as IMediaResource; return new ItemResponse(prefix, request, item); } if (path.StartsWith("cover/", StringComparison.Ordinal)) { var id = path.Split('/')[1]; - InfoFormat("Serving cover {0}", id); + Logger.InfoFormat("Serving cover {0}", id); var item = GetItem(id) as IMediaCover; return new ItemResponse(prefix, request, item.Cover, "Interactive"); } if (path.StartsWith("subtitle/", StringComparison.Ordinal)) { var id = path.Split('/')[1]; - InfoFormat("Serving subtitle {0}", id); + Logger.InfoFormat("Serving subtitle {0}", id); var item = GetItem(id) as IMetaVideoItem; return new ItemResponse(prefix, request, item.Subtitle, "Background"); } @@ -215,7 +215,7 @@ public IResponse HandleRequest(IRequest request) if (request.Method == "UNSUBSCRIBE") { return new StringResponse(HttpCode.Ok, string.Empty); } - WarnFormat("Did not understand {0} {1}", request.Method, path); + Logger.WarnFormat("Did not understand {0} {1}", request.Method, path); throw new HttpStatusException(HttpCode.NotFound); } } diff --git a/server/Handlers/MediaMount_SOAP.cs b/server/Handlers/MediaMount_SOAP.cs index 0a641890..6878402e 100644 --- a/server/Handlers/MediaMount_SOAP.cs +++ b/server/Handlers/MediaMount_SOAP.cs @@ -9,6 +9,7 @@ namespace NMaier.SimpleDlna.Server { internal partial class MediaMount { + private static readonly ILogging Logger = Logging.GetLogger(); private const string NS_DC = "http://purl.org/dc/elements/1.1/"; private const string NS_DIDL = @@ -370,7 +371,7 @@ private IEnumerable> HandleBrowse( } } catch (Exception ex) { - Debug("Not all params provided", ex); + Logger.Debug("Not all params provided", ex); } var root = GetItem(id) as IMediaFolder; @@ -573,7 +574,7 @@ private IResponse ProcessSoapRequest(IRequest request) "401Invalid Action"; fault.AppendChild(detail); rbody.AppendChild(fault); - WarnFormat( + Logger.WarnFormat( "Invalid call: Action: {0}, Params: {1}, Problem {2}", method.LocalName, sparams, ex.Message); } diff --git a/server/Http/HTTPServer.cs b/server/Http/HTTPServer.cs index 2ba4ac78..a8797cc8 100644 --- a/server/Http/HTTPServer.cs +++ b/server/Http/HTTPServer.cs @@ -1,5 +1,4 @@ -using log4net; -using NMaier.SimpleDlna.Server.Ssdp; +using NMaier.SimpleDlna.Server.Ssdp; using NMaier.SimpleDlna.Utilities; using System; using System.Collections.Concurrent; @@ -11,9 +10,13 @@ using System.Timers; namespace NMaier.SimpleDlna.Server -{ - public sealed class HttpServer : Logging, IDisposable +{//Logging, + public sealed class HttpServer : IDisposable { + + private static readonly ILogging _logger = Logging.GetLogger(); + public ILogging Logger{get{return _logger;} } + private readonly ConcurrentDictionary clients = new ConcurrentDictionary(); @@ -60,7 +63,7 @@ public HttpServer(int port) RealPort = (listener.LocalEndpoint as IPEndPoint).Port; - NoticeFormat( + Logger.NoticeFormat( "Running HTTP Server: {0} on port {1}", Signature, RealPort); ssdpServer = new SsdpHandler(); @@ -97,7 +100,7 @@ private void Accept() catch (ObjectDisposedException) { } catch (Exception ex) { - Fatal("Failed to accept", ex); + Logger.Fatal("Failed to accept", ex); } } @@ -111,7 +114,7 @@ private void AcceptCallback(IAsyncResult result) { return DateTime.Now; }); - DebugFormat("Accepted client {0}", client); + Logger.DebugFormat("Accepted client {0}", client); client.Start(); } catch (Exception) { @@ -122,7 +125,7 @@ private void AcceptCallback(IAsyncResult result) catch (ObjectDisposedException) { } catch (Exception ex) { - Error("Failed to accept a client", ex); + Logger.Error("Failed to accept a client", ex); } finally { Accept(); @@ -144,7 +147,7 @@ private static string GenerateServerSignature() pstring = Formatting.GetSystemName(); } catch (Exception ex) { - LogManager.GetLogger(typeof(HttpServer)).Debug("Failed to get uname", ex); + _logger.Debug("Failed to get uname", ex); } break; } @@ -163,7 +166,7 @@ private void TimeouterCallback(object sender, ElapsedEventArgs e) { foreach (var c in clients.ToList()) { if (c.Key.IsATimeout) { - DebugFormat("Collected timeout client {0}", c); + Logger.DebugFormat("Collected timeout client {0}", c); c.Key.Close(); } } @@ -219,7 +222,7 @@ internal void RegisterHandler(IPrefixHandler handler) if (!prefixes.TryAdd(prefix, handler)) { throw new ArgumentException("Invalid preifx; already taken"); } - DebugFormat("Registered Handler for {0}", prefix); + Logger.DebugFormat("Registered Handler for {0}", prefix); } internal void RemoveClient(HttpClient client) @@ -232,13 +235,13 @@ internal void UnregisterHandler(IPrefixHandler handler) { IPrefixHandler ignored; if (prefixes.TryRemove(handler.Prefix, out ignored)) { - DebugFormat("Unregistered Handler for {0}", handler.Prefix); + Logger.DebugFormat("Unregistered Handler for {0}", handler.Prefix); } } public void Dispose() { - Debug("Disposing HTTP"); + Logger.Debug("Disposing HTTP"); timeouter.Enabled = false; foreach (var s in servers.Values.ToList()) { UnregisterMediaServer(s); @@ -268,7 +271,7 @@ public void RegisterMediaServer(IMediaServer server) RegisterHandler(mount); foreach (var address in IP.ExternalIPAddresses) { - DebugFormat("Registering device for {0}", address); + Logger.DebugFormat("Registering device for {0}", address); var deviceGuid = Guid.NewGuid(); var list = devicesForServers.GetOrAdd(guid, new List()); lock (list) { @@ -282,7 +285,7 @@ public void RegisterMediaServer(IMediaServer server) mount.DescriptorURI )); ssdpServer.RegisterNotification(deviceGuid, uri, address); - NoticeFormat("New mount at: {0}", uri); + Logger.NoticeFormat("New mount at: {0}", uri); } } @@ -310,7 +313,7 @@ public void UnregisterMediaServer(IMediaServer server) MediaMount ignored; if (servers.TryRemove(server.Uuid, out ignored)) { - InfoFormat("Unregistered Media Server {0}", server.Uuid); + Logger.InfoFormat("Unregistered Media Server {0}", server.Uuid); } } } diff --git a/server/Http/HttpAuthorizer.cs b/server/Http/HttpAuthorizer.cs index ef93c1ec..53366a90 100644 --- a/server/Http/HttpAuthorizer.cs +++ b/server/Http/HttpAuthorizer.cs @@ -4,13 +4,11 @@ using System.Net; namespace NMaier.SimpleDlna.Server -{ - public sealed class HttpAuthorizer - : Logging, IHttpAuthorizationMethod, IDisposable +{//Logging, + public sealed class HttpAuthorizer : IHttpAuthorizationMethod, IDisposable { - private readonly List methods = - new List(); - + private static readonly ILogging Logger = Logging.GetLogger(); + private readonly List methods = new List(); private readonly HttpServer server = null; public HttpAuthorizer() @@ -45,6 +43,7 @@ public void AddMethod(IHttpAuthorizationMethod method) public bool Authorize(IHeaders headers, IPEndPoint endPoint, string mac) { + Logger.NoticeFormat("Authorize:[{0}][{1}][{2}]", endPoint, mac, headers["User-Agent"]); if (methods.Count == 0) { return true; } @@ -57,7 +56,7 @@ public bool Authorize(IHeaders headers, IPEndPoint endPoint, string mac) return false; } catch (Exception ex) { - Error("Failed to authorize", ex); + Logger.Error("Failed to authorize", ex); return false; } } diff --git a/server/Http/HttpClient.cs b/server/Http/HttpClient.cs index 4889220d..c5ba7de7 100644 --- a/server/Http/HttpClient.cs +++ b/server/Http/HttpClient.cs @@ -7,9 +7,11 @@ using System.Text.RegularExpressions; namespace NMaier.SimpleDlna.Server -{ - internal sealed class HttpClient : Logging, IRequest, IDisposable +{//Logging, + internal sealed class HttpClient : IRequest, IDisposable { + private static readonly ILogging Logger = Logging.GetLogger(); + private const uint BEGIN_TIMEOUT = 30; private const int BUFFER_SIZE = 1 << 16; @@ -244,7 +246,7 @@ private Stream ProcessRanges(IResponse rangedResponse, ref HttpCode status) status = HttpCode.Partial; } catch (Exception ex) { - Warn(String.Format( + Logger.Warn(String.Format( "{0} - Failed to process range request!", this), ex); } return responseBody; @@ -256,7 +258,7 @@ private void Read() stream.BeginRead(buffer, 0, buffer.Length, ReadCallback, 0); } catch (IOException ex) { - Warn(String.Format("{0} - Failed to BeginRead", this), ex); + Logger.Warn(String.Format("{0} - Failed to BeginRead", this), ex); Close(); } } @@ -275,13 +277,13 @@ private void ReadCallback(IAsyncResult result) if (read < 0) { throw new HttpException("Client did not send anything"); } - DebugFormat("{0} - Read {1} bytes", this, read); + Logger.DebugFormat("{0} - Read {1} bytes", this, read); readStream.Write(buffer, 0, read); lastActivity = DateTime.Now; } catch (Exception) { if (!IsATimeout) { - WarnFormat("{0} - Failed to read data", this); + Logger.WarnFormat("{0} - Failed to read data", this); Close(); } return; @@ -304,7 +306,7 @@ private void ReadCallback(IAsyncResult result) } var bytes = Encoding.ASCII.GetBytes(reader.ReadToEnd()); readStream.Write(bytes, 0, bytes.Length); - DebugFormat("Must read body bytes {0}", bodyBytes); + Logger.DebugFormat("Must read body bytes {0}", bodyBytes); } else { readStream = new MemoryStream(); @@ -315,7 +317,7 @@ private void ReadCallback(IAsyncResult result) var parts = line.Split(new char[] { ' ' }, 3); method = parts[0].Trim().ToUpperInvariant(); path = parts[1].Trim(); - DebugFormat("{0} - {1} request for {2}", this, method, path); + Logger.DebugFormat("{0} - {1} request for {2}", this, method, path); } else { var parts = line.Split(new char[] { ':' }, 2); @@ -324,20 +326,20 @@ private void ReadCallback(IAsyncResult result) } } if (bodyBytes != 0 && bodyBytes > readStream.Length) { - DebugFormat( + Logger.DebugFormat( "{0} - Bytes to go {1}", this, bodyBytes - readStream.Length); Read(); return; } using (readStream) { body = Encoding.UTF8.GetString(readStream.ToArray()); - Debug(body); - Debug(headers); + Logger.Debug(body); + Logger.Debug(headers); } SetupResponse(); } catch (Exception ex) { - Warn(String.Format("{0} - Failed to process request", this), ex); + Logger.Warn(String.Format("{0} - Failed to process request", this), ex); response = Error500.HandleRequest(this); SendResponse(); } @@ -380,7 +382,7 @@ private void SendResponse() responseStream.AddStream(responseBody); responseBody = null; } - InfoFormat("{0} - {1} response for {2}", this, (uint)statusCode, path); + Logger.InfoFormat("{0} - {1} response for {2}", this, (uint)statusCode, path); state = HttpStates.WRITING; var sp = new StreamPump(responseStream, stream, BUFFER_SIZE); sp.Pump((pump, result) => @@ -388,7 +390,7 @@ private void SendResponse() pump.Input.Close(); pump.Input.Dispose(); if (result == StreamPumpResult.Delivered) { - DebugFormat("{0} - Done writing response", this); + Logger.DebugFormat("{0} - Done writing response", this); string conn; if (headers.TryGetValue("connection", out conn) && @@ -398,7 +400,7 @@ private void SendResponse() } } else { - DebugFormat("{0} - Client aborted connection", this); + Logger.DebugFormat("{0} - Client aborted connection", this); } Close(); }); @@ -422,6 +424,7 @@ private void SetupResponse() throw new HttpStatusException(HttpCode.Denied); } if (string.IsNullOrEmpty(path)) { + Logger.Error("Empty path"); throw new HttpStatusException(HttpCode.NotFound); } var handler = owner.FindHandler(path); @@ -435,9 +438,9 @@ private void SetupResponse() } catch (HttpStatusException ex) { #if DEBUG - Warn(String.Format("{0} - Got a {2}: {1}", this, path, ex.Code), ex); + Logger.Warn(String.Format("{0} - Got a {2}: {1}", this, path, ex.Code), ex); #else - InfoFormat("{0} - Got a {2}: {1}", this, path, ex.Code); + Logger.InfoFormat("{0} - Got a {2}: {1}", this, path, ex.Code); #endif switch (ex.Code) { case HttpCode.NotFound: @@ -459,7 +462,7 @@ private void SetupResponse() } } catch (Exception ex) { - Warn(String.Format("{0} - Failed to process response", this), ex); + Logger.Warn(String.Format("{0} - Failed to process response", this), ex); response = Error500.HandleRequest(this); } SendResponse(); @@ -469,7 +472,7 @@ internal void Close() { State = HttpStates.CLOSED; - DebugFormat( + Logger.DebugFormat( "{0} - Closing connection after {1} requests", this, requestCount); try { client.Close(); diff --git a/server/Http/IPAddressAuthorizer.cs b/server/Http/IPAddressAuthorizer.cs index f7f453ac..e1b5ec29 100644 --- a/server/Http/IPAddressAuthorizer.cs +++ b/server/Http/IPAddressAuthorizer.cs @@ -5,9 +5,10 @@ using System.Net; namespace NMaier.SimpleDlna.Server -{ - public sealed class IPAddressAuthorizer : Logging, IHttpAuthorizationMethod +{//Logging, + public sealed class IPAddressAuthorizer : IHttpAuthorizationMethod { + private static readonly ILogging Logger = Logging.GetLogger(); private readonly Dictionary ips = new Dictionary(); @@ -41,10 +42,10 @@ public bool Authorize(IHeaders headers, IPEndPoint endPoint, string mac) } var rv = ips.ContainsKey(addr); if (!rv) { - DebugFormat("Rejecting {0}. Not in IP whitelist", addr); + Logger.DebugFormat("Rejecting {0}. Not in IP whitelist", addr); } else { - DebugFormat("Accepted {0} via IP whitelist", addr); + Logger.DebugFormat("Accepted {0} via IP whitelist", addr); } return rv; } diff --git a/server/Http/MacAuthorizer.cs b/server/Http/MacAuthorizer.cs index a3f33482..25d50b1a 100644 --- a/server/Http/MacAuthorizer.cs +++ b/server/Http/MacAuthorizer.cs @@ -4,9 +4,10 @@ using System.Net; namespace NMaier.SimpleDlna.Server -{ - public sealed class MacAuthorizer : Logging, IHttpAuthorizationMethod +{//Logging, + public sealed class MacAuthorizer : IHttpAuthorizationMethod { + private static readonly ILogging Logger = Logging.GetLogger(); private readonly Dictionary macs = new Dictionary(); @@ -36,10 +37,10 @@ public bool Authorize(IHeaders headers, IPEndPoint endPoint, string mac) var rv = macs.ContainsKey(mac); if (!rv) { - DebugFormat("Rejecting {0}. Not in MAC whitelist", mac ?? ""); + Logger.DebugFormat("Rejecting {0}. Not in MAC whitelist", mac ?? ""); } else { - DebugFormat("Accepted {0} via MAC whitelist", mac); + Logger.DebugFormat("Accepted {0} via MAC whitelist", mac); } return rv; } diff --git a/server/Http/UserAgentAuthorizer.cs b/server/Http/UserAgentAuthorizer.cs index eb4575bb..91e74aa1 100644 --- a/server/Http/UserAgentAuthorizer.cs +++ b/server/Http/UserAgentAuthorizer.cs @@ -4,9 +4,10 @@ using System.Net; namespace NMaier.SimpleDlna.Server -{ - public sealed class UserAgentAuthorizer : Logging, IHttpAuthorizationMethod +{//Logging, + public sealed class UserAgentAuthorizer : IHttpAuthorizationMethod { + private static readonly ILogging Logger = Logging.GetLogger(); private readonly Dictionary userAgents = new Dictionary(); @@ -41,10 +42,10 @@ public bool Authorize(IHeaders headers, IPEndPoint endPoint, string mac) } var rv = userAgents.ContainsKey(ua); if (!rv) { - DebugFormat("Rejecting {0}. Not in User-Agent whitelist", ua); + Logger.DebugFormat("Rejecting {0}. Not in User-Agent whitelist", ua); } else { - DebugFormat("Accepted {0} via User-Agent whitelist", ua); + Logger.DebugFormat("Accepted {0} via User-Agent whitelist", ua); } return rv; } diff --git a/server/Responses/ItemResponse.cs b/server/Responses/ItemResponse.cs index 0d625bcc..5ef30819 100644 --- a/server/Responses/ItemResponse.cs +++ b/server/Responses/ItemResponse.cs @@ -4,9 +4,10 @@ using System.IO; namespace NMaier.SimpleDlna.Server -{ - internal sealed class ItemResponse : Logging, IResponse +{//Logging, + internal sealed class ItemResponse : IResponse { + private static readonly ILogging Logger = Logging.GetLogger(); private readonly Headers headers; private readonly IMediaResource item; @@ -63,7 +64,7 @@ public ItemResponse(string prefix, IRequest request, IMediaResource item, prefix, item.Id ); - DebugFormat("Sending subtitles {0}", surl); + Logger.DebugFormat("Sending subtitles {0}", surl); headers.Add("CaptionInfo.sec", surl); } } @@ -81,7 +82,7 @@ public ItemResponse(string prefix, IRequest request, IMediaResource item, } headers.Add("transferMode.dlna.org", transferMode); - Debug(headers); + Logger.Debug(headers); } public Stream Body diff --git a/server/Responses/ResourceResponse.cs b/server/Responses/ResourceResponse.cs index e2b43f27..6c7e282f 100644 --- a/server/Responses/ResourceResponse.cs +++ b/server/Responses/ResourceResponse.cs @@ -4,9 +4,10 @@ using System.Resources; namespace NMaier.SimpleDlna.Server -{ - internal sealed class ResourceResponse : Logging, IResponse +{//Logging, + internal sealed class ResourceResponse : IResponse { + private static readonly ILogging Logger = Logging.GetLogger(); private readonly IHeaders headers = new ResponseHeaders(); private readonly byte[] resource; @@ -29,7 +30,7 @@ public ResourceResponse(HttpCode aStatus, string type, headers["Content-Length"] = resource.Length.ToString(); } catch (Exception ex) { - Error("Failed to prepare resource " + aResource, ex); + Logger.Error("Failed to prepare resource " + aResource, ex); throw; } } diff --git a/server/Ssdp/Datagram.cs b/server/Ssdp/Datagram.cs index a9fd1077..e382ca84 100644 --- a/server/Ssdp/Datagram.cs +++ b/server/Ssdp/Datagram.cs @@ -6,8 +6,9 @@ namespace NMaier.SimpleDlna.Server.Ssdp { - internal sealed class Datagram : Logging + internal sealed class Datagram// : Logging { + private static readonly ILogging Logger = Logging.GetLogger(); public readonly IPEndPoint EndPoint; public readonly IPAddress LocalAddress; @@ -46,7 +47,7 @@ public void Send() client.EndSend(result); } catch (Exception ex) { - Debug(ex); + Logger.Debug(ex); } finally { try { @@ -58,7 +59,7 @@ public void Send() }, null); } catch (Exception ex) { - Error(ex); + Logger.Error(ex); } ++SendCount; } diff --git a/server/Ssdp/SsdpHandler.cs b/server/Ssdp/SsdpHandler.cs index 7e86c6ce..ddfed05a 100644 --- a/server/Ssdp/SsdpHandler.cs +++ b/server/Ssdp/SsdpHandler.cs @@ -12,9 +12,12 @@ using Timers = System.Timers; namespace NMaier.SimpleDlna.Server.Ssdp -{ - internal sealed class SsdpHandler : Logging, IDisposable +{//Logging, + internal sealed class SsdpHandler : IDisposable { + + private static readonly ILogging Logger = Logging.GetLogger(); + private const int DATAGRAMS_PER_MESSAGE = 3; private const string SSDP_ADDR = "239.255.255.250"; @@ -67,7 +70,7 @@ public SsdpHandler() client.ExclusiveAddressUse = false; client.Client.Bind(new IPEndPoint(IPAddress.Any, SSDP_PORT)); client.JoinMulticastGroup(SSDP_IP, 10); - Notice("SSDP service started"); + Logger.Notice("SSDP service started"); Receive(); } @@ -163,10 +166,10 @@ private void ReceiveCallback(IAsyncResult result) } } catch (IOException ex) { - Debug("Failed to read SSDP message", ex); + Logger.Debug("Failed to read SSDP message", ex); } catch (Exception ex) { - Warn("Failed to read SSDP message", ex); + Logger.Warn("Failed to read SSDP message", ex); } Receive(); } @@ -202,21 +205,21 @@ private void SendSearchResponse(IPEndPoint endpoint, UpnpDevice dev) String.Format("HTTP/1.1 200 OK\r\n{0}\r\n", headers.HeaderBlock), false ); - InfoFormat( + Logger.InfoFormat( "{2}, {1} - Responded to a {0} request", dev.Type, endpoint, dev.Address); } private void Tick(object sender, Timers.ElapsedEventArgs e) { - Debug("Sending SSDP notifications!"); + Logger.Debug("Sending SSDP notifications!"); notificationTimer.Interval = random.Next(60000, 120000); NotifyAll(); } internal void NotifyAll() { - Debug("NotifyAll"); + Logger.Debug("NotifyAll"); foreach (var d in Devices) { NotifyDevice(d, "alive", false); } @@ -224,7 +227,7 @@ internal void NotifyAll() internal void NotifyDevice(UpnpDevice dev, string type, bool sticky) { - Debug("NotifyDevice"); + Logger.Debug("NotifyDevice"); var headers = new RawHeaders(); headers.Add("HOST", "239.255.255.250:1900"); headers.Add("CACHE-CONTROL", "max-age = 600"); @@ -248,7 +251,7 @@ internal void NotifyDevice(UpnpDevice dev, string type, bool sticky) String.Format("NOTIFY * HTTP/1.1\r\n{0}\r\n", headers.HeaderBlock), sticky ); - DebugFormat("{0} said {1}", dev.USN, type); + Logger.DebugFormat("{0} said {1}", dev.USN, type); } internal void RegisterNotification(Guid UUID, Uri Descriptor, @@ -272,7 +275,7 @@ internal void RegisterNotification(Guid UUID, Uri Descriptor, } NotifyAll(); - DebugFormat("Registered mount {0}, {1}", UUID, address); + Logger.DebugFormat("Registered mount {0}, {1}", UUID, address); } internal void RespondToSearch(IPEndPoint endpoint, string req) @@ -281,7 +284,7 @@ internal void RespondToSearch(IPEndPoint endpoint, string req) req = null; } - DebugFormat("RespondToSearch {0} {1}", endpoint, req); + Logger.DebugFormat("RespondToSearch {0} {1}", endpoint, req); foreach (var d in Devices) { if (!string.IsNullOrEmpty(req) && req != d.Type) { continue; @@ -302,12 +305,12 @@ internal void UnregisterNotification(Guid UUID) foreach (var d in dl) { NotifyDevice(d, "byebye", true); } - DebugFormat("Unregistered mount {0}", UUID); + Logger.DebugFormat("Unregistered mount {0}", UUID); } public void Dispose() { - Debug("Disposing SSDP"); + Logger.Debug("Disposing SSDP"); running = false; while (messageQueue.Count != 0) { datagramPosted.WaitOne(); diff --git a/server/Types/Identifiers.cs b/server/Types/Identifiers.cs index 8368aa39..6f224912 100644 --- a/server/Types/Identifiers.cs +++ b/server/Types/Identifiers.cs @@ -7,8 +7,9 @@ namespace NMaier.SimpleDlna.Server { - public sealed class Identifiers : Logging + public sealed class Identifiers// : Logging { + private static readonly ILogging Logger = Logging.GetLogger(); public const string GeneralRoot = "0"; public const string SamsungAudio = "A"; @@ -92,7 +93,7 @@ public void AddView(string name) views.Add(ViewRepository.Lookup(name)); } catch (Exception ex) { - Error("Failed to add view", ex); + Logger.Error("Failed to add view", ex); throw; } } @@ -112,7 +113,7 @@ public void Cleanup() } } paths = npaths; - DebugFormat("Cleanup complete: ids (evicted) {0} ({1}), paths {2} ({3})", ids.Count, ic - ids.Count, paths.Count, pc - paths.Count); + Logger.DebugFormat("Cleanup complete: ids (evicted) {0} ({1}), paths {2} ({3})", ids.Count, ic - ids.Count, paths.Count, pc - paths.Count); } public IMediaItem GetItemById(string id) diff --git a/server/Types/SubTitle.cs b/server/Types/SubTitle.cs index 89587ff9..3248aac0 100644 --- a/server/Types/SubTitle.cs +++ b/server/Types/SubTitle.cs @@ -1,5 +1,4 @@ -using log4net; -using NMaier.SimpleDlna.Utilities; +using NMaier.SimpleDlna.Utilities; using System; using System.IO; using System.Text; @@ -12,12 +11,9 @@ public sealed class Subtitle : IMediaResource [NonSerialized] private byte[] encodedText = null; - [NonSerialized] - private static readonly ILog logger = - LogManager.GetLogger(typeof(Subtitle)); + private static readonly ILogging logger = Logging.GetLogger(); - [NonSerialized] - private static readonly string[] exts = new string[] { + private static readonly string[] exts = new string[] { ".srt", ".SRT", ".ass", ".ASS", ".ssa", ".SSA", diff --git a/server/Views/BaseView.cs b/server/Views/BaseView.cs index 25f20120..588015b0 100644 --- a/server/Views/BaseView.cs +++ b/server/Views/BaseView.cs @@ -1,8 +1,8 @@ using NMaier.SimpleDlna.Utilities; namespace NMaier.SimpleDlna.Server.Views -{ - internal abstract class BaseView : Logging, IView +{//Logging, + internal abstract class BaseView : IView { public abstract string Description { get; } diff --git a/server/Views/ByTitleView.cs b/server/Views/ByTitleView.cs index f5ddc1f0..fea710da 100644 --- a/server/Views/ByTitleView.cs +++ b/server/Views/ByTitleView.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using NMaier.SimpleDlna.Utilities; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -6,6 +7,7 @@ namespace NMaier.SimpleDlna.Server.Views { internal sealed class ByTitleView : BaseView { + private static readonly ILogging Logger = Logging.GetLogger(); public override string Description { get @@ -93,7 +95,7 @@ public override IMediaFolder Transform(IMediaFolder Root) } foreach (var i in titles.ChildFolders.ToList()) { if (i.ChildCount > 100) { - ErrorFormat("Partioning folder {0}", i.Title); + Logger.ErrorFormat("Partioning folder {0}", i.Title); PartitionChildren(i as VirtualFolder, new Prefixer()); } root.AdoptFolder(i); diff --git a/server/Views/FilterView.cs b/server/Views/FilterView.cs index 729b67da..6970d03b 100644 --- a/server/Views/FilterView.cs +++ b/server/Views/FilterView.cs @@ -7,6 +7,7 @@ namespace NMaier.SimpleDlna.Server.Views { internal class FilterView : FilteringView { + private static readonly ILogging Logger = Logging.GetLogger(); private Regex filter = null; public override string Description @@ -61,7 +62,7 @@ public override void SetParameters(AttributeCollection parameters) String.Join("|", filters), RegexOptions.Compiled | RegexOptions.IgnoreCase ); - NoticeFormat("Using filter {0}", filter.ToString()); + Logger.NoticeFormat("Using filter {0}", filter.ToString()); } public override IMediaFolder Transform(IMediaFolder root) diff --git a/server/Views/LargeView.cs b/server/Views/LargeView.cs index 5861944d..416c3bf9 100644 --- a/server/Views/LargeView.cs +++ b/server/Views/LargeView.cs @@ -1,7 +1,6 @@ using NMaier.SimpleDlna.Server.Metadata; using NMaier.SimpleDlna.Utilities; using System; -using System.Linq; namespace NMaier.SimpleDlna.Server.Views { diff --git a/server/packages.config b/server/packages.config deleted file mode 100644 index 7e8e029a..00000000 --- a/server/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/server/server.csproj b/server/server.csproj index 7461c244..03054083 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -26,7 +26,7 @@ 4 - pdbonly + none true bin\Release\ TRACE @@ -44,10 +44,6 @@ - - False - ..\packages\log4net.2.0.3\lib\net40-client\log4net.dll - @@ -166,7 +162,6 @@ - diff --git a/tests/App.config b/tests/App.config new file mode 100644 index 00000000..764bdd32 --- /dev/null +++ b/tests/App.config @@ -0,0 +1,24 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ByTitleViewTest.cs b/tests/ByTitleViewTest.cs index b03a804a..f8a2ff7b 100644 --- a/tests/ByTitleViewTest.cs +++ b/tests/ByTitleViewTest.cs @@ -4,7 +4,7 @@ using System.Linq; using tests.Mocks; -namespace tests +namespace SimpleDlna.Tests { /// /// ByTitleView transformation tests diff --git a/tests/FileStoreReaderWriterTest.cs b/tests/FileStoreReaderWriterTest.cs new file mode 100644 index 00000000..f5dae533 --- /dev/null +++ b/tests/FileStoreReaderWriterTest.cs @@ -0,0 +1,105 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.FileMediaServer; +using System.IO; +using System; +using SimpleDlna.Tests.Mocks; +using NMaier.SimpleDlna.Utilities; +using NMaier.SimpleDlna.Server; + +namespace SimpleDlna.Tests +{ + /// + /// ByTitleView transformation tests + /// + [TestFixture] + public class FileStoreReaderTest + { + [Serializable] + public class FileStoreMock : IFileStore + { + public string StoreFile + { + get + { + throw new NotImplementedException(); + } + } + + public string Description + { + get + { + throw new NotImplementedException(); + } + } + + public string Name + { + get + { + throw new NotImplementedException(); + } + } + + public void Dispose() + { + } + + public bool HasCover(IStoreItem file) + { + return _coverData != null; + } + + public byte[] MaybeGetCover(IStoreItem file) + { + return _coverData; + } + + byte[] _fileData = null; + byte[] _coverData = null; + + public byte[] MaybeGetFile(FileInfo info) + { + return _fileData; + } + + public void MaybeStoreFile(IStoreItem file, byte[] data, byte[] coverData) + { + _fileData = data; + _coverData = coverData; + } + + public void SetParameters(AttributeCollection parameters) + { + throw new NotImplementedException(); + } + + public void Init() + { + throw new NotImplementedException(); + } + } + + [Serializable] + public class BaseFileMock : BaseFile { + public BaseFileMock(FileServer server, FileInfo file, DlnaMime type, + DlnaMediaTypes mediaType) : base(server,file,type,mediaType) { + } + } + + [Test] + public void FileStoreReaderWriter_File_Roundtrip_Test() + { + var store = new FileStoreMock(); + var fi = new FileInfo(@"img\Patern_test.jpg"); + var reader = new FileStoreReader(store); + var writer = new FileStoreWriter(store); + var server = new FileServer(DlnaMediaTypes.All, null, new DirectoryInfo[] { new DirectoryInfo(".") }); + var item = new BaseFileMock(server,fi,DlnaMime.AudioAAC,DlnaMediaTypes.Image); + writer.StoreFile(item); + var result = reader.GetFile(fi, null, NMaier.SimpleDlna.Server.DlnaMime.ImageJPEG); + Assert.IsNotNull(result); + Assert.AreEqual(item.Path, result.Path); + } + } +} diff --git a/tests/FileStoreTest.cs b/tests/FileStoreTest.cs new file mode 100644 index 00000000..c754c71e --- /dev/null +++ b/tests/FileStoreTest.cs @@ -0,0 +1,66 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.FileMediaServer; +using System.IO; +using SimpleDlna.Tests.Mocks; + +namespace SimpleDlna.Tests +{ + /// + /// ByTitleView transformation tests + /// + [TestFixture] + public class FileStoreTest + { + [Test] + public void FileStore_SQLite_File_Roundtrip_Test() + { + //var filename = "test.cache"; + IFileStore target = null; + try { + var fi = new FileInfo(@"img\Patern_test.jpg"); + target = new NMaier.SimpleDlna.FileStore.SQLite.FileStore(); + target.Init(); + var f1 = new StoreItemMock(fi); + var data = File.ReadAllBytes(fi.FullName); + var data2 = File.ReadAllBytes(fi.FullName); + target.MaybeStoreFile(f1, data, data2); + //var f1Cover = target.MaybeGetCover(f1); + var f2 = target.MaybeGetFile(fi); + Assert.IsNotNull(f2); + } + finally { + if (target != null) { + target.Dispose(); + if (File.Exists(target.StoreFile)) File.Delete(target.StoreFile); + } + } + } + + [Test] + public void FileStore_RaptorDB_File_Roundtrip_Test() + { + //var filename = "test.cache"; + IFileStore target = null; + try { + var fi = new FileInfo(@"img\Patern_test.jpg"); + target = new NMaier.SimpleDlna.FileStore.RaptorDB.FileStore(); + target.Init(); + var f1 = new StoreItemMock(fi); + var data = File.ReadAllBytes(fi.FullName); + var data2 = File.ReadAllBytes(fi.FullName); + target.MaybeStoreFile(f1, data, data2); + //var f1Cover = target.MaybeGetCover(f1); + var f2 = target.MaybeGetFile(fi); + Assert.IsNotNull(f2); + } + finally { + if (target != null) { + var filename = target.StoreFile; + target.Dispose(); + if ((filename != null) && File.Exists(filename)) File.Delete(filename); + } + } + } + + } +} diff --git a/tests/Mocks/StoreItem.cs b/tests/Mocks/StoreItem.cs new file mode 100644 index 00000000..b70eb504 --- /dev/null +++ b/tests/Mocks/StoreItem.cs @@ -0,0 +1,19 @@ +using NMaier.SimpleDlna.FileMediaServer; +using System; +using System.IO; + +namespace SimpleDlna.Tests.Mocks +{ + [Serializable] + public class StoreItemMock : IStoreItem + { + public StoreItemMock(FileInfo item) { + Item = item; + } + + public FileInfo Item { get; set; } + + public Cover MaybeGetCover() { return null; } + } + +} diff --git a/tests/ServerDescriptionTest.cs b/tests/ServerDescriptionTest.cs new file mode 100644 index 00000000..2a8d8b2b --- /dev/null +++ b/tests/ServerDescriptionTest.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.Server; +using NMaier.SimpleDlna.GUI; +using NMaier.SimpleDlna.Utilities; +using System.IO; + +namespace SimpleDlna.Tests +{ + /// + /// ByTitleView transformation tests + /// + [TestFixture] + public class ServerDescriptionTest + { + + [Test] + public void ServerDescription_AdoptInfo_Test() + { + var data = new ServerDescription { + Directories = new [] { "dir1", "dir2" }, + Name = "data", + Order = "Order", + FileStore = "FileStore", + OrderDescending = false, + Types = DlnaMediaTypes.All, + Views = new [] { "Views1", "Views2" }, + Macs = new [] { "Mac1", "Mac2" }, + Ips = new [] { "IP1", "IP2" }, + UserAgents = new [] { "UserAgent1", "UserAgent2" } + }; + var data2 = new ServerDescription(); + data2.AdoptInfo(data); + Assert.AreEqual(data.Directories, data2.Directories); + Assert.AreEqual(data.Name, data2.Name); + Assert.AreEqual(data.Order, data2.Order); + Assert.AreEqual(data.FileStore, data2.FileStore); + Assert.AreEqual(data.OrderDescending, data2.OrderDescending); + Assert.AreEqual(data.Types, data2.Types); + Assert.AreEqual(data.Views, data2.Views); + Assert.AreEqual(data.Macs, data2.Macs); + Assert.AreEqual(data.Ips, data2.Ips); + Assert.AreEqual(data.UserAgents, data2.UserAgents); + var filenames = new[] { "ServerDescription.tmp1", "ServerDescription.tmp2" }; + try { + XmlHelper.ToFile(data, filenames[0]); + XmlHelper.ToFile(data2, filenames[1]); + Assert.AreEqual(File.ReadAllText(filenames[0]), File.ReadAllText(filenames[1])); + } + finally { + if (File.Exists(filenames[0])) File.Delete(filenames[0]); + if (File.Exists(filenames[1])) File.Delete(filenames[1]); + } + } + } +} diff --git a/tests/Utilities/ReflectionHelperTest.cs b/tests/Utilities/ReflectionHelperTest.cs new file mode 100644 index 00000000..785a94a0 --- /dev/null +++ b/tests/Utilities/ReflectionHelperTest.cs @@ -0,0 +1,34 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.FileMediaServer; +using System.IO; +using SimpleDlna.Tests.Mocks; +using NMaier.SimpleDlna.Utilities; +using NMaier.SimpleDlna.FileStore.SQLite; + +namespace SimpleDlna.Tests.Utilities +{ + /// + /// ByTitleView transformation tests + /// + [TestFixture] + public class ReflectionHelperTest + { + [Test] + public void ReflectionHelper_Create_Test() + { + Assert.IsNotNull(ReflectionHelper.Create("assembly=SimpleDlna.FileStore.SQLite;type=NMaier.SimpleDlna.FileStore.SQLite.FileStore;")); + } + + [Test] + public void ReflectionHelper_StringToDictionary_Test() + { + var d = ReflectionHelper.StringToDictionary(string.Format("assembly={0};type={1};", typeof(FileStore).AssemblyQualifiedName, typeof(FileStore).FullName)); + Assert.IsTrue(d.ContainsKey("assembly")); + Assert.IsTrue(d.ContainsValue(typeof(FileStore).AssemblyQualifiedName)); + Assert.IsTrue(d.ContainsKey("type")); + Assert.IsTrue(d.ContainsValue(typeof(FileStore).FullName)); + Assert.AreEqual(typeof(FileStore).FullName, d["type"]); + Assert.AreEqual(typeof(FileStore).AssemblyQualifiedName, d["assembly"]); + } + } +} diff --git a/tests/Utilities/RepositoryBaseTest.cs b/tests/Utilities/RepositoryBaseTest.cs new file mode 100644 index 00000000..53034924 --- /dev/null +++ b/tests/Utilities/RepositoryBaseTest.cs @@ -0,0 +1,22 @@ +using NUnit.Framework; +using NMaier.SimpleDlna.FileMediaServer; +using System.IO; +using SimpleDlna.Tests.Mocks; +using NMaier.SimpleDlna.Utilities; + +namespace SimpleDlna.Tests.Utilities +{ + /// + /// ByTitleView transformation tests + /// + [TestFixture] + public class RepositoryBaseTest + { + [Test] + public void RepositoryBase_GetDomainAssemblies_Test() + { + var a = RepositoryBase.GetDomainAssemblies(); + Assert.IsTrue(a.Length > 0); + } + } +} diff --git a/tests/Utilities/RepositoryTest.cs b/tests/Utilities/RepositoryTest.cs new file mode 100644 index 00000000..28134dba --- /dev/null +++ b/tests/Utilities/RepositoryTest.cs @@ -0,0 +1,67 @@ +using System; +using NUnit.Framework; +using NMaier.SimpleDlna.Server.Views; +using NMaier.SimpleDlna.Utilities; +using System.Linq; +using tests.Mocks; +using NMaier.SimpleDlna.FileMediaServer; +using NMaier.SimpleDlna.FileStore.SQLite; + +namespace SimpleDlna.Tests.Utilities +{ + /// + /// Summary description for FileServerTest + /// + [TestFixture] + public class RepositoryTest + { + + public sealed class ViewRepositoryMock : Repository + { + } + + [Test] + public void Repository_GetAllTypes_Test() + { + var itype = typeof(IView); + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => a.GetTypes()) + .Where(t => itype.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) + .ToList(); + Assert.IsTrue(types.Contains(typeof(View))); + } + + [Test] + public void Repository_ViewRepository_Lookup_Test() + { + var target = ViewRepositoryMock.Lookup(typeof(View).Name); + Assert.IsNotNull(target); + } + + [Test] + public void Repository_ViewRepository_ListItems_Test() + { + var target = ViewRepositoryMock.ListItems(); + Assert.IsTrue(target.Count > 0); + } + + [Test] + public void Repository_FileStoreRepository_Lookup_Test() + { + var target = FileStoreRepository.Lookup((new NMaier.SimpleDlna.FileStore.SQLite.FileStore()).Name); + Assert.IsNotNull(target); + } + + [Test] + public void Repository_FileStoreRepository_ListItems_Test() + { + var target = FileStoreRepository.ListItems(); + Assert.IsTrue(target.Count > 0); + var keys = target.Keys.ToArray(); + var specificObject = new FileStore(); + Assert.IsTrue(keys.Contains(specificObject.Name)); + } + + + } +} diff --git a/tests/img/Patern_test.jpg b/tests/img/Patern_test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..716ddd6851e9ce3591eca8ddb46bcb8dea7b64fc GIT binary patch literal 36623 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 G$iD$wbi?=n literal 0 HcmV?d00001 diff --git a/tests/packages.config b/tests/packages.config index 904dc42c..fb463a0b 100644 --- a/tests/packages.config +++ b/tests/packages.config @@ -1,4 +1,10 @@  + + + + + + \ No newline at end of file diff --git a/tests/sdlna.key.snk b/tests/sdlna.key.snk new file mode 100644 index 0000000000000000000000000000000000000000..7e30ff02411640e5807b8ad0cd32d48cb745a656 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098wMZfhN->^Nl!3Q5v`Qf>P>)O;|H|uoq zuPj4V8M{Ea1kspx>7m=~Ae!YB7=t~Qz7(eePd3*)*b-~%a=s#O%-qg-@GPL*z6kU% z_rZ(=MtAVlNt1D>hD!9B=erFs`79ybW%gd3zM6N_Iz>{qvKFQq3-ak6OzAl8eiW^5 zOmPO^+X<^b0=H&n5wTcZ@h~o%(e5cR`ANyM%ct%9+9zyuRGC)FvaweMtNrl97Qn?s zamy#uD|T9Fa{c1Xe}>8%>_pA#h$%?caA9j1AF}orjgSmyI)uGpHuDJnF1OsUd=E1f zk2K3S76+h```Oc3U-Wme{HL>gKQqG%c4rE&?-jpk?Bd~E{~Iw+B~Ie<1%V#pR@X6h zUL0C=sJ5rU`+_8=T9L8`X>Kum>Bx}^(cTRDci3P0&#SZP`)nVOm(7?_n}f*+*Mp7U zmFRHUQ!6(|%D+=Co!{Q0Z~W}FwtXwCa7kH`hx=NoeGPF&^xO(LADYK>4*RHvW)k>x z|D7R^sunBQ6`EaX1o|FX8_=_^$?&Ia*X5JrY%JL}CCd})RcW>S)I30*%)=lme~(fB zxem@c$eEzgW0%I70=#Mmb6fA5FbAk;x{*bL8hUCD9;m6A>$BHKjd@@%*%&I!(*-hm zqlVmC$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest + + true @@ -34,15 +36,46 @@ prompt 4 + + false + + + sdlna.key.snk + + + ..\packages\EntityFramework.6.0.0\lib\net40\EntityFramework.dll + True + + + ..\packages\EntityFramework.6.0.0\lib\net40\EntityFramework.SqlServer.dll + True + + + ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll + True + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll True + 3.5 + + ..\packages\System.Data.SQLite.Core.1.0.98.1\lib\net40\System.Data.SQLite.dll + True + + + ..\packages\System.Data.SQLite.EF6.1.0.98.1\lib\net40\System.Data.SQLite.EF6.dll + True + + + ..\packages\System.Data.SQLite.Linq.1.0.98.1\lib\net40\System.Data.SQLite.Linq.dll + True + @@ -54,16 +87,33 @@ + + + + + + + + + + + {6961f1c2-41e9-4e7f-8e88-7d4a259b3df8} + FileStoreRaptorDB + + + {25741114-7f31-421e-8d2b-357a3155cee2} + FileStoreSQLite + {50e06b21-e11a-42f0-81e2-0911e771e861} fsserver @@ -72,11 +122,20 @@ {232a96f6-a2bf-44c8-b623-6e411f6296f2} server + + {9baefb29-c818-446b-9bb5-014e6a0cbb49} + SimpleDLNA + {a8960a7a-887c-40d7-9632-002e94bfc830} util + + + Always + + @@ -97,6 +156,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +