using System.Security.Cryptography; using NATS.Server.Auth; namespace NATS.Server.Imports; /// /// Handles response routing for service imports. /// Maps to Go's service reply prefix generation and response cleanup. /// Reference: golang/nats-server/server/accounts.go — addRespServiceImport, removeRespServiceImport /// public static class ResponseRouter { private static readonly char[] Base62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray(); /// /// Generates a unique reply prefix for response routing. /// Format: "_R_.{10 random base62 chars}." /// public static string GenerateReplyPrefix() { Span bytes = stackalloc byte[10]; RandomNumberGenerator.Fill(bytes); var chars = new char[10]; for (int i = 0; i < 10; i++) chars[i] = Base62[bytes[i] % 62]; return $"_R_.{new string(chars)}."; } /// /// Creates a response service import that maps the generated reply prefix /// back to the original reply subject on the requesting account. /// public static ServiceImport CreateResponseImport( Account exporterAccount, ServiceImport originalImport, string originalReply) { var replyPrefix = GenerateReplyPrefix(); var responseSi = new ServiceImport { DestinationAccount = exporterAccount, From = replyPrefix + ">", To = originalReply, IsResponse = true, ResponseType = originalImport.ResponseType, Export = originalImport.Export, TimestampTicks = DateTime.UtcNow.Ticks, }; exporterAccount.Exports.Responses[replyPrefix] = responseSi; return responseSi; } /// /// Removes a response import from the account's export map. /// For Singleton responses, this is called after the first reply is delivered. /// For Streamed/Chunked, it is called when the response stream ends. /// public static void CleanupResponse(Account account, string replyPrefix, ServiceImport responseSi) { account.Exports.Responses.Remove(replyPrefix); } }