SetNet.Streams 1.2.0

dotnet add package SetNet.Streams --version 1.2.0
                    
NuGet\Install-Package SetNet.Streams -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SetNet.Streams" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SetNet.Streams" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="SetNet.Streams" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SetNet.Streams --version 1.2.0
                    
#r "nuget: SetNet.Streams, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SetNet.Streams@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SetNet.Streams&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=SetNet.Streams&version=1.2.0
                    
Install as a Cake Tool

<p align="center"> <img src="https://raw.githubusercontent.com/Povstalez/SetNet/master/assets/icon.png" alt="SetNet" width="96"> </p>

SetNet.Streams

Large-payload streaming for SetNet: patches, avatars, replays — offered, chunked, resumable.

Regular messages are for kilobytes; this package is for the megabytes. A transfer starts with an offer (name + size) the receiver can accept or reject, then flows as sequential chunks into a pluggable sink (memory or file), with progress on the sender and resume after a dropped connection — an interrupted upload retried with the same id re-sends only the missing tail. Works in both directions (client → server uploads, server → client pushes). Added by composition — no base class.

Install

dotnet add package SetNet
dotnet add package SetNet.Streams

Usage

Call StreamsRuntime.Enable() once at startup on both ends (before handler discovery).

Server — receive uploads:

StreamsRuntime.Enable();
var streams = server.UseStreams();

streams.Received += (peer, s) =>
{
    var bytes = ((MemoryStreamSink)s.Sink).ToArray();
    Console.WriteLine($"{peer.CurrentPeerInfo.Id} sent '{s.Name}' ({s.Length} B)");
};

Client — upload with progress and resume:

StreamsRuntime.Enable();
var streams = client.UseStreams();

var progress = new Progress<double>(p => DrawBar(p));
try
{
    await streams.SendAsync("replay.dat", File.OpenRead("replay.dat"), progress);
}
catch (StreamsException ex)          // connection dropped mid-upload
{
    await client.ConnectAsync();
    await streams.SendAsync("replay.dat", File.OpenRead("replay.dat"), progress,
                            streamId: ex.StreamId);   // resumes — only the tail is re-sent
}

Large / sensitive offers — decide per offer, stream to disk:

streams.OfferReceived += async offer =>
{
    if (offer.Length > 1_000_000_000) { await offer.RejectAsync("Too big."); return; }
    await offer.AcceptAsync(new FileStreamSink($"incoming/{offer.StreamId}.bin"));
};

Server → client works the same: await streams.SendAsync(peer, "map.pak", content).

API

Member Purpose
server.UseStreams(StreamsOptions?) → StreamsServer hub: SendAsync(peer, ...) + OfferReceived/Received events (per peer)
client.UseStreams(StreamsOptions?) → StreamsClient driver: SendAsync(...) + OfferReceived/Received events
SendAsync(name, Stream/byte[], IProgress<double>?, Guid? streamId, ct) offer + chunked upload; returns the transfer id; same id ⇒ resume
IncomingStreamOffer.AcceptAsync(IStreamSink?) / RejectAsync(reason) per-offer decision (default sink = memory)
IStreamSink / MemoryStreamSink / FileStreamSink where the bytes go
StreamsOptions AutoAccept (default on, ≤ MaxAutoAcceptBytes 64 MB), ChunkSize (64 KB), OfferTimeoutMs, PartialTtlSeconds
StreamsRuntime.Enable() one-time bootstrap so the handlers are discovered

Notes

  • Reserved wire types 65492 / 65493. Don't reuse them.
  • Needs a reliable, ordered path. Chunks are validated to be exactly contiguous; run over TCP / WebSockets / UDP-reliable. Over reliable UDP set ChunkSize ≈ 1 KB (datagram limit); over TCP keep it well under Configuration.MaxMessageSize.
  • Resume is receiver-driven. The receiver keeps interrupted partials for PartialTtlSeconds keyed by stream id; the accept reply tells the sender where to continue. Use a FileStreamSink for partials that must survive a receiver restart.
  • Back-pressure. Chunks are awaited one at a time through the normal send path, so MaxInFlightMessages/SendTimeoutMs apply; a stream saturates the connection while active — pair with SetNet.Multiplex to keep latency-critical traffic on its own dispatch lane.
  • Trust. An offer's size cap is enforced (MaxAutoAcceptBytes, overrun checks), but accept-all-from-anyone is still a storage giveaway — gate with SetNet.Auth and decide in OfferReceived for anything user-generated.

Documentation & source

License

MIT

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 147 8/5/2026