using Microsoft.AspNetCore.Http; using NATS.Server.Subscriptions; namespace NATS.Server.Monitoring; /// /// Handles /subz endpoint requests, returning subscription information. /// Corresponds to Go server/monitor.go handleSubsz. /// public sealed class SubszHandler(NatsServer server) { public Subsz HandleSubsz(HttpContext ctx) { var opts = ParseQueryParams(ctx); var now = DateTime.UtcNow; // Collect subscriptions from all accounts (or filtered). // Exclude the $SYS system account unless explicitly requested — its internal // subscriptions are infrastructure and not user-facing. var allSubs = new List(); foreach (var account in server.GetAccounts()) { if (!string.IsNullOrEmpty(opts.Account) && account.Name != opts.Account) continue; if (string.IsNullOrEmpty(opts.Account) && account.Name == "$SYS") continue; allSubs.AddRange(account.SubList.GetAllSubscriptions()); } // Filter by test subject if provided if (!string.IsNullOrEmpty(opts.Test)) { allSubs = allSubs.Where(s => SubjectMatch.MatchLiteral(opts.Test, s.Subject)).ToList(); } var total = allSubs.Count; var numSubs = server.GetAccounts() .Where(a => (string.IsNullOrEmpty(opts.Account) && a.Name != "$SYS") || a.Name == opts.Account) .Aggregate(0u, (sum, a) => sum + a.SubList.Count); var numCache = server.GetAccounts() .Where(a => (string.IsNullOrEmpty(opts.Account) && a.Name != "$SYS") || a.Name == opts.Account) .Sum(a => a.SubList.CacheCount); SubDetail[] details = []; if (opts.Subscriptions) { details = allSubs .Skip(opts.Offset) .Take(opts.Limit) .Select(s => new SubDetail { Subject = s.Subject, Queue = s.Queue ?? "", Sid = s.Sid, Msgs = Interlocked.Read(ref s.MessageCount), Max = s.MaxMessages, Cid = s.Client?.Id ?? 0, }) .ToArray(); } return new Subsz { Id = server.ServerId, Now = now, NumSubs = numSubs, NumCache = numCache, Total = total, Offset = opts.Offset, Limit = opts.Limit, Subs = details, }; } private static SubszOptions ParseQueryParams(HttpContext ctx) { var q = ctx.Request.Query; var opts = new SubszOptions(); if (q.TryGetValue("subs", out var subs)) opts.Subscriptions = subs == "true" || subs == "1" || subs == "detail"; if (q.TryGetValue("offset", out var offset) && int.TryParse(offset, out var o)) opts.Offset = o; if (q.TryGetValue("limit", out var limit) && int.TryParse(limit, out var l)) opts.Limit = l; if (q.TryGetValue("acc", out var acc)) opts.Account = acc.ToString(); if (q.TryGetValue("test", out var test)) opts.Test = test.ToString(); return opts; } }