Untis-API Optimierung.

This commit is contained in:
2026-08-24 22:33:30 +02:00
parent 1db16f8b69
commit 17475a781f
9 changed files with 109 additions and 53 deletions
+8 -10
View File
@@ -9,6 +9,7 @@ public sealed class WebUntisClient : IAsyncDisposable
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
private static readonly UTF8Encoding StrictUtf8 = new(false, true);
private static readonly TimeSpan LogoutTimeout = TimeSpan.FromSeconds(2);
private readonly HttpClient _http;
private readonly WebUntisOptions _options;
private readonly SemaphoreSlim _sessionGate = new(1, 1);
@@ -177,7 +178,7 @@ public sealed class WebUntisClient : IAsyncDisposable
Entities(entry, "ro"), entry.Clone())).ToList();
}, cancellationToken);
public Task<UntisStudentAbsenceReport> GetStudentAbsencesAsync(int studentKey, int startDate, int endDate,
public Task<IReadOnlyList<UntisStudentAbsence>> GetAbsencesAsync(int startDate, int endDate,
CancellationToken cancellationToken) => WithSessionAsync(async sessionId =>
{
var result = await RpcAsync("getTimetableWithAbsences", new
@@ -187,8 +188,7 @@ public sealed class WebUntisClient : IAsyncDisposable
if (!TryProperty(result, "periodsWithAbsences", out var periods) || periods.ValueKind != JsonValueKind.Array)
throw new WebUntisException("WebUntis hat keine gültigen Fehlzeiten-Daten geliefert.");
var absences = periods.EnumerateArray()
.Where(entry => OptionalInt(entry, "studentId") == studentKey)
return (IReadOnlyList<UntisStudentAbsence>)periods.EnumerateArray()
.Select(entry => new UntisStudentAbsence(
RequiredInt(entry, "studentId"),
RequiredInt(entry, "date"),
@@ -205,9 +205,6 @@ public sealed class WebUntisClient : IAsyncDisposable
.OrderBy(entry => entry.Date)
.ThenBy(entry => entry.StartTime)
.ToList();
return new UntisStudentAbsenceReport(studentKey, startDate, endDate, absences.Count,
absences.Sum(entry => entry.AbsentMinutes), absences);
}, cancellationToken);
public Task<IReadOnlyList<UntisClassRegisterEntry>> GetClassRegisterEntriesAsync(int studentId,
@@ -346,14 +343,15 @@ public sealed class WebUntisClient : IAsyncDisposable
private async Task TryLogoutAsync(string sessionId)
{
try { await RpcAsync("logout", new { }, sessionId, CancellationToken.None); }
using var timeout = new CancellationTokenSource(LogoutTimeout);
try { await RpcAsync("logout", new { }, sessionId, timeout.Token).ConfigureAwait(false); }
catch { /* Ein fehlgeschlagener Logout darf Abrufe und Shutdown nicht fehlschlagen lassen. */ }
}
public async ValueTask DisposeAsync()
{
string? sessionId;
await _sessionGate.WaitAsync();
await _sessionGate.WaitAsync().ConfigureAwait(false);
try
{
if (_disposed) return;
@@ -368,8 +366,8 @@ public sealed class WebUntisClient : IAsyncDisposable
// Außerhalb des Gates warten: ein bereits laufender Timer-Callback könnte selbst gerade
// auf dieses Gate warten und würde sonst den Shutdown blockieren.
await _sessionExpiryTimer.DisposeAsync();
if (sessionId is not null) await TryLogoutAsync(sessionId);
await _sessionExpiryTimer.DisposeAsync().ConfigureAwait(false);
if (sessionId is not null) await TryLogoutAsync(sessionId).ConfigureAwait(false);
}
private TimeSpan SessionIdleTimeout =>