SpawnDev.WebTorrent.Server.HuggingFace
3.2.3
See the version list below for details.
dotnet add package SpawnDev.WebTorrent.Server.HuggingFace --version 3.2.3
NuGet\Install-Package SpawnDev.WebTorrent.Server.HuggingFace -Version 3.2.3
<PackageReference Include="SpawnDev.WebTorrent.Server.HuggingFace" Version="3.2.3" />
<PackageVersion Include="SpawnDev.WebTorrent.Server.HuggingFace" Version="3.2.3" />
<PackageReference Include="SpawnDev.WebTorrent.Server.HuggingFace" />
paket add SpawnDev.WebTorrent.Server.HuggingFace --version 3.2.3
#r "nuget: SpawnDev.WebTorrent.Server.HuggingFace, 3.2.3"
#:package SpawnDev.WebTorrent.Server.HuggingFace@3.2.3
#addin nuget:?package=SpawnDev.WebTorrent.Server.HuggingFace&version=3.2.3
#tool nuget:?package=SpawnDev.WebTorrent.Server.HuggingFace&version=3.2.3
SpawnDev.WebTorrent.Server.HuggingFace
Optional HuggingFace CDN proxy extension for SpawnDev.WebTorrent.Server. Fetches model files from HuggingFace's CDN on demand, caches them locally, generates SHA-256 .torrent files, and serves the cached bytes as a BEP 17/19 web seed. Browser clients hold the .torrent in memory and stream pieces from the local cache via WebRTC peers AND the HTTP web seed in the same swarm.
SpawnDev.WebTorrent.Server works without this extension — MapHuggingFaceProxy is opt-in.
Why this exists
AI models are big. CDNs scale poorly when every browser tab independently downloads the same 2 GB safetensors shard. SpawnDev's pattern: one cache server (this proxy) sits in front of HuggingFace, hashes everything once at SHA-256 piece level, and exposes both an HTTP range-request fallback (web seed) and a magnet URI (P2P seed). Every browser that loads the model becomes a peer for the next.
The hub.spawndev.com deployment runs this proxy in production for the SpawnDev model fleet.
Install
<PackageReference Include="SpawnDev.WebTorrent.Server.HuggingFace" Version="3.2.0" />
Pulls in SpawnDev.WebTorrent.Server 3.2.0 + SpawnDev.WebTorrent 3.2.0 transitively.
Quick start
using SpawnDev.WebTorrent.Server.HuggingFace;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var proxy = new HuggingFaceProxy(new HuggingFaceProxyOptions
{
CacheDirectory = "hf-cache", // single dir (or use CacheDirectories for multi)
TrackerUrls = new[] { "wss://your-tracker.example/announce" },
MinFreeDiskSpaceBytes = 2L * 1024 * 1024 * 1024, // keep 2 GB headroom (default)
});
app.MapHuggingFaceProxy(proxy);
app.Run();
Endpoints
The extension wires five MapGet routes under your ASP.NET Core app:
| Route | Purpose |
|---|---|
GET /model/{org}/{repo}/{filePath} |
Non-blocking: returns the .torrent if the file is already cached, else falls through to the HuggingFace CDN. Use as the primary URL clients hit — caching happens in the background. |
GET /torrent/{org}/{repo}/{filePath} |
Returns a fully-formed .torrent (SHA-256 piece hashes, web seed pre-populated). 404 if not yet cached. |
GET /magnet/{org}/{repo}/{filePath} |
Returns a magnet URI with xt=urn:btih: (and xt=urn:btmh: for v2 / hybrid torrents) plus xs= (exact source) and ws= (web seed) parameters. |
GET /hf/{org}/{repo}/{filePath} |
The web seed endpoint itself. Serves cached bytes with HTTP range request support; this is what mainline / desktop clients dial when they're using BEP 17/19. |
GET /hf-stats |
JSON with per-model request counts and cache usage. |
Path style mirrors HuggingFace's own URL shape: org/repo/path/to/file.safetensors.
Options (HuggingFaceProxyOptions)
| Option | Type | Default | Description |
|---|---|---|---|
CacheDirectories |
string[] |
["hf-cache"] |
Cache dirs to spread storage across drives. The proxy picks the first dir with sufficient free space. |
CacheDirectory |
string |
"hf-cache" |
Convenience setter for the single-directory case (sets CacheDirectories[0]). |
TrackerUrls |
string[] |
["wss://hub.spawndev.com:44365/announce"] |
Trackers baked into every generated .torrent. Replace with your own deployment. |
MaxCacheSizeBytes |
long |
0 (no limit) |
Hard ceiling across all cache directories. Combine with MinFreeDiskSpaceBytes for layered eviction policy. |
MinFreeDiskSpaceBytes |
long |
2 GB |
The proxy evicts (LRU) cached models before any cache drive gets below this threshold. Protects shared boxes from filling up the system drive. |
Cache lifecycle
- Client hits
/model/{org}/{repo}/{file}(or/torrent/...//magnet/...). - Proxy checks the cache. Cache hit: returns the .torrent / magnet immediately.
- Cache miss: proxy starts an async download from HuggingFace's CDN. The first request falls through to the CDN URL (so the client doesn't block); subsequent requests for the same file see the cached bytes.
- As bytes land on disk, the proxy chunks them into BEP 52 v2 pieces (16 KiB Merkle leaves, SHA-256 piece hashes) and writes a
.torrentnext to the payload. - LRU eviction kicks in when
MinFreeDiskSpaceBytesis at risk ORMaxCacheSizeBytesis exceeded.
The HuggingFace hostname (huggingface.co) is a hardcoded upstream — the proxy only fetches from that origin.
Use case: ML model delivery from Blazor
// Server side (this package)
app.MapHuggingFaceProxy(new HuggingFaceProxy(opts));
// Client side (Blazor WASM, using SpawnDev.WebTorrent)
var magnetJson = await Http.GetFromJsonAsync<MagnetResult>(
$"https://your-server/magnet/Xenova/whisper-tiny/onnx/encoder_model.onnx");
var torrent = await Client.AddAsync(magnetJson!.MagnetUri);
var bytes = await torrent.Files[0].ReadAsync(0, (int)torrent.Files[0].Length);
// Pieces arrive from peers AND from the HTTP web seed (your server) in parallel.
record MagnetResult(string MagnetUri, string RepoId, string FilePath, string WebSeed);
The first browser to load a model fills the cache; every subsequent browser participates in the swarm.
Full end-to-end walkthrough (both sides — including service-worker streaming, status polling, ONNX Runtime integration, and live hub.spawndev.com examples): Docs/huggingface.md in the WebTorrent project.
Production notes
- Disk space. A single browser session loading a 2 GB safetensors shard fills 2 GB of cache. Provision
CacheDirectoriesaccordingly; the LRU eviction is the safety net, not the plan. - CDN bandwidth. HuggingFace serves the first download; every subsequent download comes from your cache + peers in the swarm. Watching
/hf-statsshows the win — request count grows but byte count from the upstream stays flat. - Trackers. Override
TrackerUrlsto point at your own SpawnDev.RTC-based tracker (deploy via SpawnDev.RTC.ServerApp). Public trackers likewss://tracker.openwebtorrent.comwork too but are best-effort.
Dependencies
SpawnDev.WebTorrent.Server3.2.0 (web seed server primitives)SpawnDev.WebTorrent3.2.0 (.torrentcreation, SHA-256 piece hashing, BEP 52 v2)- ASP.NET Core 10 (
Microsoft.AspNetCore.Appframework reference)
License
MIT — see LICENSE.txt in the parent repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- SpawnDev.WebTorrent.Server (>= 3.2.3)
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 |
|---|---|---|
| 3.2.4-rc.7 | 0 | 5/3/2026 |
| 3.2.4-rc.6 | 0 | 5/3/2026 |
| 3.2.4-rc.5 | 0 | 5/3/2026 |
| 3.2.3 | 0 | 5/3/2026 |
| 3.2.3-rc.2 | 0 | 5/3/2026 |
| 3.2.2 | 88 | 4/29/2026 |
| 3.2.0 | 91 | 4/25/2026 |
v3.2.3 stable: version-sync with SpawnDev.WebTorrent + SpawnDev.WebTorrent.Server 3.2.3 stable. No source changes; transitive bump only.