< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.Channels.NATS.NatsSubjectSchema
Assembly: AsyncResponse.Channels.NATS
File(s): /home/runner/work/AsyncResponse/AsyncResponse/src/Channels/AsyncResponse.Channels.NATS/NatsSubjectSchema.cs
Line coverage
100%
Covered lines: 18
Uncovered lines: 0
Coverable lines: 18
Total lines: 64
Line coverage: 100%
Branch coverage
100%
Covered branches: 8
Total branches: 8
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ResponseSubject(...)100%11100%
RecoveryKey(...)100%11100%
CorrelationIdFromRecoveryKey(...)100%22100%
Encode(...)100%11100%
Decode(...)100%66100%

File(s)

/home/runner/work/AsyncResponse/AsyncResponse/src/Channels/AsyncResponse.Channels.NATS/NatsSubjectSchema.cs

#LineLine coverage
 1using System.Text;
 2
 3namespace AsyncResponse.Channels.NATS;
 4
 5/// <summary>
 6/// The single source of truth for NATS subject and Key-Value key shapes used by the channel and the
 7/// recovery store. Correlation ids are arbitrary strings, but NATS subject tokens and KV keys accept
 8/// only a restricted character set, so ids are encoded with URL-safe Base64 (alphabet
 9/// <c>A–Z a–z 0–9 - _</c>, no padding) — every character of which is legal in both a subject token
 10/// and a KV key. Subject/key shapes are a storage contract: changing them orphans in-flight recovery
 11/// state.
 12/// </summary>
 313internal sealed class NatsSubjectSchema(string _subjectPrefix)
 14{
 15    /// <summary>The response subject a waiter subscribes to and a publisher requests on.</summary>
 316    public string ResponseSubject(string correlationId) => $"{_subjectPrefix}.response.{Encode(correlationId)}";
 17
 18    /// <summary>The Key-Value key under which a correlation id's recovery state is stored.</summary>
 319    public static string RecoveryKey(string correlationId) => Encode(correlationId);
 20
 21    /// <summary>
 22    /// Recovers the original correlation id from a recovery Key-Value key. Returns the key verbatim
 23    /// when it is not valid encoded content (e.g. a key written by an older/foreign producer).
 24    /// </summary>
 325    public static string CorrelationIdFromRecoveryKey(string recoveryKey) => Decode(recoveryKey) ?? recoveryKey;
 26
 27    /// <summary>
 28    /// Encodes an arbitrary string to a NATS-safe token using URL-safe Base64 without padding.
 29    /// Implemented over <see cref="Convert.ToBase64String(byte[])"/> so it works identically on every
 30    /// target framework.
 31    /// </summary>
 32    public static string Encode(string value)
 33    {
 334        ArgumentException.ThrowIfNullOrWhiteSpace(value);
 35
 336        var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(value));
 37        // '+' and '/' are illegal in NATS subject tokens / KV keys; '=' padding is dropped.
 338        return base64.Replace('+', '-').Replace('/', '_').TrimEnd('=');
 39    }
 40
 41    /// <summary>Decodes a token produced by <see cref="Encode"/>, or returns <c>null</c> when it is not decodable.</sum
 42    public static string? Decode(string token)
 43    {
 344        if (string.IsNullOrEmpty(token))
 345            return null;
 46
 347        var base64 = token.Replace('-', '+').Replace('_', '/');
 348        switch (base64.Length % 4)
 49        {
 250            case 2: base64 += "=="; break;
 251            case 3: base64 += "="; break;
 352            case 1: return null; // never produced by Encode
 53        }
 54
 55        try
 56        {
 357            return Encoding.UTF8.GetString(Convert.FromBase64String(base64));
 58        }
 359        catch (FormatException)
 60        {
 361            return null;
 62        }
 363    }
 64}