More efficient session validity checks. Jellyfin session detection.

This commit is contained in:
2024-12-06 21:49:43 +01:00
parent a0f6870493
commit 9b6a93cda3
5 changed files with 90 additions and 67 deletions

View File

@@ -1,7 +1,5 @@
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using Cinema.Webshare;
@@ -17,6 +15,7 @@ public sealed class Session
private static readonly Uri WebshareApiUri = LinkGenerator.WebshareApiUri;
private static readonly TimeSpan InitialLoginBackoff = new TimeSpan(4 * TimeSpan.TicksPerSecond);
private static readonly TimeSpan MaxLoginBackoff = new TimeSpan(8 * TimeSpan.TicksPerMinute);
private static readonly TimeSpan TokenValidPeriod = new TimeSpan(120 * TimeSpan.TicksPerSecond);
private readonly string _userName;
private readonly string _password;
@@ -26,6 +25,7 @@ public sealed class Session
private DateTime _nextLoginTrial;
private TimeSpan _nextLoginBackoff;
private DateTime _nextValidTrial;
/// <summary>
/// Constructs a session from credentials and optionally a possibly live token.
@@ -74,52 +74,62 @@ public sealed class Session
/// <returns>True if the local instance data are valid. -or- False otherwise.</returns>
private async Task<bool> EnsureValidAsync(CancellationToken cancel)
{
if (!await RefreshUserDataAsync(cancel))
DateTime now = DateTime.Now;
if (_token != null && (_isVip ?? false) && now < _nextValidTrial)
// Fast track positive check
return true;
if (await RefreshUserDataAsync(cancel) && (_isVip ?? false))
{
DateTime now = DateTime.Now;
if (now > _nextLoginTrial)
// Valid VIP (slower with API check)
_nextValidTrial = now + TokenValidPeriod;
return true;
}
if (now > _nextLoginTrial)
{
// Try to log in again
string? token;
try
{
// Try to login again
string? token;
try
{
string? salt;
if ((salt = await GetSaltAsync(_userName, cancel)) == null
|| (token = await GetTokenAsync(_userName, _password.HashPassword(salt), cancel)) == null)
{
// Login failed
token = null;
}
}
catch
string? salt;
if ((salt = await GetSaltAsync(_userName, cancel)) == null
|| (token = await GetTokenAsync(_userName, _password.HashPassword(salt), cancel)) == null)
{
// Login failed
token = null;
}
if (token != null)
{
_nextLoginBackoff = InitialLoginBackoff;
_token = token;
if (await RefreshUserDataAsync(cancel))
return true;
}
else
{
TimeSpan nextBackoff = new TimeSpan(2 * _nextLoginBackoff.Ticks);
if (nextBackoff > MaxLoginBackoff)
nextBackoff = MaxLoginBackoff;
_nextLoginTrial = now + nextBackoff;
}
}
catch
{
token = null;
}
_token = null;
_isVip = null;
_vipDaysLeft = null;
return false;
if (token != null && await RefreshUserDataAsync(cancel) && (_isVip ?? false))
{
// Valid token with VIP
_nextLoginBackoff = InitialLoginBackoff;
_token = token;
_nextValidTrial = now + TokenValidPeriod;
return true;
}
else
{
// Invalid, no token or not VIP ...
TimeSpan nextBackoff = new TimeSpan(2 * _nextLoginBackoff.Ticks);
if (nextBackoff > MaxLoginBackoff)
nextBackoff = MaxLoginBackoff;
_nextLoginTrial = now + nextBackoff;
}
}
else
return true;
// ... still invalid, no token or not VIP
_token = null;
_isVip = null;
_vipDaysLeft = null;
return false;
}
/// <summary>