# 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](https://gitea.dohertylan.com/dohertj2/natsnet/milestone/3). 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: ```bash 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: ```bash 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: ```bash dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db ``` You can also filter by status: ```bash 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: ```bash dotnet run --project tools/NatsNet.PortTracker -- library map \ --package "" \ --namespace "<.NET namespace>" \ --notes "" \ --db porting.db ``` **Example -- mapping `encoding/json`:** ```bash 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`:** ```bash 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: ```bash dotnet run --project tools/NatsNet.PortTracker -- library map \ --package "Custom" \ --namespace "NatsNet.Internal" \ --notes "No direct equivalent; requires custom implementation. See
." \ --db porting.db ``` ### Step 5: Verify all libraries are mapped Run the suggest command again -- it should return an empty list: ```bash dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db ``` Expected output: ``` All libraries have been mapped! ``` Also verify via the full list: ```bash 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: ```bash dotnet run --project tools/NatsNet.PortTracker -- phase check 1 --db porting.db ``` Expected: ``` Phase 1 Checklist: [x] Modules populated: [x] Features populated: [x] Unit tests populated: [x] Dependencies mapped: [x] Libraries identified: [x] All libraries mapped: / ``` ### Step 7: Export the mapping report Save the complete library mapping state for reference during porting: ```bash 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` | | `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` | | `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` `` 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](https://gitea.dohertylan.com/dohertj2/natsnet/issues/30) `library suggest` returns "All libraries have been mapped!" - [ ] [#21](https://gitea.dohertylan.com/dohertj2/natsnet/issues/21) Every entry in `library list` shows status `mapped` or `verified`. - [ ] [#22](https://gitea.dohertylan.com/dohertj2/natsnet/issues/22) Each mapping includes a `--package` (the NuGet package or BCL assembly), a `--namespace` (the .NET namespace to use), and `--notes` (migration guidance). - [ ] [#23](https://gitea.dohertylan.com/dohertj2/natsnet/issues/23) `phase check 1` shows all items checked including "All libraries mapped". - [ ] [#24](https://gitea.dohertylan.com/dohertj2/natsnet/issues/24) A mapping report has been exported for reference. - [ ] Close the Phase 3 milestone in Gitea: ```bash 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.