Files
nexus/backend/Services/TaskBoardCursorCodec.cs
T
AzuTear f5552218bc
CI - Build & Test / Backend (.NET) (push) Successful in 42s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m46s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Successful in 56s
feat: ship agent-first mission control v0.2.57
2026-07-31 22:39:47 +02:00

73 lines
2.3 KiB
C#

using System.Globalization;
using System.Text;
namespace Nexus.Api.Services;
internal readonly record struct TaskBoardCursorPosition(
DateTimeOffset UpdatedAt,
Guid Id);
internal static class TaskBoardCursorCodec
{
private const string Version = "v1";
private const int MaximumEncodedLength = 128;
public static string Encode(DateTimeOffset updatedAt, Guid id)
{
var payload = string.Create(
CultureInfo.InvariantCulture,
$"{Version}|{updatedAt.UtcDateTime.Ticks}|{id:N}");
return Convert.ToBase64String(Encoding.UTF8.GetBytes(payload))
.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
}
public static bool TryDecode(string? cursor, out TaskBoardCursorPosition position)
{
position = default;
if (string.IsNullOrWhiteSpace(cursor) || cursor.Length > MaximumEncodedLength)
return false;
try
{
var normalized = cursor
.Replace('-', '+')
.Replace('_', '/');
normalized = (normalized.Length % 4) switch
{
0 => normalized,
2 => normalized + "==",
3 => normalized + "=",
_ => throw new FormatException("Invalid Base64Url length.")
};
var payload = Encoding.UTF8.GetString(Convert.FromBase64String(normalized));
var parts = payload.Split('|');
if (parts.Length != 3
|| !string.Equals(parts[0], Version, StringComparison.Ordinal)
|| !long.TryParse(parts[1], NumberStyles.None, CultureInfo.InvariantCulture, out var utcTicks)
|| !Guid.TryParseExact(parts[2], "N", out var id))
{
return false;
}
var updatedAt = new DateTimeOffset(utcTicks, TimeSpan.Zero);
position = new TaskBoardCursorPosition(updatedAt, id);
return true;
}
catch (Exception exception) when (
exception is FormatException
or ArgumentOutOfRangeException
or DecoderFallbackException)
{
return false;
}
}
}
public sealed class InvalidTaskBoardCursorException()
: FormatException("The Done cursor is invalid or unsupported.");