Files
natsnet/docs/plans/phases/phase-3-library-mapping.md
Joseph Doherty 6021d8445e docs: link completion criteria to Gitea issues and add issue tracking guidance
- Created 52 Gitea issues across milestones 1-7, one per completion criterion
- Each criterion now links to its corresponding issue ([#N](url) format)
- Milestone Tracking sections updated with Issue Updates subsection:
  when/how to comment, close issues via CLI or web UI
- Phases 4-7 criteria converted from plain bullets to checkbox format
2026-02-26 06:50:08 -05:00

14 KiB

Phase 3: Library Mapping

Objective

Map every external Go dependency detected by the analyzer to its .NET equivalent. This includes Go standard library packages, well-known third-party libraries, and NATS ecosystem packages. When Phase 3 is complete, the library suggest command returns an empty list and every import has a documented .NET migration path.

Prerequisites

  • Phases 1 and 2 are complete (database is populated and verified).
  • Familiarity with both the Go standard library and .NET BCL / NuGet ecosystem.
  • A working dotnet CLI for running PortTracker commands.

Source and Target Locations

Component Path
Go source code golang/ (specifically golang/nats-server/)
.NET ported version dotnet/

Milestone Tracking

This phase corresponds to Milestone 3 in Gitea. When starting this phase, verify the milestone is open. Assign relevant issues to this milestone as work progresses.

Issue Updates

Each completion criterion has a corresponding Gitea issue. Update issues as you work:

  • Starting a criterion: Add a comment noting work has begun
  • Blocked: Add a comment describing the blocker
  • Complete: Close the issue with a comment summarizing the result (e.g., counts, verification output)

Close issues via CLI:

curl -s -X PATCH "https://gitea.dohertylan.com/api/v1/repos/dohertj2/natsnet/issues/{N}" \
  -H "Content-Type: application/json" \
  -H "Authorization: token $GITEA_TOKEN" \
  -d '{"state":"closed"}'

Or close via the Gitea web UI.

Steps

Step 1: List all unmapped libraries

Start by seeing everything that needs attention:

dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db

This shows all library_mappings entries with status not_mapped, sorted by import path. The output includes the Go import path, the library name, and a usage description.

If the list is empty, all libraries are already mapped and Phase 3 is complete.

Step 2: Review the full library list

To see both mapped and unmapped libraries in one view:

dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db

You can also filter by status:

dotnet run --project tools/NatsNet.PortTracker -- library list --status not_mapped --db porting.db
dotnet run --project tools/NatsNet.PortTracker -- library list --status mapped --db porting.db

Step 3: Map each library

For each unmapped library, determine the appropriate .NET equivalent using the reference table below, then record the mapping:

dotnet run --project tools/NatsNet.PortTracker -- library map <id> \
  --package "<NuGet package or BCL>" \
  --namespace "<.NET namespace>" \
  --notes "<migration notes>" \
  --db porting.db

Example -- mapping encoding/json:

dotnet run --project tools/NatsNet.PortTracker -- library map 1 \
  --package "System.Text.Json" \
  --namespace "System.Text.Json" \
  --notes "Use JsonSerializer. Consider source generators for AOT." \
  --db porting.db

Example -- mapping github.com/klauspost/compress:

dotnet run --project tools/NatsNet.PortTracker -- library map 12 \
  --package "System.IO.Compression" \
  --namespace "System.IO.Compression" \
  --notes "S2/Snappy codec needs evaluation; may need custom impl or IronSnappy NuGet." \
  --db porting.db

Repeat for every entry in the library suggest output.

Step 4: Handle libraries that need custom implementations

Some Go libraries have no direct .NET equivalent and will require custom code. For these, record the mapping with a descriptive note:

dotnet run --project tools/NatsNet.PortTracker -- library map <id> \
  --package "Custom" \
  --namespace "NatsNet.Internal" \
  --notes "No direct equivalent; requires custom implementation. See <details>." \
  --db porting.db

Step 5: Verify all libraries are mapped

Run the suggest command again -- it should return an empty list:

dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db

Expected output:

All libraries have been mapped!

Also verify via the full list:

dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db

Every entry should show status mapped (or verified if you have already validated the mapping in code).

Step 6: Run the phase check

Confirm Phase 1 now shows full completion including library mappings:

dotnet run --project tools/NatsNet.PortTracker -- phase check 1 --db porting.db

Expected:

Phase 1 Checklist:
  [x] Modules populated:       <N>
  [x] Features populated:      <N>
  [x] Unit tests populated:    <N>
  [x] Dependencies mapped:     <N>
  [x] Libraries identified:    <N>
  [x] All libraries mapped:    <N>/<N>

Step 7: Export the mapping report

Save the complete library mapping state for reference during porting:

dotnet run --project tools/NatsNet.PortTracker -- report export \
  --format md \
  --output docs/reports/phase-3-library-mapping.md \
  --db porting.db

Common Go to .NET Mappings Reference

Use this table as a starting point when determining .NET equivalents. Adapt based on the specific usage patterns found in the NATS server source.

Go Standard Library

Go Package .NET Equivalent Notes
encoding/json System.Text.Json Use JsonSerializer; consider source generators for performance
encoding/binary System.Buffers.Binary.BinaryPrimitives For endian-aware reads/writes
encoding/base64 System.Convert Convert.ToBase64String / Convert.FromBase64String
encoding/hex System.Convert Convert.ToHexString (.NET 5+)
encoding/pem System.Security.Cryptography.PemEncoding .NET 5+
sync System.Threading Mutex -> lock / Monitor; RWMutex -> ReaderWriterLockSlim; WaitGroup -> CountdownEvent; Once -> Lazy<T>
sync/atomic System.Threading.Interlocked Interlocked.Increment, CompareExchange, etc.
net System.Net.Sockets TcpListener, TcpClient, Socket
net/http System.Net.Http / Microsoft.AspNetCore Client: HttpClient; Server: Kestrel / minimal APIs
net/url System.Uri Uri, UriBuilder
crypto/tls System.Net.Security.SslStream Wrap NetworkStream with SslStream
crypto/x509 System.Security.Cryptography.X509Certificates X509Certificate2
crypto/sha256 System.Security.Cryptography.SHA256 SHA256.HashData() (.NET 8+)
crypto/ed25519 System.Security.Cryptography Ed25519 support in .NET 9+
crypto/rand System.Security.Cryptography.RandomNumberGenerator RandomNumberGenerator.Fill()
time System.TimeSpan / System.Threading.Timer time.Duration -> TimeSpan; time.Ticker -> PeriodicTimer; time.After -> Task.Delay
time (parsing) System.DateTime / System.DateTimeOffset DateTime.Parse, custom formats
fmt String interpolation / String.Format $"..." for most cases; String.Format for dynamic
io System.IO Reader -> Stream; Writer -> Stream; io.Copy -> Stream.CopyTo
io/fs System.IO Directory, File, FileInfo
bufio System.IO.BufferedStream Or StreamReader / StreamWriter
bytes System.Buffers / MemoryStream bytes.Buffer -> MemoryStream or ArrayBufferWriter<byte>
strings System.String / System.Text.StringBuilder Most methods have direct equivalents
strconv int.Parse, double.Parse, etc. Or Convert class
context CancellationToken context.Context -> CancellationToken; context.WithCancel -> CancellationTokenSource
os System.Environment / System.IO os.Exit -> Environment.Exit; file ops -> File class
os/signal System.Runtime.Loader.AssemblyLoadContext UnloadingEvent or Console.CancelKeyPress
path/filepath System.IO.Path Path.Combine, Path.GetDirectoryName, etc.
sort System.Linq / Array.Sort LINQ .OrderBy() or in-place Array.Sort
math System.Math Direct equivalent
math/rand System.Random Random.Shared for thread-safe usage (.NET 6+)
regexp System.Text.RegularExpressions.Regex Consider source generators for compiled patterns
errors System.Exception Go errors -> .NET exceptions; errors.Is -> pattern matching
log Serilog Project choice: Serilog via Microsoft.Extensions.Logging
testing xUnit testing.T -> xUnit [Fact]/[Theory]; testing.B -> BenchmarkDotNet
flag System.CommandLine Or Microsoft.Extensions.Configuration
embed Embedded resources .csproj <EmbeddedResource> items
runtime System.Runtime / System.Environment runtime.GOOS -> RuntimeInformation.IsOSPlatform

NATS Ecosystem Libraries

Go Package .NET Equivalent Notes
github.com/nats-io/jwt/v2 Custom / evaluate existing JWT claims for NATS auth; may need custom implementation matching NATS JWT spec
github.com/nats-io/nkeys Custom implementation Ed25519 key pairs for NATS authentication; use System.Security.Cryptography Ed25519
github.com/nats-io/nuid Custom / System.Guid NATS unique IDs; simple custom implementation or adapt to Guid if format is flexible
github.com/nats-io/nats.go NATS.Net (official) Only used in tests; the official .NET NATS client

Third-Party Libraries

Go Package .NET Equivalent Notes
github.com/klauspost/compress System.IO.Compression General compression: GZipStream, DeflateStream. S2/Snappy: evaluate IronSnappy NuGet or custom port
github.com/minio/highwayhash Custom / NuGet HighwayHash implementation; search NuGet or port the algorithm
golang.org/x/crypto System.Security.Cryptography bcrypt -> Rfc2898DeriveBytes or BCrypt.Net NuGet; argon2 -> Konscious.Security NuGet
golang.org/x/sys System.Runtime.InteropServices Platform-specific syscalls -> P/Invoke or RuntimeInformation
golang.org/x/time System.Threading.RateLimiting rate.Limiter -> RateLimiter (.NET 7+); TokenBucketRateLimiter or SlidingWindowRateLimiter
golang.org/x/text System.Globalization Unicode normalization, encoding detection

Mapping Decision Guidelines

When choosing a .NET equivalent, follow these priorities:

  1. BCL first: Prefer built-in .NET Base Class Library types over NuGet packages.
  2. Official packages second: If BCL does not cover it, prefer Microsoft.* or System.* NuGet packages.
  3. Well-maintained NuGet third: Choose packages with active maintenance, high download counts, and compatible licenses.
  4. Custom implementation last: Only write custom code when no suitable package exists. Document the rationale in the mapping notes.

For each mapping, consider:

  • API surface: Does the .NET equivalent cover all methods used in the Go code?
  • Performance: Are there performance-critical paths that need benchmarking?
  • Thread safety: Go's concurrency model differs from .NET. Note any synchronization concerns.
  • Platform support: Does the .NET package work on all target platforms (Linux, macOS, Windows)?

Completion Criteria

Phase 3 is complete when ALL of the following are true:

  • #30 library suggest returns "All libraries have been mapped!"
  • #21 Every entry in library list shows status mapped or verified.
  • #22 Each mapping includes a --package (the NuGet package or BCL assembly), a --namespace (the .NET namespace to use), and --notes (migration guidance).
  • #23 phase check 1 shows all items checked including "All libraries mapped".
  • #24 A mapping report has been exported for reference.
  • Close the Phase 3 milestone in Gitea:
    curl -s -X PATCH "https://gitea.dohertylan.com/api/v1/repos/dohertj2/natsnet/milestones/3" \
      -H "Content-Type: application/json" \
      -H "Authorization: token $GITEA_TOKEN" \
      -d '{"state":"closed"}'
    
    Or close it via the Gitea web UI at https://gitea.dohertylan.com/dohertj2/natsnet/milestone/3

Troubleshooting

"Library not found"

The ID you passed to library map does not exist. Run library suggest to get the current list of IDs and their import paths.

Unsure which .NET package to use

For unfamiliar Go packages:

  1. Check what the package does in the Go source (look at the import usage in the files listed by the analyzer).
  2. Search NuGet.org for equivalent functionality.
  3. Check if the Go package is a thin wrapper around a well-known algorithm that .NET implements natively.
  4. When in doubt, map it as "Custom" with detailed notes and revisit during the porting phase.

Multiple .NET options for one Go package

When there are several valid .NET equivalents (e.g., Newtonsoft.Json vs System.Text.Json), prefer the one that:

  • Is part of the BCL or a Microsoft package.
  • Has better performance characteristics.
  • Has source generator support for AOT compilation.

Record the alternatives in the --notes field so the decision can be revisited.

Stdlib packages showing as unmapped

The analyzer classifies imports as stdlib vs external based on whether the first path component contains a dot. Standard library packages like encoding/json, net/http, etc. should still be recorded in the library_mappings table so that every import path has a documented .NET migration path. Map them using the reference table above.