Skip to content

Commit 0eb9e50

Browse files
committed
feat(Telemetry): implement no-op telemetry client and runtime gate for mobile
- Introduced NoOpTelemetryClient to handle telemetry requests when telemetry is disabled on mobile. - Added TelemetryRuntimeGate to manage telemetry functionality based on mobile host status. - Updated various telemetry methods to return early if telemetry is disabled, improving performance and preventing unnecessary operations. - Enhanced existing telemetry methods to respect the new runtime gate, ensuring consistent behavior across the telemetry system.
1 parent 5890c09 commit 0eb9e50

11 files changed

Lines changed: 155 additions & 0 deletions

Telemetry/Consent/TelemetryConsentStore.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ internal static class TelemetryConsentStore
1010

1111
internal static TelemetryConsentDocument Snapshot()
1212
{
13+
if (TelemetryRuntimeGate.IsDisabled)
14+
return new();
15+
1316
lock (Sync)
1417
{
1518
EnsureLoaded();
@@ -19,6 +22,9 @@ internal static TelemetryConsentDocument Snapshot()
1922

2023
internal static TelemetryApplicantConsent GetApplicantConsent(string applicantId)
2124
{
25+
if (TelemetryRuntimeGate.IsDisabled)
26+
return new() { Consent = TelemetryConsentState.Denied };
27+
2228
lock (Sync)
2329
{
2430
EnsureLoaded();
@@ -28,6 +34,9 @@ internal static TelemetryApplicantConsent GetApplicantConsent(string applicantId
2834

2935
internal static bool IsRequestGranted(TelemetryApplicant applicant, TelemetryRequest request)
3036
{
37+
if (TelemetryRuntimeGate.IsDisabled)
38+
return false;
39+
3140
lock (Sync)
3241
{
3342
EnsureLoaded();
@@ -42,6 +51,9 @@ internal static bool IsSharedContributionGranted(
4251
string contributorModId,
4352
string contributionId)
4453
{
54+
if (TelemetryRuntimeGate.IsDisabled)
55+
return false;
56+
4557
lock (Sync)
4658
{
4759
EnsureLoaded();
@@ -57,6 +69,9 @@ public static void SetApplicantConsent(
5769
TelemetryConsentState state,
5870
IEnumerable<string>? grantedRequests = null)
5971
{
72+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
73+
return;
74+
6075
lock (Sync)
6176
{
6277
EnsureLoaded();
@@ -85,6 +100,9 @@ public static void SetSharedContributionConsent(
85100
string contributionId,
86101
bool granted)
87102
{
103+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
104+
return;
105+
88106
lock (Sync)
89107
{
90108
EnsureLoaded();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Text.Json.Nodes;
2+
3+
namespace STS2RitsuLib.Telemetry
4+
{
5+
internal sealed class NoOpTelemetryClient(string applicantId) : ITelemetryClient
6+
{
7+
public string ApplicantId { get; } = applicantId;
8+
9+
public bool IsEnabled(string requestId)
10+
{
11+
return false;
12+
}
13+
14+
public void Capture(
15+
string eventName,
16+
string requestId,
17+
IReadOnlyDictionary<string, object?>? properties = null)
18+
{
19+
}
20+
21+
public void CapturePayload(
22+
string eventName,
23+
string requestId,
24+
JsonNode payload,
25+
IReadOnlyDictionary<string, object?>? properties = null)
26+
{
27+
}
28+
29+
public void CaptureException(
30+
Exception exception,
31+
IReadOnlyDictionary<string, object?>? properties = null)
32+
{
33+
}
34+
}
35+
}

Telemetry/Core/TelemetryApi.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public static class TelemetryApi
1616
public static ITelemetryClient GetClient(string applicantId)
1717
{
1818
ArgumentException.ThrowIfNullOrWhiteSpace(applicantId);
19+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
20+
return new NoOpTelemetryClient(applicantId);
21+
1922
return new TelemetryClient(applicantId);
2023
}
2124

@@ -29,6 +32,9 @@ public static void CaptureVanillaRunHistory(
2932
JsonNode? applicantPayload = null,
3033
IReadOnlyDictionary<string, object?>? properties = null)
3134
{
35+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
36+
return;
37+
3238
RunHistoryTelemetryCollector.CaptureVanillaRunHistory(
3339
applicantId,
3440
runHistory,

Telemetry/Core/TelemetryRegistry.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public static class TelemetryRegistry
2323
public static void RegisterApplicant(TelemetryApplicant applicant)
2424
{
2525
ArgumentNullException.ThrowIfNull(applicant);
26+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
27+
return;
28+
2629
ArgumentException.ThrowIfNullOrWhiteSpace(applicant.ApplicantId);
2730
ArgumentException.ThrowIfNullOrWhiteSpace(applicant.OwnerModId);
2831
ArgumentException.ThrowIfNullOrWhiteSpace(applicant.DisplayName);
@@ -45,6 +48,9 @@ public static void RegisterApplicant(TelemetryApplicant applicant)
4548
public static void RegisterContributionProvider(ITelemetryContributionProvider provider)
4649
{
4750
ArgumentNullException.ThrowIfNull(provider);
51+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
52+
return;
53+
4854
ArgumentException.ThrowIfNullOrWhiteSpace(provider.ContributorModId);
4955
ArgumentException.ThrowIfNullOrWhiteSpace(provider.ContributionId);
5056
lock (Sync)

Telemetry/Core/TelemetryRuntime.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ internal static class TelemetryRuntime
2020
/// </summary>
2121
internal static void CaptureStartupSnapshot()
2222
{
23+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
24+
return;
25+
2326
lock (Sync)
2427
{
2528
if (_startupSnapshot != null)
@@ -42,6 +45,9 @@ internal static void CaptureStartupSnapshot()
4245
/// </summary>
4346
internal static void ReplayStartupSnapshotToAuthorizedApplicants()
4447
{
48+
if (TelemetryRuntimeGate.IsDisabled)
49+
return;
50+
4551
foreach (var applicant in TelemetryRegistry.GetApplicants())
4652
ReplayStartupSnapshotToApplicant(applicant.ApplicantId);
4753
}
@@ -52,6 +58,9 @@ internal static void ReplayStartupSnapshotToAuthorizedApplicants()
5258
/// </summary>
5359
internal static void RefreshStartupModInventorySnapshot(string reason)
5460
{
61+
if (TelemetryRuntimeGate.IsDisabled)
62+
return;
63+
5564
lock (Sync)
5665
{
5766
if (_startupSnapshot == null)
@@ -72,6 +81,9 @@ internal static void RefreshStartupModInventorySnapshot(string reason)
7281
/// </summary>
7382
internal static void ReplayStartupSnapshotToApplicant(string applicantId)
7483
{
84+
if (TelemetryRuntimeGate.IsDisabled)
85+
return;
86+
7587
StartupTelemetrySnapshot snapshot;
7688

7789
lock (Sync)
@@ -105,6 +117,9 @@ internal static void ReplayStartupSnapshotToApplicant(string applicantId)
105117
/// </summary>
106118
internal static void ResetStartupDeliveryForDiscardedEvents(IEnumerable<TelemetryEnvelope> events)
107119
{
120+
if (TelemetryRuntimeGate.IsDisabled)
121+
return;
122+
108123
var discardedKeys = events
109124
.Select(BuildStartupDeliveryKey)
110125
.Where(key => key != null)
@@ -126,6 +141,9 @@ internal static void ResetStartupDeliveryForDiscardedEvents(IEnumerable<Telemetr
126141
/// </summary>
127142
internal static void MarkStartupDeliveryConfirmed(IEnumerable<TelemetryEnvelope> events)
128143
{
144+
if (TelemetryRuntimeGate.IsDisabled)
145+
return;
146+
129147
var confirmedKeys = events
130148
.Select(BuildStartupDeliveryKey)
131149
.Where(key => key != null)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using STS2RitsuLib.Platform;
2+
3+
namespace STS2RitsuLib.Telemetry
4+
{
5+
internal static class TelemetryRuntimeGate
6+
{
7+
internal const string MobileDisabledReason = "Telemetry is disabled on mobile hosts.";
8+
9+
private static readonly Lock Sync = new();
10+
private static bool _loggedMobileDisabled;
11+
12+
internal static bool IsDisabled => RitsuLibMobileSteamRuntime.SuppressNativeSteamIntegration;
13+
14+
internal static bool TryNoOpForDisabledMobile()
15+
{
16+
if (!IsDisabled)
17+
return false;
18+
19+
LogDisabledOnce();
20+
return true;
21+
}
22+
23+
internal static void LogDisabledOnce()
24+
{
25+
if (!IsDisabled)
26+
return;
27+
28+
lock (Sync)
29+
{
30+
if (_loggedMobileDisabled)
31+
return;
32+
33+
_loggedMobileDisabled = true;
34+
}
35+
36+
RitsuLibFramework.Logger.Info(
37+
"[Telemetry] Telemetry is disabled on mobile hosts; telemetry APIs will run as no-op.");
38+
}
39+
}
40+
}

Telemetry/Diagnostics/DiagnosticsTelemetryCollector.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ internal static void CaptureExceptionForAuthorizedApplicants(Exception exception
6262
{
6363
ArgumentNullException.ThrowIfNull(exception);
6464
ArgumentException.ThrowIfNullOrWhiteSpace(source);
65+
if (TelemetryRuntimeGate.IsDisabled)
66+
return;
6567

6668
try
6769
{
@@ -100,6 +102,9 @@ internal static void CaptureExceptionForAuthorizedApplicants(Exception exception
100102

101103
internal static void InitializeGlobalExceptionHandlers()
102104
{
105+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
106+
return;
107+
103108
lock (Sync)
104109
{
105110
if (_globalHandlersInitialized)

Telemetry/Integration/RitsuLibTelemetryBootstrap.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ internal static void Initialize()
2424
return;
2525

2626
_initialized = true;
27+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
28+
return;
29+
2730
DiagnosticsTelemetryCollector.InitializeGlobalExceptionHandlers();
2831
RitsuLibFramework.SubscribeLifecycle<RunEndedEvent>(RunHistoryTelemetryCollector.CaptureEndedRun);
2932
RitsuLibFramework.SubscribeLifecycleOnce<MainMenuReadyEvent>(_ => InitializeMainMenuTelemetry());

Telemetry/Integration/RitsuLibTelemetryConfiguration.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ internal static class RitsuLibTelemetryConfiguration
66

77
internal static ITelemetryAdapter CreateAdapter()
88
{
9+
if (TelemetryRuntimeGate.IsDisabled)
10+
return new DisabledTelemetryAdapter(TelemetryRuntimeGate.MobileDisabledReason);
11+
912
return new HttpJsonTelemetryAdapter(DefaultIngestEndpoint);
1013
}
1114
}

Telemetry/Queue/TelemetryQueue.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ internal static class TelemetryQueue
1111

1212
internal static void Enqueue(TelemetryEnvelope envelope)
1313
{
14+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
15+
return;
16+
1417
lock (Sync)
1518
{
1619
var doc = ReadQueue(envelope.ApplicantId);
@@ -25,6 +28,9 @@ internal static void Enqueue(TelemetryEnvelope envelope)
2528

2629
public static async Task FlushApplicantAsync(string applicantId, CancellationToken cancellationToken = default)
2730
{
31+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
32+
return;
33+
2834
TelemetryApplicant applicant;
2935

3036
lock (Sync)
@@ -133,12 +139,18 @@ public static async Task FlushApplicantAsync(string applicantId, CancellationTok
133139

134140
public static async Task FlushAllAsync(CancellationToken cancellationToken = default)
135141
{
142+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
143+
return;
144+
136145
foreach (var applicant in TelemetryRegistry.GetApplicants())
137146
await FlushApplicantAsync(applicant.ApplicantId, cancellationToken);
138147
}
139148

140149
public static void ClearApplicant(string applicantId)
141150
{
151+
if (TelemetryRuntimeGate.TryNoOpForDisabledMobile())
152+
return;
153+
142154
lock (Sync)
143155
{
144156
var doc = ReadQueue(applicantId);
@@ -150,6 +162,9 @@ public static void ClearApplicant(string applicantId)
150162

151163
public static int GetQueuedEventCount(string applicantId)
152164
{
165+
if (TelemetryRuntimeGate.IsDisabled)
166+
return 0;
167+
153168
lock (Sync)
154169
{
155170
return ReadQueue(applicantId).Events.Count;

0 commit comments

Comments
 (0)