- Update all 7 phase docs with source/target location references (golang/ for Go source, dotnet/ for .NET version) - Rename NATS.Server to ZB.MOM.NatsNet.Server in phase 4-7 docs - Update solution layout to dotnet/src/ and dotnet/tests/ structure - Create CLAUDE.md with project summary and phase links - Update .gitignore: track porting.db, add standard .NET patterns - Add golang/nats-server as git submodule - Add reports/generate-report.sh and pre-commit hook - Add documentation_rules.md to version control
291 lines
12 KiB
Markdown
291 lines
12 KiB
Markdown
# 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/` |
|
|
|
|
## 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 <id> \
|
|
--package "<NuGet package or BCL>" \
|
|
--namespace "<.NET namespace>" \
|
|
--notes "<migration 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 <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:
|
|
|
|
```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: <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:
|
|
|
|
```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<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:
|
|
|
|
- [ ] `library suggest` returns "All libraries have been mapped!"
|
|
- [ ] Every entry in `library list` shows status `mapped` or `verified`.
|
|
- [ ] Each mapping includes a `--package` (the NuGet package or BCL assembly),
|
|
a `--namespace` (the .NET namespace to use), and `--notes` (migration
|
|
guidance).
|
|
- [ ] `phase check 1` shows all items checked including "All libraries mapped".
|
|
- [ ] A mapping report has been exported for reference.
|
|
|
|
## Troubleshooting
|
|
|
|
### "Library <id> 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.
|