up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-24 09:07:40 +02:00
parent 150b3730ef
commit e6119cbe91
59 changed files with 1827 additions and 204 deletions

View File

@@ -2696,15 +2696,21 @@ var concelierTimelineEndpoint = app.MapGet("/obs/concelier/timeline", async (
var take = Math.Clamp(limit.GetValueOrDefault(10), 1, 100);
var startId = 0;
if (!string.IsNullOrWhiteSpace(cursor) && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out startId))
var candidateCursor = cursor ?? context.Request.Headers["Last-Event-ID"].FirstOrDefault();
if (!string.IsNullOrWhiteSpace(candidateCursor) && !int.TryParse(candidateCursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out startId))
{
return Results.BadRequest(new { error = "cursor must be integer" });
}
var logger = loggerFactory.CreateLogger("ConcelierTimeline");
context.Response.Headers.CacheControl = "no-store";
context.Response.Headers["X-Accel-Buffering"] = "no";
context.Response.ContentType = "text/event-stream";
// SSE retry hint (5s) to encourage clients to reconnect with cursor
await context.Response.WriteAsync("retry: 5000\n\n", cancellationToken).ConfigureAwait(false);
var now = timeProvider.GetUtcNow();
var events = Enumerable.Range(startId, take)
@@ -2723,13 +2729,14 @@ var concelierTimelineEndpoint = app.MapGet("/obs/concelier/timeline", async (
foreach (var (evt, idx) in events.Select((e, i) => (e, i)))
{
cancellationToken.ThrowIfCancellationRequested();
var id = startId + idx;
await context.Response.WriteAsync($"id: {id}\n", cancellationToken);
await context.Response.WriteAsync($"event: {evt.Type}\n", cancellationToken);
await context.Response.WriteAsync($"data: {JsonSerializer.Serialize(evt)}\n\n", cancellationToken);
await context.Response.WriteAsync($"id: {id}\n", cancellationToken).ConfigureAwait(false);
await context.Response.WriteAsync($"event: {evt.Type}\n", cancellationToken).ConfigureAwait(false);
await context.Response.WriteAsync($"data: {JsonSerializer.Serialize(evt)}\n\n", cancellationToken).ConfigureAwait(false);
}
await context.Response.Body.FlushAsync(cancellationToken);
await context.Response.Body.FlushAsync(cancellationToken).ConfigureAwait(false);
var nextCursor = startId + events.Count;
context.Response.Headers["X-Next-Cursor"] = nextCursor.ToString(CultureInfo.InvariantCulture);