Code review

This commit is contained in:
pleb
2026-04-18 21:40:23 -07:00
parent f1a853691c
commit 2ad7b50f65
6 changed files with 87 additions and 93 deletions
+25 -71
View File
@@ -5,38 +5,26 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
#if false
using BeatLeader.Utils;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
#endif
using IPALogger = IPA.Logging.Logger;
namespace Setlist
{
/// <summary>
/// Parses BeatLeader sync URLs and checks ownership via GET /user/playlists.
/// Reuses BeatLeader's sign-in by piggy-backing on Unity's process-wide
/// <see cref="UnityWebRequest"/> cookie cache (the shipped 0.9.x BeatLeader
/// signs in with <see cref="UnityWebRequest"/>; cookies are global per host).
/// We block on BeatLeader's <c>Authentication._signedIn</c> via reflection so
/// we don't fire the request before the cookie is in the cache.
/// Parses BeatLeader-style sync URLs for logging. Ownership is determined in
/// <see cref="Plugin.FormatPlaylistLogLine"/> from playlist JSON only (no network).
/// </summary>
internal static class BeatLeaderPlaylistOwnership
{
private const string AuthenticationTypeName = "BeatLeader.API.Authentication";
private const string SignedInFieldName = "_signedIn";
private const float LoginWaitTimeoutSeconds = 90f;
private const float PlatformUserPollStepSeconds = 0.5f;
/// <summary>How long to wait for <see cref="PlatformLeaderboardsModel"/> to appear and populate <c>playerId</c> (plugin runs before menu init).</summary>
private const float PlatformUserWaitTimeoutSeconds = 30f;
private const float PlatformUserGetUserInfoRetrySeconds = 3f;
private const int RequestTimeoutSeconds = 30;
private sealed class UserPlaylistSummary
{
[JsonProperty("guid")]
public string Guid { get; set; }
}
internal static bool TryExtractBeatLeaderPlaylistGuid(string syncUrl, out string guid)
{
@@ -79,9 +67,8 @@ namespace Setlist
}
/// <summary>
/// Spawns a hidden coroutine runner that waits for BeatLeader sign-in,
/// fetches <c>/user/playlists</c>, then logs the per-playlist ownership.
/// Must be called from the Unity main thread (BSIPA's <c>OnApplicationStart</c> is fine).
/// Spawns a hidden coroutine runner that resolves the platform user id, then logs per-playlist
/// ownership from playlist JSON. Must be called from the Unity main thread (BSIPA <c>OnApplicationStart</c> is fine).
/// </summary>
internal static void ScheduleVerifyAndLog(
List<(string Title, bool HasSyncUrl, string BeatLeaderGuid, string OwnerId)> entries,
@@ -95,7 +82,7 @@ namespace Setlist
}
/// <summary>
/// Component that drives the verification coroutine; self-destroys when finished.
/// Component that drives the logging coroutine; self-destroys when finished.
/// </summary>
private sealed class OwnershipRunner : MonoBehaviour
{
@@ -119,54 +106,6 @@ namespace Setlist
? "platformUserId=(unknown)"
: $"platformUserId={platformUserId}");
HashSet<string> owned = null;
string failure = null;
if (_entries.Any(e => e.BeatLeaderGuid != null))
{
FieldInfo signedInField;
try
{
signedInField = ResolveSignedInField(_log);
}
catch (Exception ex)
{
signedInField = null;
failure = "reflecting BeatLeader Authentication failed: " + ex.Message;
}
if (signedInField != null)
{
var waitedSeconds = 0f;
while (!IsSignedIn(signedInField))
{
if (waitedSeconds >= LoginWaitTimeoutSeconds)
{
failure = $"BeatLeader login did not complete within {LoginWaitTimeoutSeconds:F0}s; "
+ "is the BeatLeader mod actually signing in (check BeatLeader log lines)?";
break;
}
yield return new WaitForSeconds(1f);
waitedSeconds += 1f;
}
if (failure == null)
{
var fetchEnumerator = FetchOwnedGuids(result =>
{
owned = result.OwnedGuids;
failure = result.Failure;
});
yield return StartCoroutine(fetchEnumerator);
}
}
}
if (owned == null && failure != null)
{
_log.Info("BeatLeader /user/playlists: " + failure);
}
foreach (var e in _entries)
{
_log.Info(Plugin.FormatPlaylistLogLine(
@@ -174,8 +113,7 @@ namespace Setlist
e.HasSyncUrl,
e.BeatLeaderGuid,
e.OwnerId,
platformUserId,
owned));
platformUserId));
}
Destroy(gameObject);
@@ -287,6 +225,21 @@ namespace Setlist
return last;
}
// SETLIST: Remove the entire #if false region below once we no longer need the old
// BeatLeader GET /user/playlists + login-wait verification path for reference.
#if false
private const string AuthenticationTypeName = "BeatLeader.API.Authentication";
private const string SignedInFieldName = "_signedIn";
private const float LoginWaitTimeoutSeconds = 90f;
private const int RequestTimeoutSeconds = 30;
private sealed class UserPlaylistSummary
{
[JsonProperty("guid")]
public string Guid { get; set; }
}
private struct FetchResult
{
public HashSet<string> OwnedGuids;
@@ -384,6 +337,7 @@ namespace Setlist
var asm = typeof(BeatLeaderPlaylistOwnership).Assembly;
return asm.GetName().Version?.ToString() ?? "0.0.0";
}
#endif
}
}
}