https://github.com/rainxh11/sakontstack.reactivestream
a Stream wrapper that provides read / write progress reporting through IProgress<StreamProgress> and an IObservable<StreamProgress>
https://github.com/rainxh11/sakontstack.reactivestream
csharp dotnet limit observable progress reactive reactiveextensions stream throttle
Last synced: 2 months ago
JSON representation
a Stream wrapper that provides read / write progress reporting through IProgress<StreamProgress> and an IObservable<StreamProgress>
- Host: GitHub
- URL: https://github.com/rainxh11/sakontstack.reactivestream
- Owner: rainxh11
- License: mit
- Created: 2023-08-19T15:58:35.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2023-08-19T20:22:42.000Z (almost 3 years ago)
- Last Synced: 2025-12-31T08:42:49.429Z (6 months ago)
- Topics: csharp, dotnet, limit, observable, progress, reactive, reactiveextensions, stream, throttle
- Language: C#
- Homepage:
- Size: 13.7 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Reactive Stream
a `Stream` wrapper that provides Read/Write progress reporting through `IProgress` and `IObservable`
with speed throttling for Read/Write streams separately.
| Version | Downloads |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| [](https://www.nuget.org/packages/SakontStack.ReactiveStream/) |  |
## Example Usage:
### Report file download progress:
- progress using `IProgress`
```csharp
using System.Reactive.Linq;
using SakontStack.ReactiveStream;
using ByteSizeLib;
var fileLink = new Uri(@"https://releases.ubuntu.com/jammy/ubuntu-22.04.3-desktop-amd64.iso");
var client = new HttpClient();
var response = await client.GetAsync(fileLink, HttpCompletionOption.ResponseHeadersRead);
var length = long.Parse(response.Content.Headers
.First(h => h.Key.Equals("Content-Length"))
.Value
.First());
var progress = new Progress(p => Console
.WriteLine($"Downloaded {ByteSize.FromBytes(p.Bytes).ToBinaryString()}" +
$"/{ByteSize.FromBytes(p.TotalBytes ?? 0).ToBinaryString()} " +
$"({p.Percentage:N2}%) " +
$"{ByteSize.FromBytes(p.BytesPerSecond).ToBinaryString()}/sec"));
var stream = new ReactiveStream(new MemoryStream(), progress: progress, totalLength: length);
// stream progress will only start reporting progress after you subscribe to it
stream.Subscribe();
await response.Content.CopyToAsync(stream);
```
_**NOTE:**_ _setting custom report interval while using `IProgress` alone, requires using `stream.Sample()` operator._
- progress using `IObservable`
```csharp
using System.Reactive.Linq;
using SakontStack.ReactiveStream;
using ByteSizeLib;
var fileLink = new Uri(@"https://releases.ubuntu.com/jammy/ubuntu-22.04.3-desktop-amd64.iso");
var client = new HttpClient();
var response = await client.GetAsync(fileLink, HttpCompletionOption.ResponseHeadersRead);
var length = long.Parse(response.Content.Headers
.First(h => h.Key.Equals("Content-Length"))
.Value
.First());
var stream = new ReactiveStream(new MemoryStream(), totalLength: length);
stream
.Sample(TimeSpan.FromSeconds(0.25)) // Only report progress each 0.25 seconds
.Do(p => Console
.WriteLine($"Downloaded {ByteSize.FromBytes(p.Bytes).ToBinaryString()}"+
$"/{ByteSize.FromBytes(p.TotalBytes ?? 0).ToBinaryString()}"+
$"({p.Percentage:N2}%) "+
$"{ByteSize.FromBytes(p.BytesPerSecond).ToBinaryString()}/sec"))
.Subscribe();
await response.Content.CopyToAsync(stream);
```
- setting download speed limits:
```csharp
using System.Reactive.Linq;
using SakontStack.ReactiveStream;
using ByteSizeLib;
var fileLink = new Uri(@"https://releases.ubuntu.com/jammy/ubuntu-22.04.3-desktop-amd64.iso");
var client = new HttpClient();
var response = await client.GetAsync(fileLink, HttpCompletionOption.ResponseHeadersRead);
var length = long.Parse(response.Content.Headers
.First(h => h.Key.Equals("Content-Length"))
.Value
.First());
var stream = new ReactiveStream(new MemoryStream(), totalLength: length,
configureStream: s =>
{
// 1 MB/sec speed limit for write streams;
s.WriteSpeedLimit = 1024 * 1024;
});
stream
.Sample(TimeSpan.FromSeconds(0.25)) // Only report progress each 0.25 seconds
.Do(p => Console
.WriteLine($"Downloaded {ByteSize.FromBytes(p.Bytes).ToBinaryString()}"+
$"/{ByteSize.FromBytes(p.TotalBytes ?? 0).ToBinaryString()}"+
$"({p.Percentage:N2}%) "+
$"{ByteSize.FromBytes(p.BytesPerSecond).ToBinaryString()}/sec"))
.Subscribe();
await response.Content.CopyToAsync(stream);
```
- changing speed limits in realtime:
```csharp
stream.ModifyOptions(x => x.WriteSpeedLimit = null);
```
**[`ByteSizeLib`](https://www.nuget.org/packages/ByteSize) library is not a dependency, and only used in this example to provide sample codes that will print progress with better formatted byte sizes**
_example output:_
```powershell
...
Downloaded 4.7 MiB/4.69 GiB (0.10%) 680 KiB/sec
Downloaded 5.03 MiB/4.69 GiB (0.10%) 1016 KiB/sec
Downloaded 5.04 MiB/4.69 GiB (0.10%) 1 MiB/sec
Downloaded 5.36 MiB/4.69 GiB (0.11%) 328 KiB/sec
Downloaded 5.7 MiB/4.69 GiB (0.12%) 680 KiB/sec
```
## API:
the `ReactiveStream` class implements both `Stream` & `IObservable`
```csharp
public class ReactiveStream : Stream, IObservable
{
//* ... *//
}
```