Files
deepdrft/DeepDrftPublic.Client/Services/BeaconInterop.cs
T
daniel-c-harvey dbd90ee52a feat(phase-16): anonymous play & share telemetry substrate (wave 16.1)
Player-service play-session tracker (floor + 3-bucket classify), SharePopover share tracker with debounce, sendBeacon interop, proxied rate-limited POST api/event/{play,share}, append-only event logs + incremental play_counter with server-side release resolution. Migration authored, not applied. No anonId, no read surface.
2026-06-19 12:59:00 -04:00

61 lines
1.9 KiB
C#

using Microsoft.JSInterop;
namespace DeepDrftPublic.Client.Services;
/// <summary>
/// Thin C# wrapper over the <c>window.DeepDrftBeacon</c> TS interop (Phase 16 §2.2). Wraps the
/// <c>navigator.sendBeacon</c> POST and the page-unload registration so the rest of the client never
/// touches <see cref="IJSRuntime"/> string identifiers directly. All calls are best-effort: a JS
/// failure (module not yet loaded, interop unavailable during prerender) is swallowed — telemetry must
/// never throw into the UI or the playback path.
/// </summary>
public sealed class BeaconInterop
{
private readonly IJSRuntime _js;
public BeaconInterop(IJSRuntime js)
{
_js = js;
}
/// <summary>Queue a fire-and-forget POST of a JSON body to the given absolute URL.</summary>
public async Task SendAsync(string url, string json)
{
try
{
await _js.InvokeAsync<bool>("DeepDrftBeacon.send", url, json);
}
catch
{
// Module not loaded / not interactive yet — drop the event silently.
}
}
/// <summary>Register a .NET unload callback (fires on pagehide / visibility→hidden) under a key.</summary>
public async Task RegisterUnloadAsync<T>(string key, DotNetObjectReference<T> dotNetRef, string methodName)
where T : class
{
try
{
await _js.InvokeVoidAsync("DeepDrftBeacon.registerUnload", key, dotNetRef, methodName);
}
catch
{
// Best-effort — without the unload handler, mid-play tab-close simply isn't recorded.
}
}
/// <summary>Detach a previously-registered unload callback.</summary>
public async Task UnregisterUnloadAsync(string key)
{
try
{
await _js.InvokeVoidAsync("DeepDrftBeacon.unregisterUnload", key);
}
catch
{
// Disposal best-effort.
}
}
}