diff --git a/EternalArrowBackup.sln b/EternalArrowBackup.sln index af6262d..2e7ae11 100644 --- a/EternalArrowBackup.sln +++ b/EternalArrowBackup.sln @@ -65,6 +65,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TargetMetadataStorage", "Ta EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EternalArrowBackup.TargetBinaryStorage.InMemoryBinaryStorage.Tests", "Tests\TargetMetadataStorage\InMemoryMetadataStorage\EternalArrowBackup.TargetBinaryStorage.InMemoryBinaryStorage.Tests.csproj", "{A2661315-0A4E-47AA-B0D8-200E98461004}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EternalArrowBackup.ReportStorage.InMemoryReportStorage", "Source\ReportStorage\InMemoryReportStorage\EternalArrowBackup.ReportStorage.InMemoryReportStorage.csproj", "{050B524C-451C-49F6-A9E5-60E40A40CFEE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -139,6 +141,10 @@ Global {A2661315-0A4E-47AA-B0D8-200E98461004}.Debug|Any CPU.Build.0 = Debug|Any CPU {A2661315-0A4E-47AA-B0D8-200E98461004}.Release|Any CPU.ActiveCfg = Release|Any CPU {A2661315-0A4E-47AA-B0D8-200E98461004}.Release|Any CPU.Build.0 = Release|Any CPU + {050B524C-451C-49F6-A9E5-60E40A40CFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {050B524C-451C-49F6-A9E5-60E40A40CFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {050B524C-451C-49F6-A9E5-60E40A40CFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {050B524C-451C-49F6-A9E5-60E40A40CFEE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -173,5 +179,6 @@ Global {AC7EA3E8-6469-4102-940F-31EF831E823F} = {99C42B64-99CF-4FB3-B270-079476B43FF7} {F22F46A0-75BD-49CB-96F2-4E230B59601A} = {884B8E01-303A-40CF-8884-D62115F98683} {A2661315-0A4E-47AA-B0D8-200E98461004} = {F22F46A0-75BD-49CB-96F2-4E230B59601A} + {050B524C-451C-49F6-A9E5-60E40A40CFEE} = {8FA27C30-856D-4895-87AD-BE71847B76EF} EndGlobalSection EndGlobal diff --git a/Source/ReportStorage/Contracts/EternalArrowBackup.ReportStorage.Contracts.csproj b/Source/ReportStorage/Contracts/EternalArrowBackup.ReportStorage.Contracts.csproj index 954020d..0a822af 100644 --- a/Source/ReportStorage/Contracts/EternalArrowBackup.ReportStorage.Contracts.csproj +++ b/Source/ReportStorage/Contracts/EternalArrowBackup.ReportStorage.Contracts.csproj @@ -1,7 +1,11 @@ - + netstandard1.4 + + + + \ No newline at end of file diff --git a/Source/ReportStorage/Contracts/IReportInfo.cs b/Source/ReportStorage/Contracts/IReportInfo.cs index d6852dc..978050f 100644 --- a/Source/ReportStorage/Contracts/IReportInfo.cs +++ b/Source/ReportStorage/Contracts/IReportInfo.cs @@ -1,6 +1,9 @@ namespace EternalArrowBackup.ReportStorage.Contracts { using System; + using System.Threading; + using System.Threading.Tasks; + using System.Threading.Tasks.Dataflow; public interface IReportInfo { @@ -14,8 +17,8 @@ bool HasErrors { get; } - IObservable GetAllErrors(); + Task GetAllErrors(ActionBlock actionBlock, CancellationToken ct); - IObservable GetAllFiles(); + Task GetAllFiles(ActionBlock actionBlock, CancellationToken ct); } } diff --git a/Source/ReportStorage/Contracts/IReportStorage.cs b/Source/ReportStorage/Contracts/IReportStorage.cs index 64b2e03..0448fdf 100644 --- a/Source/ReportStorage/Contracts/IReportStorage.cs +++ b/Source/ReportStorage/Contracts/IReportStorage.cs @@ -1,7 +1,8 @@ namespace EternalArrowBackup.ReportStorage.Contracts { - using System; + using System.Threading; using System.Threading.Tasks; + using System.Threading.Tasks.Dataflow; public interface IReportStorage { @@ -13,6 +14,6 @@ Task AddFileInfo(string reportId, string directoryPath, string fileName, string hash, long size); - IObservable GetAllReports(bool includeEmpty); + Task GetAllReports(ActionBlock actionBlock, bool includeEmpty, CancellationToken ct); } } diff --git a/Source/ReportStorage/InMemoryReportStorage/EternalArrowBackup.ReportStorage.InMemoryReportStorage.csproj b/Source/ReportStorage/InMemoryReportStorage/EternalArrowBackup.ReportStorage.InMemoryReportStorage.csproj new file mode 100644 index 0000000..3d7dba1 --- /dev/null +++ b/Source/ReportStorage/InMemoryReportStorage/EternalArrowBackup.ReportStorage.InMemoryReportStorage.csproj @@ -0,0 +1,15 @@ + + + + netstandard1.4 + + + + + + + + + + + \ No newline at end of file diff --git a/Source/ReportStorage/InMemoryReportStorage/FileInfo.cs b/Source/ReportStorage/InMemoryReportStorage/FileInfo.cs new file mode 100644 index 0000000..3002bed --- /dev/null +++ b/Source/ReportStorage/InMemoryReportStorage/FileInfo.cs @@ -0,0 +1,24 @@ +namespace EternalArrowBackup.ReportStorage.InMemoryReportStorage +{ + using System; + using EternalArrowBackup.ReportStorage.Contracts; + + class FileInfo : IFileInfo + { + public FileInfo(string directoryPath, string filename, string hash, long size) + { + this.DirectoryPath = directoryPath; + this.Filename = filename; + this.Hash = hash; + this.Size = size; + } + + public string DirectoryPath { get; } + + public string Filename { get; } + + public string Hash { get; } + + public long Size { get; } + } +} diff --git a/Source/ReportStorage/InMemoryReportStorage/ReportInfo.cs b/Source/ReportStorage/InMemoryReportStorage/ReportInfo.cs new file mode 100644 index 0000000..7a00dea --- /dev/null +++ b/Source/ReportStorage/InMemoryReportStorage/ReportInfo.cs @@ -0,0 +1,84 @@ +namespace EternalArrowBackup.ReportStorage.InMemoryReportStorage +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using System.Threading.Tasks.Dataflow; + using EternalArrowBackup.ReportStorage.Contracts; + + internal class ReportInfo : IReportInfo + { + public ReportInfo(string reportId, DateTime dateTime) + { + + } + + public string ReportId { get; } + + public DateTime DateTime { get; } + + public bool IsCompleted { get; private set; } = false; + + public bool IsEmpty { get; private set; } + + public bool HasErrors { get; private set; } + + private List Errors { get; } = new List(); + + private List Files { get; } = new List(); + + public Task GetAllErrors(ActionBlock actionBlock, CancellationToken ct) + { + return Task.Run(() => + { + foreach (var error in this.Errors) + { + if (ct.IsCancellationRequested) + { + break; + } + + actionBlock.Post(error); + } + + actionBlock.Complete(); + }); + } + + public Task GetAllFiles(ActionBlock actionBlock, CancellationToken ct) + { + return Task.Run(() => + { + foreach (var fileInfo in this.Files) + { + if (ct.IsCancellationRequested) + { + break; + } + + actionBlock.Post(fileInfo); + } + + actionBlock.Complete(); + }); + } + + public void AddFile(IFileInfo fileInfo) + { + this.Files.Add(fileInfo); + } + + public void AddError(string errorMessage) + { + this.Errors.Add(errorMessage); + } + + public void Complete(bool isEmpty, bool hasErrors) + { + this.IsCompleted = true; + this.IsEmpty = isEmpty; + this.HasErrors = hasErrors; + } + } +} diff --git a/Source/ReportStorage/InMemoryReportStorage/ReportStorage.cs b/Source/ReportStorage/InMemoryReportStorage/ReportStorage.cs new file mode 100644 index 0000000..ed5db5b --- /dev/null +++ b/Source/ReportStorage/InMemoryReportStorage/ReportStorage.cs @@ -0,0 +1,57 @@ +namespace EternalArrowBackup.ReportStorage.InMemoryReportStorage +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using System.Threading.Tasks.Dataflow; + using EternalArrowBackup.ReportStorage.Contracts; + + public class ReportStorage : IReportStorage + { + private Dictionary Reports { get; } = new Dictionary(); + + public Task AddError(string reportId, string errorMessage) + { + return Task.Run(() => this.Reports[reportId].AddError(errorMessage)); + } + + public Task AddFileInfo(string reportId, string directoryPath, string fileName, string hash, long size) + { + return Task.Run(() => this.Reports[reportId].AddFile(new FileInfo(directoryPath, fileName, hash, size))); + } + + public Task CompleteReport(string reportId, bool isEmpty, bool hasErrors) + { + return Task.Run(() => this.Reports[reportId].Complete(isEmpty, hasErrors)); + } + + public Task GetAllReports(ActionBlock actionBlock, bool includeEmpty, CancellationToken ct) + { + return Task.Run(() => + { + foreach (var report in this.Reports.Values) + { + if (ct.IsCancellationRequested) + { + break; + } + + if (!includeEmpty && report.IsCompleted && !report.IsEmpty) + { + continue; + } + + actionBlock.Post(report); + } + + actionBlock.Complete(); + }); + } + + public Task InitReport(string reportId) + { + return Task.Run(() => this.Reports[reportId] = new ReportInfo(reportId, DateTime.UtcNow)); + } + } +}