diff --git a/README.md b/README.md
index 3ad7a4f..bcf75c6 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,15 @@
# Progress
+[](https://github.com/gcastellov/progress/actions/workflows/dotnet.yml)
-Report progression with ease by using multilple components such as Bars, Spinners, Pulse and more
+This library helps you to spin up reporters for giving an overview of a workload's progression. These reporters can either be for console apps that output the information or background jobs hosted by APIs handling the progress via hooks.

## Report progress for console apps
+Report progression with ease by using multilple components such as Bars, Spinners, Pulse and more.
```csharp
-using var reporter = new ReporterBuilder()
+using var reporter = new ConsoleReporterBuilder()
.UsingReportingFrequency(TimeSpan.FromMilliseconds(50))
.UsingComponentDescriptor(BarDescriptor.Default)
.Build(Worker.AllItems);
@@ -23,6 +25,8 @@ await worker.DoMywork();
```
### Define the component to show progress
+Components are subjected to the ConsoleReporter.
+
```csharp
var descriptor = new BarDescriptor()
.UsingProgressSymbol('#')
@@ -37,7 +41,7 @@ var descriptor = BarDescriptor.Default;
### Define the reporter to use the component
```csharp
-var reporter = new ReporterBuilder()
+var reporter = new ConsoleReporterBuilder()
.DisplayingStartingTime()
.DisplayingElapsedTime()
.DisplayingTimeOfArrival()
@@ -51,31 +55,21 @@ var reporter = new ReporterBuilder()
.Build(Worker.AllItems);
```
-### Start the reporter
-```csharp
-reporter.Start();
-```
-
-### Report progress
-```csharp
-reporter.ReportSuccess()
-reporter.ReportFailure()
-```
+## Report progress for background jobs
+In case your workload happens in the background and you only pretend to collect progression status during certain moments of the execution, or export the results at the end, the BackgroundReporter may help you to remove all the boilerplate.
-### Collect stats while running
```csharp
-var onProgress = (Stats stats) =>
-{
- // TODO: Do something useful
-};
-
-var onCompletion = (Stats stats) =>
-{
- // TODO: Do something useful
-};
-
-var reporter = new ReporterBuilder()
- .NotifyingProgress(onProgress)
- .NotifyingCompletion(onCompletion)
+_reporter = new BackgroundReporterBuilder()
+ .NotifyingProgress((stats) =>
+ {
+ logger.LogDebug("Getting stats on progress {percent}", stats.CurrentPercent);
+ })
+ .NotifyingCompletion((stats) =>
+ {
+ logger.LogDebug("Getting stats on completion");
+ })
.Build(Worker.AllItems);
+
+_worker.OnSuccess = () => _reporter.ReportSuccess();
+_worker.OnFailure = () => _reporter.ReportFailure();
```
\ No newline at end of file
diff --git a/src/Progress.UnitTest/Builders/BackgroundReporterBuilderTests.cs b/src/Progress.UnitTest/Builders/BackgroundReporterBuilderTests.cs
new file mode 100644
index 0000000..bc0bd16
--- /dev/null
+++ b/src/Progress.UnitTest/Builders/BackgroundReporterBuilderTests.cs
@@ -0,0 +1,80 @@
+using Progress.Builders;
+using Progress.Settings;
+
+namespace Progress.UnitTest.Builders;
+
+public class BackgroundReporterBuilderTests
+{
+ [Fact]
+ public void GivenProgressNotifications_WhenBuilding_ThenReporterIsSetUp()
+ {
+ // Arrange
+ var callback = (Stats stats) => { };
+ var builder = new BackgroundReporterBuilder()
+ .NotifyingProgress(callback);
+
+ // Act
+ var actual = builder.Build(100);
+
+ // Arrange
+ actual.OnProgress.Should().NotBeNull();
+ actual.OnProgress.Should().Be(callback);
+ actual.Configuration.StatsFrequency.Should().Be(TimeSpan.FromSeconds(5));
+ }
+
+ [Fact]
+ public void GivenProgressNotificationsWithFrequency_WhenBuilding_ThenReporterIsSetUp()
+ {
+ // Arrange
+ var callback = (Stats stats) => { };
+ var frequency = TimeSpan.FromSeconds(20);
+ var builder = new BackgroundReporterBuilder()
+ .NotifyingProgress(callback, frequency);
+
+ // Act
+ var actual = builder.Build(100);
+
+ // Arrange
+ actual.OnProgress.Should().NotBeNull();
+ actual.OnProgress.Should().Be(callback);
+ actual.Configuration.StatsFrequency.Should().Be(frequency);
+ actual.Configuration.Options.NotifyProgressStats.Should().BeTrue();
+ }
+
+ [Fact]
+ public void GivenCompletionNotifications_WhenBuilding_ThenReporterIsSetUp()
+ {
+ // Arrange
+ var callback = (Stats stats) => { };
+ var builder = new BackgroundReporterBuilder()
+ .NotifyingCompletion(callback);
+
+ // Act
+ var actual = builder.Build(100);
+
+ // Arrange
+ actual.OnCompletion.Should().NotBeNull();
+ actual.OnCompletion.Should().Be(callback);
+ actual.Configuration.Options.NotifyCompletionStats.Should().BeTrue();
+ }
+
+ [Fact]
+ public void GivenExporting_WhenBuilding_ThenReporterIsSetUp()
+ {
+ // Arrange
+ const string fileName = "output.txt";
+ const FileType type = FileType.Text;
+ var builder = new BackgroundReporterBuilder()
+ .ExportingTo(fileName, type);
+
+ // Act
+ var actual = builder.Build(100);
+
+ // Assert
+ actual.Configuration.ExportSettings.Should().NotBeNull();
+ actual.Configuration.ExportSettings.FileName.Should().Be(fileName);
+ actual.Configuration.ExportSettings.FileType.Should().Be(FileType.Text);
+ actual.Configuration.Options.ExportCompletionStats.Should().BeTrue();
+ }
+
+}
diff --git a/src/Progress.UnitTest/ReporterBuilderTests.cs b/src/Progress.UnitTest/Builders/ConsoleReporterBuilderTests.cs
similarity index 82%
rename from src/Progress.UnitTest/ReporterBuilderTests.cs
rename to src/Progress.UnitTest/Builders/ConsoleReporterBuilderTests.cs
index fc39528..df0c456 100644
--- a/src/Progress.UnitTest/ReporterBuilderTests.cs
+++ b/src/Progress.UnitTest/Builders/ConsoleReporterBuilderTests.cs
@@ -1,14 +1,15 @@
-using Progress.Settings;
+using Progress.Builders;
+using Progress.Settings;
-namespace Progress.UnitTest;
+namespace Progress.UnitTest.Builders;
-public class ReporterBuilderTests
+public class ConsoleReporterBuilderTests
{
[Fact]
public void GivenNothingToComplete_WhenBuilding_ThenThrowsException()
{
// Arrange
- var builder = new ReporterBuilder();
+ var builder = new ConsoleReporterBuilder();
// Act
var action = () => builder.Build(0);
@@ -21,7 +22,7 @@ public void GivenNothingToComplete_WhenBuilding_ThenThrowsException()
public void GivenSomethingToComplete_WhenBuilding_ThenReturnsReporter()
{
// Arrange
- var builder = new ReporterBuilder();
+ var builder = new ConsoleReporterBuilder();
// Act
var actual = builder.Build(100);
@@ -35,7 +36,7 @@ public void GivenReportingFrequency_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
var expectedFrequency = TimeSpan.FromSeconds(20);
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.UsingReportingFrequency(expectedFrequency);
// Act
@@ -49,7 +50,7 @@ public void GivenReportingFrequency_WhenBuilding_ThenReporterIsSetUp()
public void GivenElapsedTime_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.DisplayingElapsedTime();
// Act
@@ -63,7 +64,7 @@ public void GivenElapsedTime_WhenBuilding_ThenReporterIsSetUp()
public void GivenStartingTime_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.DisplayingStartingTime();
// Act
@@ -77,7 +78,7 @@ public void GivenStartingTime_WhenBuilding_ThenReporterIsSetUp()
public void GivenItemsOverview_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.DisplayingItemsOverview();
// Act
@@ -91,7 +92,7 @@ public void GivenItemsOverview_WhenBuilding_ThenReporterIsSetUp()
public void GivenSummary_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.DisplayingItemsSummary();
// Act
@@ -106,7 +107,7 @@ public void GivenProgressNotifications_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
var callback = (Stats stats) => { };
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.NotifyingProgress(callback);
// Act
@@ -124,7 +125,7 @@ public void GivenProgressNotificationsWithFrequency_WhenBuilding_ThenReporterIsS
// Arrange
var callback = (Stats stats) => { };
var frequency = TimeSpan.FromSeconds(20);
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.NotifyingProgress(callback, frequency);
// Act
@@ -142,7 +143,7 @@ public void GivenCompletionNotifications_WhenBuilding_ThenReporterIsSetUp()
{
// Arrange
var callback = (Stats stats) => { };
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.NotifyingCompletion(callback);
// Act
@@ -160,7 +161,7 @@ public void GivenExporting_WhenBuilding_ThenReporterIsSetUp()
// Arrange
const string fileName = "output.txt";
const FileType type = FileType.Text;
- var builder = new ReporterBuilder()
+ var builder = new ConsoleReporterBuilder()
.ExportingTo(fileName, type);
// Act
diff --git a/src/Progress.UnitTest/PrinterTests.cs b/src/Progress.UnitTest/PrinterTests.cs
index c1e5582..a80db71 100644
--- a/src/Progress.UnitTest/PrinterTests.cs
+++ b/src/Progress.UnitTest/PrinterTests.cs
@@ -8,7 +8,7 @@ public class PrinterTests
public void GivenDefaults_WhenPrinting_ThenGetsOutput()
{
// Arrange
- Printer printer = new(new Settings.ReportingOptions(), BarDescriptor.Default.Build());
+ Printer printer = new(new Settings.Console.ReportingOptions(), BarDescriptor.Default.Build());
Stats stats = new();
// Act
diff --git a/src/Progress.UnitTest/Progress.UnitTest.csproj b/src/Progress.UnitTest/Progress.UnitTest.csproj
index b775e1f..0a3c19b 100644
--- a/src/Progress.UnitTest/Progress.UnitTest.csproj
+++ b/src/Progress.UnitTest/Progress.UnitTest.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Progress.UnitTest/Reporters/BackgroundReporterTests.cs b/src/Progress.UnitTest/Reporters/BackgroundReporterTests.cs
new file mode 100644
index 0000000..b6d05f0
--- /dev/null
+++ b/src/Progress.UnitTest/Reporters/BackgroundReporterTests.cs
@@ -0,0 +1,74 @@
+using Progress.Descriptors;
+using Progress.Reporters;
+
+namespace Progress.UnitTest.Reporters;
+
+public class BackgroundReporterTests
+{
+ [Fact]
+ public void GivenNothingToComplete_WhenInitializing_ThenThrowsException()
+ {
+ // Act
+ var action = () => new BackgroundReporter(0);
+
+ // Assert
+ action.Should().Throw();
+ }
+
+ [Fact]
+ public void GivenOperationNotStarted_WhenStopping_ThenThrowsException()
+ {
+ // Arrange
+ var reporter = new BackgroundReporter(100);
+
+ // Act
+ var action = () => reporter.Stop();
+
+ // Assert
+ action.Should().Throw();
+ }
+
+ [Fact]
+ public async Task GivenProgressNotifications_WhenRunning_ThenCallbackIsCalled()
+ {
+ // Arrange
+ bool isCalled = false;
+ var reporter = new BackgroundReporter(100)
+ {
+ OnProgress = (stats) => isCalled = true
+ };
+
+ reporter.Configuration.Options.NotifyProgressStats = true;
+ reporter.Configuration.StatsFrequency = TimeSpan.FromSeconds(1);
+
+
+ // Act
+ reporter.Start();
+ await Task.Delay(TimeSpan.FromMilliseconds(1500));
+
+ // Assert
+ isCalled.Should().BeTrue();
+ }
+
+ [Fact]
+ public async Task GivenCompletionNotifications_WhenFinished_ThenCallbackIsCalled()
+ {
+ // Arrange
+ bool isCalled = false;
+ var reporter = new BackgroundReporter(1)
+ {
+ OnCompletion = (stats) => isCalled = true
+ };
+
+ reporter.Configuration.Options.NotifyCompletionStats = true;
+ reporter.Configuration.StatsFrequency = TimeSpan.FromMilliseconds(500);
+ reporter.Start();
+
+ // Act
+ reporter.ReportSuccess();
+ await Task.Delay(TimeSpan.FromMilliseconds(1500));
+
+ // Assert
+ isCalled.Should().BeTrue();
+ }
+}
diff --git a/src/Progress.UnitTest/ReporterTests.cs b/src/Progress.UnitTest/Reporters/ConsoleReporterTests.cs
similarity index 78%
rename from src/Progress.UnitTest/ReporterTests.cs
rename to src/Progress.UnitTest/Reporters/ConsoleReporterTests.cs
index 8d760af..6788f99 100644
--- a/src/Progress.UnitTest/ReporterTests.cs
+++ b/src/Progress.UnitTest/Reporters/ConsoleReporterTests.cs
@@ -1,11 +1,12 @@
using Progress.Descriptors;
+using Progress.Reporters;
using System.Text;
-namespace Progress.UnitTest;
+namespace Progress.UnitTest.Reporters;
-public class ReporterTests
+public class ConsoleReporterTests
{
- public ReporterTests()
+ public ConsoleReporterTests()
{
StringBuilder builder = new();
TextWriter writer = new StringWriter(builder);
@@ -16,7 +17,7 @@ public ReporterTests()
public void GivenDefaults_WhenInitializing_ThenExpectedSettings()
{
// Arrange
- var reporter = new Reporter(100, BarDescriptor.Default.Build());
+ var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build());
// Assert
reporter.Configuration.Options.DisplayStartingTime.Should().BeTrue();
@@ -39,7 +40,7 @@ public void GivenDefaults_WhenInitializing_ThenExpectedSettings()
public void GivenNothingToComplete_WhenInitializing_ThenThrowsException()
{
// Act
- var action = () => new Reporter(0, BarDescriptor.Default.Build());
+ var action = () => new ConsoleReporter(0, BarDescriptor.Default.Build());
// Assert
action.Should().Throw();
@@ -49,7 +50,7 @@ public void GivenNothingToComplete_WhenInitializing_ThenThrowsException()
public void GivenNoComponent_WhenInitializing_ThenThrowsException()
{
// Act
- var action = () => new Reporter(100, null!);
+ var action = () => new ConsoleReporter(100, null!);
// Assert
action.Should().Throw();
@@ -59,7 +60,7 @@ public void GivenNoComponent_WhenInitializing_ThenThrowsException()
public void GivenOperationNotStarted_WhenStopping_ThenThrowsException()
{
// Arrange
- var reporter = new Reporter(100, BarDescriptor.Default.Build());
+ var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build());
// Act
var action = () => reporter.Stop();
@@ -72,7 +73,7 @@ public void GivenOperationNotStarted_WhenStopping_ThenThrowsException()
public void GivenOperationNotStarted_WhenResuming_ThenThrowsException()
{
// Arrange
- var reporter = new Reporter(100, BarDescriptor.Default.Build());
+ var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build());
// Act
var action = () => reporter.Resume();
@@ -85,7 +86,7 @@ public void GivenOperationNotStarted_WhenResuming_ThenThrowsException()
public void GivenOperationNotStopped_WhenResuming_ThenThrowsException()
{
// Arrange
- using var reporter = new Reporter(100, BarDescriptor.Default.Build());
+ using var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build());
reporter.Start();
// Act
@@ -99,7 +100,7 @@ public void GivenOperationNotStopped_WhenResuming_ThenThrowsException()
public void GivenStartedOperation_WhenStopping_ThenSuccess()
{
// Arrange
- var reporter = new Reporter(100, BarDescriptor.Default.Build());
+ var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build());
reporter.Start();
// Act
@@ -110,7 +111,7 @@ public void GivenStartedOperation_WhenStopping_ThenSuccess()
public void GivenStoppedOperation_WhenResuming_ThenSuccess()
{
// Arrange
- var reporter = new Reporter(100, BarDescriptor.Default.Build());
+ var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build());
reporter.Start();
reporter.Stop();
@@ -123,7 +124,7 @@ public async Task GivenProgressNotifications_WhenRunning_ThenCallbackIsCalled()
{
// Arrange
bool isCalled = false;
- var reporter = new Reporter(100, BarDescriptor.Default.Build())
+ var reporter = new ConsoleReporter(100, BarDescriptor.Default.Build())
{
OnProgress = (stats) => isCalled = true
};
@@ -145,7 +146,7 @@ public async Task GivenCompletionNotifications_WhenFinished_ThenCallbackIsCalled
{
// Arrange
bool isCalled = false;
- var reporter = new Reporter(1, BarDescriptor.Default.Build())
+ var reporter = new ConsoleReporter(1, BarDescriptor.Default.Build())
{
OnCompletion = (stats) => isCalled = true
};
diff --git a/src/Progress.sln b/src/Progress.sln
index 0c7d039..07a6545 100644
--- a/src/Progress.sln
+++ b/src/Progress.sln
@@ -7,18 +7,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress", "Progress\Progre
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Bar.App", "Progress.Samples.Bar.App\Progress.Samples.Bar.App.csproj", "{256B943E-F24D-44C8-A667-34F025A60AC7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Bar.App", "Samples\Progress.Samples.Bar.App\Progress.Samples.Bar.App.csproj", "{256B943E-F24D-44C8-A667-34F025A60AC7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples", "Progress.Samples\Progress.Samples.csproj", "{FEDB17DF-27B4-407C-A225-0DBAA1157715}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples", "Samples\Progress.Samples\Progress.Samples.csproj", "{FEDB17DF-27B4-407C-A225-0DBAA1157715}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Spinner.App", "Progress.Samples.Spinner.App\Progress.Samples.Spinner.App.csproj", "{BDD1AF4C-9905-4D5F-9020-07CDE449E7F7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Spinner.App", "Samples\Progress.Samples.Spinner.App\Progress.Samples.Spinner.App.csproj", "{BDD1AF4C-9905-4D5F-9020-07CDE449E7F7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Pulse.App", "Progress.Samples.Pulse.App\Progress.Samples.Pulse.App.csproj", "{8B3E0D5B-ABBB-45D6-B0BA-25EDB15D2502}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Pulse.App", "Samples\Progress.Samples.Pulse.App\Progress.Samples.Pulse.App.csproj", "{8B3E0D5B-ABBB-45D6-B0BA-25EDB15D2502}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.HearthBeat.App", "Progress.Samples.HearthBeat.App\Progress.Samples.HearthBeat.App.csproj", "{8DEBB035-B737-4C7D-9706-400914D06FC3}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.HearthBeat.App", "Samples\Progress.Samples.HearthBeat.App\Progress.Samples.HearthBeat.App.csproj", "{8DEBB035-B737-4C7D-9706-400914D06FC3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.UnitTest", "Progress.UnitTest\Progress.UnitTest.csproj", "{4ACE65FC-B0A8-45E8-9A46-99DD8E5AA447}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Progress.Samples.Background.Api", "Samples\Progress.Samples.Background.Api\Progress.Samples.Background.Api.csproj", "{DDFD6BC0-2650-4289-81AD-23B2AF96C405}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{45A524E0-71BD-4A1A-8720-80D36E0F5630}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -53,6 +57,10 @@ Global
{4ACE65FC-B0A8-45E8-9A46-99DD8E5AA447}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4ACE65FC-B0A8-45E8-9A46-99DD8E5AA447}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4ACE65FC-B0A8-45E8-9A46-99DD8E5AA447}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DDFD6BC0-2650-4289-81AD-23B2AF96C405}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DDFD6BC0-2650-4289-81AD-23B2AF96C405}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DDFD6BC0-2650-4289-81AD-23B2AF96C405}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DDFD6BC0-2650-4289-81AD-23B2AF96C405}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -63,6 +71,8 @@ Global
{BDD1AF4C-9905-4D5F-9020-07CDE449E7F7} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{8B3E0D5B-ABBB-45D6-B0BA-25EDB15D2502} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{8DEBB035-B737-4C7D-9706-400914D06FC3} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {4ACE65FC-B0A8-45E8-9A46-99DD8E5AA447} = {45A524E0-71BD-4A1A-8720-80D36E0F5630}
+ {DDFD6BC0-2650-4289-81AD-23B2AF96C405} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D9F7C575-D4A4-4256-97B8-29638AC42A70}
diff --git a/src/Progress/Builders/BackgroundReporterBuilder.cs b/src/Progress/Builders/BackgroundReporterBuilder.cs
new file mode 100644
index 0000000..a8d0b00
--- /dev/null
+++ b/src/Progress/Builders/BackgroundReporterBuilder.cs
@@ -0,0 +1,88 @@
+using Progress.Reporters;
+using Progress.Settings;
+
+namespace Progress.Builders;
+
+///
+/// Builder for helping to set up the background reporter with the desired behavior.
+///
+public class BackgroundReporterBuilder
+{
+ private TimeSpan _statsFrequency = TimeSpan.FromSeconds(5);
+ private ExportSettings _exportSettings = default!;
+ private Action _onProgressNotified = default!;
+ private Action _onCompletionNotified = default!;
+
+ ///
+ /// Sets the progress notification callback.
+ /// Default notification frequency is set to 5 seconds.
+ ///
+ ///
+ ///
+ public BackgroundReporterBuilder NotifyingProgress(Action callback)
+ {
+ return NotifyingProgress(callback, _statsFrequency);
+ }
+
+ ///
+ /// Sets the progress notification callback with the invocation frequency.
+ ///
+ ///
+ ///
+ ///
+ public BackgroundReporterBuilder NotifyingProgress(Action callback, TimeSpan statsFrequency)
+ {
+ _onProgressNotified = callback;
+ _statsFrequency = statsFrequency;
+ return this;
+ }
+
+ ///
+ /// Sets the completion notification callback.
+ ///
+ ///
+ ///
+ public BackgroundReporterBuilder NotifyingCompletion(Action callback)
+ {
+ _onCompletionNotified = callback;
+ return this;
+ }
+
+ ///
+ /// Sets and tells the reporter how and where to export the final stats.
+ ///
+ ///
+ ///
+ ///
+ public BackgroundReporterBuilder ExportingTo(string fileName, FileType fileType)
+ {
+ _exportSettings = new ExportSettings(fileName, fileType);
+ return this;
+ }
+
+ ///
+ /// Builds the reporter getting an instance of .
+ ///
+ ///
+ ///
+ ///
+ public BackgroundReporter Build(ulong itemsCount)
+ {
+ if (itemsCount == 0)
+ throw new ArgumentException("Nothing to do! Set the initial items count for completion.");
+
+ var reporter = new BackgroundReporter(itemsCount)
+ {
+ OnProgress = _onProgressNotified,
+ OnCompletion = _onCompletionNotified
+ };
+
+ reporter.Configuration.StatsFrequency = _statsFrequency;
+ reporter.Configuration.ExportSettings = _exportSettings;
+ reporter.Configuration.Options.NotifyProgressStats = _onProgressNotified != null;
+ reporter.Configuration.Options.NotifyCompletionStats = _onCompletionNotified != null;
+ reporter.Configuration.Options.ExportCompletionStats = _exportSettings != null;
+
+ return reporter;
+ }
+}
diff --git a/src/Progress/ReporterBuilder.cs b/src/Progress/Builders/ConsoleReporterBuilder.cs
similarity index 77%
rename from src/Progress/ReporterBuilder.cs
rename to src/Progress/Builders/ConsoleReporterBuilder.cs
index 392dbd4..ce1b583 100644
--- a/src/Progress/ReporterBuilder.cs
+++ b/src/Progress/Builders/ConsoleReporterBuilder.cs
@@ -1,13 +1,14 @@
using Progress.Descriptors;
+using Progress.Reporters;
using Progress.Settings;
-namespace Progress;
+namespace Progress.Builders;
///
-/// Builder for helping to set up the reported with the desired behavior.
-/// It will create an instance of using a by default.
+/// Builder for helping to set up the console reporter with the desired behavior.
+/// It will create an instance of using a by default.
///
-public class ReporterBuilder
+public class ConsoleReporterBuilder
{
private bool _displayRemainingTime;
private bool _displayEstTimeOfArrival;
@@ -26,7 +27,7 @@ public class ReporterBuilder
/// The reporter will display the elapsed time since the start.
///
///
- public ReporterBuilder DisplayingElapsedTime()
+ public ConsoleReporterBuilder DisplayingElapsedTime()
{
_displayElapsedTime = true;
return this;
@@ -36,7 +37,7 @@ public ReporterBuilder DisplayingElapsedTime()
/// The reporter will display the remaining time to finish.
///
///
- public ReporterBuilder DisplayingRemainingTime()
+ public ConsoleReporterBuilder DisplayingRemainingTime()
{
_displayRemainingTime = true;
return this;
@@ -46,7 +47,7 @@ public ReporterBuilder DisplayingRemainingTime()
/// The reporter will display when the operation is expected to finish.
///
///
- public ReporterBuilder DisplayingTimeOfArrival()
+ public ConsoleReporterBuilder DisplayingTimeOfArrival()
{
_displayEstTimeOfArrival = true;
return this;
@@ -56,7 +57,7 @@ public ReporterBuilder DisplayingTimeOfArrival()
/// The reporter will display when the operation started.
///
///
- public ReporterBuilder DisplayingStartingTime()
+ public ConsoleReporterBuilder DisplayingStartingTime()
{
_displayStartingTime = true;
return this;
@@ -66,7 +67,7 @@ public ReporterBuilder DisplayingStartingTime()
/// The rerporter will display the total of items processed.
///
///
- public ReporterBuilder DisplayingItemsOverview()
+ public ConsoleReporterBuilder DisplayingItemsOverview()
{
_displayItemsOverview = true;
return this;
@@ -76,7 +77,7 @@ public ReporterBuilder DisplayingItemsOverview()
/// The reporter will display the amount of success and failures.
///
///
- public ReporterBuilder DisplayingItemsSummary()
+ public ConsoleReporterBuilder DisplayingItemsSummary()
{
_displayItemsSummary = true;
return this;
@@ -88,7 +89,7 @@ public ReporterBuilder DisplayingItemsSummary()
///
///
///
- public ReporterBuilder UsingReportingFrequency(TimeSpan frequency)
+ public ConsoleReporterBuilder UsingReportingFrequency(TimeSpan frequency)
{
_reportFrequency = frequency;
return this;
@@ -99,7 +100,7 @@ public ReporterBuilder UsingReportingFrequency(TimeSpan frequency)
///
///
///
- public ReporterBuilder UsingComponentDescriptor(ComponentDescriptor descriptor)
+ public ConsoleReporterBuilder UsingComponentDescriptor(ComponentDescriptor descriptor)
{
_componentDescriptor = descriptor;
return this;
@@ -111,7 +112,7 @@ public ReporterBuilder UsingComponentDescriptor(ComponentDescriptor descriptor)
///
///
///
- public ReporterBuilder NotifyingProgress(Action callback)
+ public ConsoleReporterBuilder NotifyingProgress(Action callback)
{
return NotifyingProgress(callback, _statsFrequency);
}
@@ -122,7 +123,7 @@ public ReporterBuilder NotifyingProgress(Action callback)
///
///
///
- public ReporterBuilder NotifyingProgress(Action callback, TimeSpan statsFrequency)
+ public ConsoleReporterBuilder NotifyingProgress(Action callback, TimeSpan statsFrequency)
{
_onProgressNotified = callback;
_statsFrequency = statsFrequency;
@@ -134,7 +135,7 @@ public ReporterBuilder NotifyingProgress(Action callback, TimeSpan statsF
///
///
///
- public ReporterBuilder NotifyingCompletion(Action callback)
+ public ConsoleReporterBuilder NotifyingCompletion(Action callback)
{
_onCompletionNotified = callback;
return this;
@@ -146,26 +147,26 @@ public ReporterBuilder NotifyingCompletion(Action callback)
///
///
///
- public ReporterBuilder ExportingTo(string fileName, FileType fileType)
+ public ConsoleReporterBuilder ExportingTo(string fileName, FileType fileType)
{
_exportSettings = new ExportSettings(fileName, fileType);
return this;
}
///
- /// Builds the reporte getting an instance of .
+ /// Builds the reporter getting an instance of .
///
///
///
///
- public Reporter Build(ulong itemsCount)
+ public ConsoleReporter Build(ulong itemsCount)
{
if (itemsCount == 0)
throw new ArgumentException("Nothing to do! Set the initial items count for completion.");
var component = _componentDescriptor.Build();
- var reporter = new Reporter(itemsCount, component)
+ var reporter = new ConsoleReporter(itemsCount, component)
{
OnProgress = _onProgressNotified,
OnCompletion = _onCompletionNotified
diff --git a/src/Progress/Components/Component.cs b/src/Progress/Components/Component.cs
index 5d53f5d..8d1d336 100644
--- a/src/Progress/Components/Component.cs
+++ b/src/Progress/Components/Component.cs
@@ -10,7 +10,7 @@ internal abstract class Component
public abstract Component Next(ulong availableItems, ulong currentCount);
- protected static Percent Calculate(ulong availableItems, ulong currentCount) => new(availableItems, currentCount);
+ public static Percent Calculate(ulong availableItems, ulong currentCount) => new(availableItems, currentCount);
internal class Percent
{
diff --git a/src/Progress/Content/README.md b/src/Progress/Content/README.md
index 29166be..c9bec2d 100644
--- a/src/Progress/Content/README.md
+++ b/src/Progress/Content/README.md
@@ -1,12 +1,13 @@
# Progress
-Report progression with ease by using multilple components such as Bars, Spinners, Pulse and more
+This library helps you to spin up reporters for giving an overview of the progression of a given operation. These reporters can either be for console apps that output the information or background jobs hosted by APIs handling the progress via hooks.
## Report progress for console apps
+Report progression with ease by using multilple components such as Bars, Spinners, Pulse and more.
```csharp
-using var reporter = new ReporterBuilder()
+using var reporter = new ConsoleReporterBuilder()
.UsingReportingFrequency(TimeSpan.FromMilliseconds(50))
.UsingComponentDescriptor(BarDescriptor.Default)
.Build(Worker.AllItems);
@@ -22,6 +23,8 @@ await worker.DoMywork();
```
### Define the component to show progress
+Components are subjected to the ConsoleReporter.
+
```csharp
var descriptor = new BarDescriptor()
.UsingProgressSymbol('#')
@@ -36,7 +39,7 @@ var descriptor = BarDescriptor.Default;
### Define the reporter to use the component
```csharp
-var reporter = new ReporterBuilder()
+var reporter = new ConsoleReporterBuilder()
.DisplayingStartingTime()
.DisplayingElapsedTime()
.DisplayingTimeOfArrival()
@@ -51,6 +54,25 @@ var reporter = new ReporterBuilder()
.Build(Worker.AllItems);
```
+## Report progress for background jobs
+In case your workload happens in the background and you only pretend to collect progression status during certain moments of the execution, or export the results at the end, the BackgroundReporter may help you to remove all the boilerplate.
+
+```csharp
+_reporter = new BackgroundReporterBuilder()
+ .NotifyingProgress((stats) =>
+ {
+ logger.LogDebug("Getting stats on progress {percent}", stats.CurrentPercent);
+ })
+ .NotifyingCompletion((stats) =>
+ {
+ logger.LogDebug("Getting stats on completion");
+ })
+ .Build(Worker.AllItems);
+
+_worker.OnSuccess = () => _reporter.ReportSuccess();
+_worker.OnFailure = () => _reporter.ReportFailure();
+```
+
### Start the reporter
```csharp
reporter.Start();
@@ -84,7 +106,7 @@ var onCompletion = (Stats stats) =>
// TODO: Do something useful
};
-var reporter = new ReporterBuilder()
+var reporter = new ConsoleReporterBuilder()
.NotifyingProgress(onProgress)
.NotifyingCompletion(onCompletion)
.Build(Worker.AllItems);
@@ -93,7 +115,7 @@ var reporter = new ReporterBuilder()
### Exports final stats (json, csv, xml, txt)
```csharp
-var reporter = new ReporterBuilder()
+var reporter = new ConsoleReporterBuilder()
.ExportingTo("output.json", FileType.Json)
.Build(Worker.AllItems);
-```
+```
\ No newline at end of file
diff --git a/src/Progress/Exporter.cs b/src/Progress/Exporter.cs
index 7bd9b5b..659bcde 100644
--- a/src/Progress/Exporter.cs
+++ b/src/Progress/Exporter.cs
@@ -10,7 +10,13 @@ namespace Progress;
internal class Exporter(ExportSettings settings)
{
private readonly ExportSettings _settings = settings;
- private readonly IEnumerable _exporters = [ new CsvExporter(), new TextExporter(), new JsonExporter(), new XmlExporter() ];
+ private readonly IEnumerable _exporters =
+ [
+ new CsvExporter(),
+ new TextExporter(),
+ new JsonExporter(),
+ new XmlExporter()
+ ];
public void Export(Stats stats)
{
@@ -18,9 +24,13 @@ public void Export(Stats stats)
? File.OpenWrite(_settings.FileName)
: File.Create(_settings.FileName);
+ using StreamWriter writer = new(stream);
+
IContentExporter contentExporter = _exporters.FirstOrDefault(e => e.FileType == _settings.FileType) ?? throw new NotSupportedException("Not supported export type");
string content = contentExporter.Export(stats);
- byte[] result = Encoding.Default.GetBytes(content);
- stream.Write(result, 0, result.Length);
+ writer.Write(content);
+ stream.Flush(true);
+ writer.Close();
+ stream.Close();
}
}
diff --git a/src/Progress/Printer.cs b/src/Progress/Printer.cs
index d859abb..b247f45 100644
--- a/src/Progress/Printer.cs
+++ b/src/Progress/Printer.cs
@@ -1,5 +1,5 @@
using Progress.Components;
-using Progress.Settings;
+using Progress.Settings.Console;
using System.Text;
namespace Progress;
diff --git a/src/Progress/Progress.csproj b/src/Progress/Progress.csproj
index 78a594e..2f6ff24 100644
--- a/src/Progress/Progress.csproj
+++ b/src/Progress/Progress.csproj
@@ -9,16 +9,16 @@
Progress
- 1.4.0
+ 2.0.0
MIT
Gerard Castello
Report progress with ease
- Report progression with ease by using multilple components such as Bars, Spinners, Pulse and more
+ Report workload progression with ease by using multilple components such as Bars, Spinners, Pulse and more
Content/logo.png
Content/README.md
https://github.com/gcastellov/progress
- dotnet, report, progress, background, console
-
+ dotnet, report, workload, progress, background, console
+
True
diff --git a/src/Progress/Reporters/BackgroundReporter.cs b/src/Progress/Reporters/BackgroundReporter.cs
new file mode 100644
index 0000000..957c2b0
--- /dev/null
+++ b/src/Progress/Reporters/BackgroundReporter.cs
@@ -0,0 +1,149 @@
+using Progress.Components;
+using Progress.Settings.Background;
+
+namespace Progress.Reporters;
+
+///
+/// Reports background task's progress based on the settings provided.
+///
+public class BackgroundReporter
+{
+ private readonly ulong _itemsCount;
+ private readonly Configuration _configuration;
+
+ private ulong _successCount;
+ private ulong _failureCount;
+ private Timer _timer;
+ private Thread _statsThread = default!;
+ private CancellationTokenSource _cancellationTokenSource = default!;
+ private CancellationToken _cancellationToken;
+ private DateTimeOffset _lastStatsNotification;
+
+ ///
+ /// Inidicates whehter the task is completed or not.
+ ///
+ public bool IsFinished => CurrentCount == _itemsCount;
+
+ internal Configuration Configuration => _configuration;
+ internal Action? OnProgress { get; set; } = null!;
+ internal Action? OnCompletion { get; set; } = null!;
+
+ private ulong CurrentCount => _successCount + _failureCount;
+
+ internal BackgroundReporter(ulong itemsCount)
+ {
+ if (itemsCount == 0)
+ throw new ArgumentException($"Nothing to do!. {nameof(itemsCount)} must be greater than 0");
+
+ _itemsCount = itemsCount;
+ _timer = Timer.Start();
+ _configuration = new Configuration();
+ }
+
+ ///
+ /// Reportes success. By calling this method, the success counter increases.
+ ///
+ public void ReportSuccess() => Interlocked.Increment(ref _successCount);
+
+ ///
+ /// Reports failures. By calling this method, the failure counter increases.
+ ///
+ public void ReportFailure() => Interlocked.Increment(ref _failureCount);
+
+ ///
+ /// Starts a thread that reports the progression of the operation.
+ ///
+ public void Start()
+ {
+ _successCount = 0;
+ _failureCount = 0;
+ _lastStatsNotification = DateTimeOffset.UtcNow;
+ _timer = Timer.Start();
+ _cancellationTokenSource = new CancellationTokenSource();
+ _cancellationToken = _cancellationTokenSource.Token;
+ _statsThread = DoStats();
+ _statsThread.Start();
+ }
+
+ ///
+ /// Stops the thread that reports the progression of the operation.
+ ///
+ public void Stop()
+ {
+ if (_statsThread == null)
+ throw new InvalidOperationException($"First start the reporting by calling {nameof(Start)}");
+
+ if (_cancellationToken.CanBeCanceled)
+ _cancellationTokenSource.Cancel();
+
+ if (_statsThread != null && _statsThread.IsAlive)
+ _statsThread.Join();
+ }
+
+ private Thread DoStats()
+ {
+ var tStart = new ThreadStart(() =>
+ {
+ do
+ {
+ ReportStats();
+ Thread.Sleep(Configuration.StatsFrequency);
+ }
+ while (!IsFinished && !_cancellationToken.IsCancellationRequested);
+
+ if (IsFinished)
+ {
+ ReportCompletionStats();
+ Export();
+ }
+ });
+
+ return new(tStart);
+ }
+
+ private void ReportStats()
+ {
+ if (OnProgress == null || DateTimeOffset.UtcNow - _lastStatsNotification < Configuration.StatsFrequency)
+ return;
+
+ var stats = CollectStats();
+ OnProgress.Invoke(stats);
+ _lastStatsNotification = DateTimeOffset.UtcNow;
+ }
+
+ private void ReportCompletionStats()
+ {
+ if (OnCompletion == null)
+ return;
+
+ var stats = CollectStats();
+ OnCompletion.Invoke(stats);
+ }
+
+ private void Export()
+ {
+ if (Configuration.Options.ExportCompletionStats && Configuration.ExportSettings != null)
+ {
+ var stats = CollectStats();
+ new Exporter(Configuration.ExportSettings).Export(stats);
+ }
+ }
+
+ private Stats CollectStats()
+ {
+ var percent = Component.Calculate(_itemsCount, CurrentCount);
+
+ return new()
+ {
+ StartedOn = _timer.StartedOn,
+ ElapsedTime = _timer.ElapsedTime,
+ RemainingTime = _timer.GetRemainingTime(percent.Value),
+ EstTimeOfArrival = _timer.GetEstimatedTimeOfArrival(percent.Value),
+ ExpectedItems = _itemsCount,
+ CurrentCount = CurrentCount,
+ SuccessCount = _successCount,
+ FailureCount = _failureCount,
+ CurrentPercent = percent.Value,
+ };
+ }
+}
diff --git a/src/Progress/Reporter.cs b/src/Progress/Reporters/ConsoleReporter.cs
similarity index 93%
rename from src/Progress/Reporter.cs
rename to src/Progress/Reporters/ConsoleReporter.cs
index 9906f3a..83d45df 100644
--- a/src/Progress/Reporter.cs
+++ b/src/Progress/Reporters/ConsoleReporter.cs
@@ -1,13 +1,13 @@
using Progress.Components;
-using Progress.Settings;
+using Progress.Settings.Console;
using System.Text;
-namespace Progress;
+namespace Progress.Reporters;
///
-/// Reports background task completion based on the settings provided.
+/// Reports background task's progress to console based on the settings provided.
///
-public class Reporter : IDisposable
+public class ConsoleReporter : IDisposable
{
private readonly ulong _itemsCount;
private readonly Configuration _configuration;
@@ -36,7 +36,7 @@ public class Reporter : IDisposable
private ulong CurrentCount => _successCount + _failureCount;
- internal Reporter(ulong itemsCount, Component component)
+ internal ConsoleReporter(ulong itemsCount, Component component)
{
if (itemsCount == 0)
throw new ArgumentException($"Nothing to do!. {nameof(itemsCount)} must be greater than 0");
diff --git a/src/Progress/Settings/Background/Configuration.cs b/src/Progress/Settings/Background/Configuration.cs
new file mode 100644
index 0000000..f6b9f9c
--- /dev/null
+++ b/src/Progress/Settings/Background/Configuration.cs
@@ -0,0 +1,8 @@
+namespace Progress.Settings.Background;
+
+internal class Configuration
+{
+ public ReportingOptions Options { get; init; } = new();
+ public ExportSettings ExportSettings { get; set; } = default!;
+ public TimeSpan StatsFrequency { get; set; } = TimeSpan.FromSeconds(5);
+}
diff --git a/src/Progress/Settings/Background/ReportingOptions.cs b/src/Progress/Settings/Background/ReportingOptions.cs
new file mode 100644
index 0000000..475b2c9
--- /dev/null
+++ b/src/Progress/Settings/Background/ReportingOptions.cs
@@ -0,0 +1,8 @@
+namespace Progress.Settings.Background;
+
+internal class ReportingOptions
+{
+ internal bool NotifyProgressStats { get; set; } = false;
+ internal bool NotifyCompletionStats { get; set; } = false;
+ internal bool ExportCompletionStats { get; set; } = false;
+}
diff --git a/src/Progress/Settings/Configuration.cs b/src/Progress/Settings/Console/Configuration.cs
similarity index 86%
rename from src/Progress/Settings/Configuration.cs
rename to src/Progress/Settings/Console/Configuration.cs
index 0f4825b..45ceccb 100644
--- a/src/Progress/Settings/Configuration.cs
+++ b/src/Progress/Settings/Console/Configuration.cs
@@ -1,4 +1,4 @@
-namespace Progress.Settings;
+namespace Progress.Settings.Console;
internal class Configuration
{
diff --git a/src/Progress/Settings/ReportingOptions.cs b/src/Progress/Settings/Console/ReportingOptions.cs
similarity index 91%
rename from src/Progress/Settings/ReportingOptions.cs
rename to src/Progress/Settings/Console/ReportingOptions.cs
index 91a5a5b..dc9f457 100644
--- a/src/Progress/Settings/ReportingOptions.cs
+++ b/src/Progress/Settings/Console/ReportingOptions.cs
@@ -1,4 +1,4 @@
-namespace Progress.Settings;
+namespace Progress.Settings.Console;
internal class ReportingOptions
{
diff --git a/src/Samples/Progress.Samples.Background.Api/BackgroundJob.cs b/src/Samples/Progress.Samples.Background.Api/BackgroundJob.cs
new file mode 100644
index 0000000..81ff345
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/BackgroundJob.cs
@@ -0,0 +1,38 @@
+
+using Progress.Builders;
+
+namespace Progress.Samples.Background.Api;
+
+internal class BackgroundJob(ILogger logger) : BackgroundService
+{
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ var onProgress = (Stats stats) =>
+ {
+ // TODO: Do something useful
+ logger.LogDebug("Getting stats on progress {percent}", stats.CurrentPercent);
+ };
+
+ var onCompletion = (Stats stats) =>
+ {
+ // TODO: Do something useful
+ logger.LogDebug("Getting stats on completion");
+ };
+
+ var reporter = new BackgroundReporterBuilder()
+ .NotifyingProgress(onProgress, TimeSpan.FromSeconds(10))
+ .NotifyingCompletion(onCompletion)
+ .ExportingTo("output.json", Settings.FileType.Json)
+ .Build(Worker.AllItems);
+
+
+ var worker = new Worker()
+ {
+ OnSuccess = () => reporter.ReportSuccess(),
+ OnFailure = () => reporter.ReportFailure(),
+ };
+
+ reporter.Start();
+ await worker.DoMywork();
+ }
+}
diff --git a/src/Samples/Progress.Samples.Background.Api/HostedService.cs b/src/Samples/Progress.Samples.Background.Api/HostedService.cs
new file mode 100644
index 0000000..b1a0a06
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/HostedService.cs
@@ -0,0 +1,39 @@
+using Progress.Builders;
+using Progress.Reporters;
+
+namespace Progress.Samples.Background.Api;
+
+internal class HostedService : IHostedService
+{
+ private readonly Worker _worker = new();
+ private readonly BackgroundReporter _reporter;
+
+ public HostedService(ILogger logger)
+ {
+ _reporter = new BackgroundReporterBuilder()
+ .NotifyingProgress((stats) =>
+ {
+ logger.LogDebug("Getting stats on progress {percent}", stats.CurrentPercent);
+ })
+ .NotifyingCompletion((stats) =>
+ {
+ logger.LogDebug("Getting stats on completion");
+ })
+ .Build(Worker.AllItems);
+
+ _worker.OnSuccess = () => _reporter.ReportSuccess();
+ _worker.OnFailure = () => _reporter.ReportFailure();
+ }
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ _reporter.Start();
+ await _worker.DoMywork();
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ _reporter.Stop();
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/Samples/Progress.Samples.Background.Api/Program.cs b/src/Samples/Progress.Samples.Background.Api/Program.cs
new file mode 100644
index 0000000..0528485
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/Program.cs
@@ -0,0 +1,14 @@
+using Progress.Samples.Background.Api;
+using System.Net;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.Services.AddHostedService();
+builder.Services.AddHostedService();
+
+var app = builder.Build();
+app.MapGet("/info", (HttpContext ctx) =>
+{
+ ctx.Response.StatusCode = (int)HttpStatusCode.Accepted;
+});
+
+app.Run();
\ No newline at end of file
diff --git a/src/Samples/Progress.Samples.Background.Api/Progress.Samples.Background.Api.csproj b/src/Samples/Progress.Samples.Background.Api/Progress.Samples.Background.Api.csproj
new file mode 100644
index 0000000..8f87d85
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/Progress.Samples.Background.Api.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/src/Samples/Progress.Samples.Background.Api/Properties/launchSettings.json b/src/Samples/Progress.Samples.Background.Api/Properties/launchSettings.json
new file mode 100644
index 0000000..14e0ce1
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/Properties/launchSettings.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:13974",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "info",
+ "applicationUrl": "http://localhost:5041",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "info",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/src/Samples/Progress.Samples.Background.Api/appsettings.Development.json b/src/Samples/Progress.Samples.Background.Api/appsettings.Development.json
new file mode 100644
index 0000000..ff66ba6
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/src/Samples/Progress.Samples.Background.Api/appsettings.json b/src/Samples/Progress.Samples.Background.Api/appsettings.json
new file mode 100644
index 0000000..ef83c65
--- /dev/null
+++ b/src/Samples/Progress.Samples.Background.Api/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/Progress.Samples.Bar.App/Program.cs b/src/Samples/Progress.Samples.Bar.App/Program.cs
similarity index 88%
rename from src/Progress.Samples.Bar.App/Program.cs
rename to src/Samples/Progress.Samples.Bar.App/Program.cs
index a86fe9b..3149bbf 100644
--- a/src/Progress.Samples.Bar.App/Program.cs
+++ b/src/Samples/Progress.Samples.Bar.App/Program.cs
@@ -1,4 +1,5 @@
using Progress;
+using Progress.Builders;
using Progress.Descriptors;
using Progress.Samples;
using Progress.Settings;
@@ -13,7 +14,7 @@
// TODO: Do something useful
};
-using var reporter = new ReporterBuilder()
+using var reporter = new ConsoleReporterBuilder()
.DisplayingStartingTime()
.DisplayingElapsedTime()
.DisplayingTimeOfArrival()
diff --git a/src/Progress.Samples.Bar.App/Progress.Samples.Bar.App.csproj b/src/Samples/Progress.Samples.Bar.App/Progress.Samples.Bar.App.csproj
similarity index 81%
rename from src/Progress.Samples.Bar.App/Progress.Samples.Bar.App.csproj
rename to src/Samples/Progress.Samples.Bar.App/Progress.Samples.Bar.App.csproj
index 9fade77..713b647 100644
--- a/src/Progress.Samples.Bar.App/Progress.Samples.Bar.App.csproj
+++ b/src/Samples/Progress.Samples.Bar.App/Progress.Samples.Bar.App.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Progress.Samples.HearthBeat.App/Program.cs b/src/Samples/Progress.Samples.HearthBeat.App/Program.cs
similarity index 88%
rename from src/Progress.Samples.HearthBeat.App/Program.cs
rename to src/Samples/Progress.Samples.HearthBeat.App/Program.cs
index caff2cb..ec55aae 100644
--- a/src/Progress.Samples.HearthBeat.App/Program.cs
+++ b/src/Samples/Progress.Samples.HearthBeat.App/Program.cs
@@ -1,4 +1,5 @@
using Progress;
+using Progress.Builders;
using Progress.Descriptors;
using Progress.Samples;
using Progress.Settings;
@@ -13,7 +14,7 @@
// TODO: Do something useful
};
-using var reporter = new ReporterBuilder()
+using var reporter = new ConsoleReporterBuilder()
.DisplayingStartingTime()
.DisplayingElapsedTime()
.DisplayingTimeOfArrival()
diff --git a/src/Progress.Samples.HearthBeat.App/Progress.Samples.HearthBeat.App.csproj b/src/Samples/Progress.Samples.HearthBeat.App/Progress.Samples.HearthBeat.App.csproj
similarity index 81%
rename from src/Progress.Samples.HearthBeat.App/Progress.Samples.HearthBeat.App.csproj
rename to src/Samples/Progress.Samples.HearthBeat.App/Progress.Samples.HearthBeat.App.csproj
index 9fade77..713b647 100644
--- a/src/Progress.Samples.HearthBeat.App/Progress.Samples.HearthBeat.App.csproj
+++ b/src/Samples/Progress.Samples.HearthBeat.App/Progress.Samples.HearthBeat.App.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Progress.Samples.Pulse.App/Program.cs b/src/Samples/Progress.Samples.Pulse.App/Program.cs
similarity index 88%
rename from src/Progress.Samples.Pulse.App/Program.cs
rename to src/Samples/Progress.Samples.Pulse.App/Program.cs
index 20b1d64..acdf5cc 100644
--- a/src/Progress.Samples.Pulse.App/Program.cs
+++ b/src/Samples/Progress.Samples.Pulse.App/Program.cs
@@ -1,4 +1,5 @@
using Progress;
+using Progress.Builders;
using Progress.Descriptors;
using Progress.Samples;
using Progress.Settings;
@@ -14,7 +15,7 @@
};
-using var reporter = new ReporterBuilder()
+using var reporter = new ConsoleReporterBuilder()
.DisplayingStartingTime()
.DisplayingElapsedTime()
.DisplayingTimeOfArrival()
diff --git a/src/Progress.Samples.Pulse.App/Progress.Samples.Pulse.App.csproj b/src/Samples/Progress.Samples.Pulse.App/Progress.Samples.Pulse.App.csproj
similarity index 81%
rename from src/Progress.Samples.Pulse.App/Progress.Samples.Pulse.App.csproj
rename to src/Samples/Progress.Samples.Pulse.App/Progress.Samples.Pulse.App.csproj
index 9fade77..713b647 100644
--- a/src/Progress.Samples.Pulse.App/Progress.Samples.Pulse.App.csproj
+++ b/src/Samples/Progress.Samples.Pulse.App/Progress.Samples.Pulse.App.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Progress.Samples.Spinner.App/Program.cs b/src/Samples/Progress.Samples.Spinner.App/Program.cs
similarity index 81%
rename from src/Progress.Samples.Spinner.App/Program.cs
rename to src/Samples/Progress.Samples.Spinner.App/Program.cs
index 6879109..00cb6b1 100644
--- a/src/Progress.Samples.Spinner.App/Program.cs
+++ b/src/Samples/Progress.Samples.Spinner.App/Program.cs
@@ -1,6 +1,8 @@
using Progress;
+using Progress.Builders;
using Progress.Descriptors;
using Progress.Samples;
+using Progress.Settings;
var onProgress = (Stats stats) =>
{
@@ -13,7 +15,7 @@
};
-using var reporter = new ReporterBuilder()
+using var reporter = new ConsoleReporterBuilder()
.DisplayingStartingTime()
.DisplayingElapsedTime()
.DisplayingTimeOfArrival()
@@ -22,7 +24,7 @@
.DisplayingItemsOverview()
.NotifyingProgress(onProgress)
.NotifyingCompletion(onCompletion)
- .ExportingTo("output.xml", Progress.Settings.FileType.Xml)
+ .ExportingTo("output.xml", FileType.Xml)
.UsingReportingFrequency(TimeSpan.FromMilliseconds(50))
.UsingComponentDescriptor(SpinnerDescriptor.Default)
.Build(Worker.AllItems);
diff --git a/src/Progress.Samples.Spinner.App/Progress.Samples.Spinner.App.csproj b/src/Samples/Progress.Samples.Spinner.App/Progress.Samples.Spinner.App.csproj
similarity index 81%
rename from src/Progress.Samples.Spinner.App/Progress.Samples.Spinner.App.csproj
rename to src/Samples/Progress.Samples.Spinner.App/Progress.Samples.Spinner.App.csproj
index 9fade77..713b647 100644
--- a/src/Progress.Samples.Spinner.App/Progress.Samples.Spinner.App.csproj
+++ b/src/Samples/Progress.Samples.Spinner.App/Progress.Samples.Spinner.App.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Progress.Samples/Progress.Samples.csproj b/src/Samples/Progress.Samples/Progress.Samples.csproj
similarity index 100%
rename from src/Progress.Samples/Progress.Samples.csproj
rename to src/Samples/Progress.Samples/Progress.Samples.csproj
diff --git a/src/Progress.Samples/Worker.cs b/src/Samples/Progress.Samples/Worker.cs
similarity index 100%
rename from src/Progress.Samples/Worker.cs
rename to src/Samples/Progress.Samples/Worker.cs