28 KiB
28 KiB
Gateways — Gap Analysis
This file tracks what has and hasn't been ported from Go to .NET for the Gateways module. See stillmissing.md for the full LOC comparison across all modules.
LLM Instructions: How to Analyze This Category
Step 1: Read the Go Reference Files
Read each Go source file listed below. For every file:
- Extract all exported types (structs, interfaces, type aliases)
- Extract all exported methods on those types (receiver functions)
- Extract all exported standalone functions
- Note key constants, enums, and protocol states
- Note important unexported helpers that implement core logic (functions >20 lines)
- Pay attention to concurrency patterns (goroutines, mutexes, channels) — these map to different .NET patterns
Step 2: Read the .NET Implementation Files
Read all .cs files in the .NET directories listed below. For each Go symbol found in Step 1:
- Search for a matching type, method, or function in .NET
- If found, compare the behavior: does it handle the same edge cases? Same error paths?
- If partially implemented, note what's missing
- If not found, note it as MISSING
Step 3: Cross-Reference Tests
Compare Go test functions against .NET test methods:
- For each Go
Test*function, check if a corresponding .NET[Fact]or[Theory]exists - Note which test scenarios are covered and which are missing
- Check the parity DB (
docs/test_parity.db) for existing mappings:sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
Step 4: Classify Each Item
Use these status values:
| Status | Meaning |
|---|---|
| PORTED | Equivalent exists in .NET with matching behavior |
| PARTIAL | .NET implementation exists but is incomplete (missing edge cases, error handling, or features) |
| MISSING | No .NET equivalent found — needs to be ported |
| NOT_APPLICABLE | Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.) |
| DEFERRED | Intentionally skipped for now (document why) |
Step 5: Fill In the Gap Inventory
Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.
Key Porting Notes for Gateways
- Gateways connect separate NATS clusters. They start in "optimistic" mode (forward everything) then switch to "interest-only" mode.
- Reply subject mapping:
_GR_.<cluster>.<hash>.<reply>prevents routing loops. - Gateway connections use
ClientKind = GATEWAY.
Go Reference Files (Source)
golang/nats-server/server/gateway.go— Inter-cluster bridges (~3,400 lines). Interest-only mode optimizes traffic. Reply subject mapping (_GR_.prefix) avoids cross-cluster conflicts.
Go Reference Files (Tests)
golang/nats-server/server/gateway_test.gogolang/nats-server/test/gateway_test.go(integration)
.NET Implementation Files (Source)
src/NATS.Server/Gateways/(all files)
.NET Implementation Files (Tests)
tests/NATS.Server.Tests/Gateways/
Gap Inventory
golang/nats-server/server/gateway.go
Constants, Variables, and Enums
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
SetGatewaysSolicitDelay |
gateway.go:76 | NOT_APPLICABLE | — | Test-only helper; sets atomic delay before soliciting gateways. Go-specific test hook. |
ResetGatewaysSolicitDelay |
gateway.go:83 | NOT_APPLICABLE | — | Test-only helper; resets atomic delay. Go-specific test hook. |
GatewayDoNotForceInterestOnlyMode |
gateway.go:130 | NOT_APPLICABLE | — | Test-only global flag; disables forced interest-only mode in tests. Go-specific test hook. |
GatewayInterestMode (enum: Optimistic/Transitioning/InterestOnly) |
gateway.go:94–111 | PORTED | src/NATS.Server/Gateways/GatewayInterestTracker.cs:16 |
GatewayInterestMode enum with identical three values. |
GatewayInterestMode.String() |
gateway.go:113 | NOT_APPLICABLE | — | Go stringer pattern; C# uses ToString() automatically. |
gwReplyPrefix / gwReplyPrefixLen / gwHashLen / offset constants |
gateway.go:49–58 | PARTIAL | src/NATS.Server/Gateways/ReplyMapper.cs:12 |
GatewayReplyPrefix = "_GR_." is present. Hash length and byte-offset arithmetic constants are missing; .NET uses string-segment parsing instead of fixed-width offsets. |
oldGWReplyPrefix / oldGWReplyPrefixLen / oldGWReplyStart |
gateway.go:43–46 | MISSING | — | Old $GR. reply prefix for backward-compat with pre-v2.9 servers is not represented in .NET. ReplyMapper.TryRestoreGatewayReply handles it partially via numeric-hash detection but has no dedicated constant. |
gatewayTLSInsecureWarning |
gateway.go:71 | MISSING | — | TLS insecure warning string; no TLS gateway support yet. |
Structs / Types
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
srvGateway struct |
gateway.go:134 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:66 |
GatewayManager covers outbound/inbound maps, accept loop, discovery, registration, and stats. Missing: RTT-ordered outbound list (outo), totalQSubs atomic counter, pasi per-account subscription interest map, rsubs recent-subscription sync.Map, sIDHash/routesIDByHash for reply routing, sqbsz/recSubExp, and oldHash/oldReplyPfx for backward compat. |
sitally struct |
gateway.go:189 | MISSING | — | Subject-interest tally (ref count + queue flag) used in pasi.m. No equivalent in .NET. |
gatewayCfg struct |
gateway.go:194 | PARTIAL | src/NATS.Server/Configuration/GatewayOptions.cs:27 (RemoteGatewayOptions) |
RemoteGatewayOptions covers name and URLs. Missing: hash/oldHash byte arrays, implicit flag, connAttempts counter, tlsName, varzUpdateURLs, URL management methods (addURLs, updateURLs, getURLs, saveTLSHostname), and per-remote TLS config. |
gateway struct (per-client) |
gateway.go:207 | MISSING | — | Per-connection gateway state (outbound flag, outsim sync.Map, insim map, connectURL, useOldPrefix, interestOnlyMode, remoteName). Absorbed into GatewayConnection but without full per-message interest tracking. |
outsie struct |
gateway.go:229 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs |
GatewayInterestTracker.AccountState covers mode and no-interest set. Missing: per-account sl *Sublist for queue-sub tracking in InterestOnly mode, qsubs counter. |
insie struct |
gateway.go:256 | MISSING | — | Inbound per-account no-interest set with mode tracking. No distinct type in .NET; GatewayInterestTracker handles outbound-side equivalent but not the inbound RS-/RS+ tracking map. |
gwReplyMap struct |
gateway.go:261 | PARTIAL | src/NATS.Server/Gateways/ReplyMapper.cs:289 (CacheEntry) |
ReplyMapCache.CacheEntry provides key/value/TTL. Missing: Go stores ms string (routed subject) and exp int64 (Unix nano expiry); .NET uses DateTime but does not store the destination server/cluster hash separately. |
gwReplyMapping struct |
gateway.go:266 | PARTIAL | src/NATS.Server/Gateways/ReplyMapper.cs:181 (ReplyMapCache) |
ReplyMapCache provides LRU+TTL. Missing: atomic check int32 field for fast-path bypass; Go mapping is per-client or per-account with explicit locker, .NET is a single shared cache. |
GatewayConnectionState enum |
gateway.go (n/a) | PORTED | src/NATS.Server/Gateways/GatewayManager.cs:14 |
.NET addition: lifecycle states (Connecting/Connected/Disconnected/Draining). No direct Go equivalent but covers the connection state machine. |
GatewayRegistration |
gateway.go (n/a) | PORTED | src/NATS.Server/Gateways/GatewayManager.cs:26 |
.NET-specific registration record with stats counters. |
GatewayReconnectPolicy |
gateway.go:689 | PORTED | src/NATS.Server/Gateways/GatewayManager.cs:43 |
Exponential backoff with jitter matches Go's reconnect delay logic. |
GatewayInfo |
gateway.go (Info struct) | PARTIAL | src/NATS.Server/Gateways/GatewayInfo.cs:7 |
Covers name and URLs for gossip discovery. Go's Info struct has many more gateway-related fields (GatewayCmd, GatewayCmdPayload, GatewayNRP, GatewayIOM, GatewayURLs, etc.) that are not in this type. |
Functions and Methods — srvGateway receiver
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
srvGateway.updateRemotesTLSConfig |
gateway.go:426 | MISSING | — | Config-reload TLS update for remote gateway connections. TLS not implemented in .NET. |
srvGateway.rejectUnknown |
gateway.go:476 | PARTIAL | src/NATS.Server/Configuration/GatewayOptions.cs:11 |
GatewayOptions.RejectUnknown property exists but is not enforced in the accept-loop or handshake logic. |
srvGateway.generateInfoJSON |
gateway.go:649 | MISSING | — | Generates the gateway INFO protocol JSON. No INFO protocol generation in .NET. |
srvGateway.getClusterHash |
gateway.go:2892 | MISSING | — | Returns 6-byte cluster hash for reply routing. No cluster hash computed at runtime in .NET. |
srvGateway.shouldMapReplyForGatewaySend |
gateway.go:2507 | MISSING | — | Checks recent subscriptions (rsubs) to decide whether to map a reply subject. rsubs not ported. |
srvGateway.orderOutboundConnectionsLocked |
gateway.go:1764 | MISSING | — | Sorts outbound connections by lowest RTT. RTT-based ordering not implemented. |
srvGateway.orderOutboundConnections |
gateway.go:1771 | MISSING | — | Locked wrapper for orderOutboundConnectionsLocked. |
Functions and Methods — Server receiver
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
validateGatewayOptions |
gateway.go:306 | MISSING | — | Validates gateway config (name, port, remote URLs). No validation equivalent in .NET. |
getGWHash (standalone) |
gateway.go:335 | MISSING | — | Computes 6-char hash for gateway name. Used for reply prefix construction. Not ported. |
getOldHash (standalone) |
gateway.go:339 | MISSING | — | SHA-256-based 4-char hash for old $GR. prefix. Not ported. |
Server.newGateway |
gateway.go:350 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:90 |
GatewayManager constructor covers basic setup. Missing: hash computation, reply prefix assembly, oldReplyPfx, pasi init, resolver config. |
Server.startGateways |
gateway.go:487 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:161 (StartAsync) |
StartAsync starts accept loop and connects to remotes. Missing: solicit delay, cluster-formation wait. |
Server.startGatewayAcceptLoop |
gateway.go:511 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:326 (AcceptLoopAsync) |
Accept loop exists. Missing: TLS config, authRequired, reject-unknown check, advertising, GatewayIOM flag, INFO protocol send. |
Server.setGatewayInfoHostPort |
gateway.go:595 | MISSING | — | Configures gateway listener host/port with advertise override and non-local IP resolution. |
Server.solicitGateways |
gateway.go:668 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:173 (StartAsync remote loop) |
Connects to configured remotes. Missing: implicit vs explicit distinction, goroutine-per-remote with proper lifecycle. |
Server.reconnectGateway |
gateway.go:689 | PORTED | src/NATS.Server/Gateways/GatewayManager.cs:149 (ReconnectGatewayAsync) |
Exponential backoff reconnect delay with jitter. |
Server.solicitGateway |
gateway.go:706 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:358 (ConnectWithRetryAsync) |
Retry loop with multiple URL support. Missing: random URL selection, shouldReportConnectErr throttling, implicit gateway retry limits, DNS resolution via resolver, ConnectBackoff flag. |
srvGateway.hasInbound |
gateway.go:790 | MISSING | — | Checks if an inbound connection for a named gateway exists. Not implemented. |
Server.createGateway |
gateway.go:805 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:344 (HandleInboundAsync) and ConnectWithRetryAsync |
Creates client connection for inbound/outbound. Missing: full client lifecycle, TLS handshake, CONNECT/INFO protocol, expectConnect flag, ping timer setup, temp-client registration. |
client.sendGatewayConnect |
gateway.go:958 | PARTIAL | src/NATS.Server/Gateways/GatewayConnection.cs:113 (PerformOutboundHandshakeAsync) |
Handshake sends server ID. Go sends full CONNECT JSON with auth, TLS flag, gateway name. .NET sends a simplified GATEWAY {serverId} line. |
client.processGatewayConnect |
gateway.go:993 | MISSING | — | Parses CONNECT from inbound gateway; validates gateway field, rejects wrong port/unknown gateways. No protocol parsing in .NET. |
client.processGatewayInfo |
gateway.go:1045 | MISSING | — | Handles INFO protocol for both outbound (first connect + gossip) and inbound (register, switch to interest-only, send queue subs). Core of gateway handshake. Not ported. |
Server.gossipGatewaysToInboundGateway |
gateway.go:1253 | MISSING | — | Sends INFO gossip for all known gateways to a new inbound connection for full-mesh formation. |
Server.forwardNewGatewayToLocalCluster |
gateway.go:1279 | MISSING | — | Floods cluster routes with new gateway INFO to ensure all nodes connect. |
Server.sendQueueSubsToGateway |
gateway.go:1311 | PARTIAL | src/NATS.Server/Gateways/GatewayConnection.cs:72 (AddQueueSubscription) |
Registers queue subs locally. Missing: actual RS+ wire protocol emission to the remote peer. |
Server.sendAccountSubsToGateway |
gateway.go:1319 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:210 (SendAccountSubscriptions) |
Sends subject list to named gateway. Missing: wire protocol emission (RS+ with account prefix) and mode switch to InterestOnly. |
gwBuildSubProto (standalone) |
gateway.go:1323 | MISSING | — | Builds RS+/RS- binary protocol buffer for a given account/subject map. |
Server.sendSubsToGateway |
gateway.go:1342 | MISSING | — | Full subscription send loop (queue subs on connect, or all subs for an account on mode switch). |
Server.processGatewayInfoFromRoute |
gateway.go:1394 | MISSING | — | Handles gateway gossip INFO received via a cluster route connection. |
Server.sendGatewayConfigsToRoute |
gateway.go:1406 | MISSING | — | Sends known outbound gateway configs to a new route connection. |
Server.processImplicitGateway |
gateway.go:1453 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:119 (ProcessImplicitGateway) |
Records discovered gateway name. Missing: URL augmentation of existing config, creation of gatewayCfg, launching solicitGateway goroutine for the new implicit remote. |
Server.NumOutboundGateways |
gateway.go:1501 | MISSING | — | Public test-facing count of outbound connections. No exact equivalent. |
Server.numOutboundGateways |
gateway.go:1506 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:284 (GetConnectedGatewayCount) |
Returns connected count from registrations. Does not distinguish inbound vs outbound. |
Server.numInboundGateways |
gateway.go:1514 | MISSING | — | Count of inbound gateway connections. No equivalent. |
Server.getRemoteGateway |
gateway.go:1522 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:264 (GetRegistration) |
Returns registration by name. Missing: returns gatewayCfg in Go (with TLS, URLs, hash); .NET returns GatewayRegistration (only state/stats). |
gatewayCfg.bumpConnAttempts |
gateway.go:1530 | MISSING | — | Test helper to increment connection attempts counter. |
gatewayCfg.getConnAttempts |
gateway.go:1537 | MISSING | — | Test helper to read connection attempts. |
gatewayCfg.resetConnAttempts |
gateway.go:1545 | MISSING | — | Test helper to reset connection attempts. |
gatewayCfg.isImplicit |
gateway.go:1552 | MISSING | — | Returns whether a gateway config was discovered (implicit) vs configured (explicit). |
gatewayCfg.getURLs |
gateway.go:1561 | MISSING | — | Returns randomly shuffled URL slice for connection attempts. |
gatewayCfg.getURLsAsStrings |
gateway.go:1576 | MISSING | — | Returns URL host strings for gossip INFO. |
gatewayCfg.updateURLs |
gateway.go:1588 | MISSING | — | Rebuilds URL map from config + INFO-discovered URLs. |
gatewayCfg.saveTLSHostname |
gateway.go:1612 | MISSING | — | Saves TLS ServerName from a URL hostname. TLS not implemented. |
gatewayCfg.addURLs |
gateway.go:1621 | MISSING | — | Adds newly discovered URLs into the URL map. |
Server.addGatewayURL |
gateway.go:1648 | MISSING | — | Adds a URL to the server's gateway URL set and regenerates INFO JSON. |
Server.removeGatewayURL |
gateway.go:1661 | MISSING | — | Removes a URL from the gateway URL set and regenerates INFO JSON. |
Server.sendAsyncGatewayInfo |
gateway.go:1676 | MISSING | — | Sends updated INFO to all inbound gateway connections (e.g., after URL change). |
Server.getGatewayURL |
gateway.go:1688 | MISSING | — | Returns this server's gateway listen URL string. |
Server.getGatewayName |
gateway.go:1697 | MISSING | — | Returns this server's gateway cluster name. |
Server.getAllGatewayConnections |
gateway.go:1703 | MISSING | — | Collects all inbound + outbound gateway clients into a map. |
Server.registerInboundGatewayConnection |
gateway.go:1720 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:392 (Register) |
Register adds connection to dictionary. Missing: separate inbound map keyed by CID. |
Server.registerOutboundGatewayConnection |
gateway.go:1728 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:392 (Register) |
Register handles registration. Missing: duplicate-prevention logic (return false if name already exists), RTT-ordered outo list. |
Server.getOutboundGatewayConnection |
gateway.go:1743 | MISSING | — | Returns outbound connection by name. No named lookup of outbound connections. |
Server.getOutboundGatewayConnections |
gateway.go:1752 | MISSING | — | Returns all outbound connections in RTT order. |
Server.getInboundGatewayConnections |
gateway.go:1778 | MISSING | — | Returns all inbound connections. |
Server.removeRemoteGatewayConnection |
gateway.go:1788 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:416 (WatchConnectionAsync) |
Removes connection and decrements stats. Missing: outbound-specific cleanup (delete from outo/out, remove qsub tracking from totalQSubs), inbound-specific cleanup (remove _R_ subscriptions). |
Server.GatewayAddr |
gateway.go:1862 | MISSING | — | Returns *net.TCPAddr for the gateway listener. No equivalent (only ListenEndpoint string). |
client.processGatewayAccountUnsub |
gateway.go:1875 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs:86 (TrackNoInterest) |
Tracks no-interest at account level. Missing: handling of queue subs (reset ni map but keep entry if qsubs > 0), Go's nil-vs-entry distinction in outsim. |
client.processGatewayAccountSub |
gateway.go:1904 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs:61 (TrackInterest) |
Clears no-interest in optimistic mode. Missing: queue-sub check (don't delete entry if qsubs > 0). |
client.processGatewayRUnsub |
gateway.go:1934 | MISSING | — | Parses RS- protocol; for optimistic mode stores in ni map, for InterestOnly/queue removes from sublist. Full RS- processing not ported. |
client.processGatewayRSub |
gateway.go:2029 | MISSING | — | Parses RS+ protocol; registers interest in sublist for queue subs and InterestOnly mode. Full RS+ processing not ported. |
client.gatewayInterest |
gateway.go:2165 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs:113 (ShouldForward) |
ShouldForward handles Optimistic/Transitioning/InterestOnly modes. Missing: separate queue-sub result (*SublistResult) return, interestOnlyMode flag override, emptyResult guard. |
Server.switchAccountToInterestMode |
gateway.go:2211 | PORTED | src/NATS.Server/Gateways/GatewayInterestTracker.cs:144 (SwitchToInterestOnly) |
Switches account to InterestOnly. Go iterates all inbound connections; .NET operates per-tracker instance. |
Server.maybeSendSubOrUnsubToGateways |
gateway.go:2237 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:193 (PropagateLocalSubscription/Unsubscription) |
Propagates sub/unsub to inbound gateways. Missing: per-mode decision (optimistic ni-map check vs InterestOnly always-send), wildcard cleanup of ni-map, A+ send when clearing A-, actual wire protocol. |
Server.sendQueueSubOrUnsubToGateways |
gateway.go:2335 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:199 (PropagateLocalUnsubscription) |
Propagates queue sub changes. Missing: wire RS+/RS- protocol, A- clearing logic. |
Server.gatewayUpdateSubInterest |
gateway.go:2391 | MISSING | — | Ref-counted pasi map update + recent-sub tracking + triggers send to gateways. Core subscription-interest accounting not ported. |
isGWRoutedReply (standalone) |
gateway.go:2484 | PORTED | src/NATS.Server/Gateways/ReplyMapper.cs:17 (HasGatewayReplyPrefix) |
Detects _GR_. prefix with length guard. |
isGWRoutedSubjectAndIsOldPrefix (standalone) |
gateway.go:2490 | PARTIAL | src/NATS.Server/Gateways/ReplyMapper.cs:17 |
HasGatewayReplyPrefix checks new prefix only. Old $GR. prefix detection missing. |
hasGWRoutedReplyPrefix (standalone) |
gateway.go:2502 | PORTED | src/NATS.Server/Gateways/ReplyMapper.cs:17 (HasGatewayReplyPrefix) |
Equivalent prefix check. |
srvGateway.shouldMapReplyForGatewaySend |
gateway.go:2507 | MISSING | — | Checks rsubs sync.Map to decide if a reply subject needs gateway mapping. No rsubs equivalent. |
client.sendMsgToGateways |
gateway.go:2540 | PARTIAL | src/NATS.Server/Gateways/GatewayManager.cs:181 (ForwardMessageAsync) |
Iterates connections and sends. Missing: direct-send path for _GR_ subjects (hash routing), queue group filtering, reply subject mapping, header stripping for non-header peers, message tracing, per-account stats, RTT-ordered iteration. |
Server.gatewayHandleAccountNoInterest |
gateway.go:2787 | PARTIAL | Partially in GatewayInterestTracker.TrackNoInterest |
Sends A- under pasi lock. Missing: pasi lock coordination, actual A- wire protocol emission from inbound side. |
client.sendAccountUnsubToGateway |
gateway.go:2802 | PARTIAL | src/NATS.Server/Gateways/GatewayConnection.cs:142 (SendAMinusAsync) |
Sends A- wire protocol. Missing: idempotency guard (don't send if already sent, tracked via nil entry in insim). |
Server.gatewayHandleSubjectNoInterest |
gateway.go:2830 | MISSING | — | On missing subject interest: sends RS- under pasi lock, counts RS-, triggers mode switch at threshold. Core interest-only negotiation not ported. |
Server.storeRouteByHash |
gateway.go:2901 | MISSING | — | Stores route client keyed by server-ID hash for gateway reply routing. |
Server.removeRouteByHash |
gateway.go:2909 | MISSING | — | Removes route entry by hash. |
Server.getRouteByHash |
gateway.go:2918 | MISSING | — | Looks up route by hash for per-account or pool routing. Used in handleGatewayReply. |
getSubjectFromGWRoutedReply (standalone) |
gateway.go:2948 | PORTED | src/NATS.Server/Gateways/ReplyMapper.cs:74 (TryRestoreGatewayReply) |
Extracts original subject from routed reply; handles both old and new prefix. |
client.handleGatewayReply |
gateway.go:2963 | MISSING | — | On inbound message: detects _GR_ prefix, decodes cluster/server hash, routes to origin route or delivers locally. Core gateway reply routing not ported. |
client.processInboundGatewayMsg |
gateway.go:3107 | MISSING | — | Main inbound message processor: handles GW reply, account lookup, no-interest signaling, message delivery. Not ported. |
client.gatewayAllSubsReceiveStart |
gateway.go:3183 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs:86 (mode=Transitioning path) |
Go sets mode to Transitioning; .NET sets Transitioning mode when threshold crossed. Missing: command-protocol parsing, explicit start triggered by INFO command. |
client.gatewayAllSubsReceiveComplete |
gateway.go:3216 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs:144 (SwitchToInterestOnly) |
Final switch to InterestOnly. Go clears ni map and sets mode; .NET does equivalent. Missing: triggered by INFO command with gatewayCmdAllSubsComplete. |
getAccountFromGatewayCommand (standalone) |
gateway.go:3240 | MISSING | — | Extracts account from GatewayCmdPayload in INFO protocol. Not ported. |
client.gatewaySwitchAccountToSendAllSubs |
gateway.go:3260 | PARTIAL | src/NATS.Server/Gateways/GatewayInterestTracker.cs:144 (SwitchToInterestOnly) |
Switches mode and triggers async all-subs send. Missing: INFO command emission (gatewayCmdAllSubsStart/gatewayCmdAllSubsComplete), async sendAccountSubsToGateway goroutine. |
Server.trackGWReply |
gateway.go:3324 | PARTIAL | src/NATS.Server/Gateways/ReplyMapper.cs:231 (ReplyMapCache.Set) |
Caches reply mapping with TTL. Missing: per-client vs per-account duality, gwrm.m sync.Map for background cleanup, check int32 atomic flag, gwrm.ch channel to trigger expiry timer. |
Server.startGWReplyMapExpiration |
gateway.go:3371 | PARTIAL | src/NATS.Server/Gateways/ReplyMapper.cs:267 (ReplyMapCache.PurgeExpired) |
Purge is manual on-demand. Go runs a dedicated goroutine with timer reset on new entries via channel. No background expiry goroutine in .NET. |
gwReplyMapping.get |
gateway.go:280 | PORTED | src/NATS.Server/Gateways/ReplyMapper.cs:202 (ReplyMapCache.TryGet) |
LRU get with TTL check. |
RemoteGatewayOpts.clone |
gateway.go:290 | MISSING | — | Deep-copies a RemoteGatewayOpts including TLS config clone. No clone method on RemoteGatewayOptions. |
Additional .NET-Only Types (No Go Equivalent)
| .NET Symbol | .NET File:Line | Notes |
|---|---|---|
GatewayCommandType enum |
src/NATS.Server/Gateways/GatewayCommands.cs:9 |
.NET-specific wire command enum; Go uses string constants and byte dispatch. |
GatewayCommands static class |
src/NATS.Server/Gateways/GatewayCommands.cs:31 |
Wire-protocol constants and formatters. Partially maps to Go's rSubBytes/rUnsubBytes/aSubBytes/aUnsubBytes/InfoProto but uses a simplified format. |
GatewayMessage record |
src/NATS.Server/Gateways/GatewayConnection.cs:346 |
DTO for received messages; no direct Go equivalent. |
ReplyMapCache |
src/NATS.Server/Gateways/ReplyMapper.cs:181 |
LRU+TTL cache for reply mappings. |
Keeping This File Updated
After porting work is completed:
- Update status: Change
MISSING → PORTEDorPARTIAL → PORTEDfor each item completed - Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
- Re-count LOC: Update the LOC numbers in
stillmissing.md:# Re-count .NET source LOC for this module find src/NATS.Server/Gateways/ -name '*.cs' -type f -exec cat {} + | wc -l # Re-count .NET test LOC for this module find tests/NATS.Server.Tests/Gateways/ -name '*.cs' -type f -exec cat {} + | wc -l - Add a changelog entry below with date and summary of what was ported
- Update the parity DB if new test mappings were created:
sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
Change Log
| Date | Change | By |
|---|---|---|
| 2026-02-25 | File created with LLM analysis instructions | auto |
| 2026-02-25 | Full gap inventory completed: analyzed all ~3,427 lines of gateway.go; classified 80+ Go symbols against 6 .NET source files. Final counts: 9 PORTED, 35 PARTIAL, 37 MISSING, 5 NOT_APPLICABLE. | claude-sonnet-4-6 |