Skip to content

Commit 49a987d

Browse files
committed
feat: Implement system telemetry submission
1 parent fe16c61 commit 49a987d

File tree

4 files changed

+74
-3
lines changed

4 files changed

+74
-3
lines changed

Source/Menu/MainForm.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ orderby tool.Text
268268
ShowTimetableEnvironment();
269269

270270
CheckForUpdate();
271+
CheckForTelemetry();
271272

272273
if (!Initialized)
273274
{
@@ -347,6 +348,21 @@ public virtual void OnCheckUpdatesAgain(EventArgs e)
347348
CheckForUpdate();
348349
}
349350

351+
void CheckForTelemetry()
352+
{
353+
// DO NOT await this call as we want it to run in the background
354+
_ = TelemetryManager.SubmitIfDue(TelemetryType.System, () => new
355+
{
356+
SystemInfo.Application,
357+
SystemInfo.Runtime,
358+
SystemInfo.OperatingSystem,
359+
SystemInfo.InstalledMemoryMB,
360+
SystemInfo.CPUs,
361+
SystemInfo.GPUs,
362+
SystemInfo.Direct3DFeatureLevels
363+
});
364+
}
365+
350366
void LoadLanguage()
351367
{
352368
if (Settings.Language.Length > 0)

Source/Orts.Settings/Orts.Settings.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
1515
<DocumentationFile>..\..\Program\Orts.Settings.xml</DocumentationFile>
1616
</PropertyGroup>
17+
<ItemGroup>
18+
<Reference Include="System.Net.Http" />
19+
</ItemGroup>
1720
<ItemGroup>
1821
<Reference Include="GNU.Gettext, Version=1.1.5151.39896, Culture=neutral, processorArchitecture=MSIL">
1922
<SpecificVersion>False</SpecificVersion>

Source/Orts.Settings/TelemetryManager.cs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
using System;
1919
using System.Collections.Generic;
2020
using System.Diagnostics;
21-
using System.Net;
22-
using Newtonsoft.Json.Linq;
21+
using System.Net.Http;
22+
using System.Threading.Tasks;
23+
using Newtonsoft.Json;
2324
using ORTS.Common;
2425

2526
namespace ORTS.Settings
@@ -43,6 +44,7 @@ public class TelemetryManager
4344
internal static readonly DateTime StateDisabled = new DateTime(1899, 1, 2);
4445
internal static readonly DateTime StateEnabledMin = new DateTime(1900, 1, 1);
4546

47+
static readonly HttpClient HttpClient = new HttpClient();
4648
static readonly Dictionary<TelemetryType, TimeSpan> Frequency = new Dictionary<TelemetryType, TimeSpan>
4749
{
4850
{ TelemetryType.System, TimeSpan.FromDays(7) },
@@ -67,6 +69,8 @@ public TelemetryManager(TelemetrySettings settings)
6769
{
6870
RandomNumber1000.Value = new Random().Next(1, 1001);
6971
}
72+
73+
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"{ApplicationInfo.ProductName}/{VersionInfo.VersionOrBuild}");
7074
}
7175

7276
/// <summary>
@@ -95,5 +99,53 @@ public void SetState(TelemetryType type, TelemetryState state)
9599
State[type].Value = state == TelemetryState.Enabled ? StateEnabledMin : state == TelemetryState.Disabled ? StateDisabled : StateUndecided;
96100
}
97101
}
102+
103+
/// <summary>
104+
/// Returns true if the specified telemetry type is enabled and due to be sent.
105+
/// </summary>
106+
/// <param name="type">Which telemetry type to check</param>
107+
/// <returns>Whether to send the telemetry</returns>
108+
public bool IsDue(TelemetryType type)
109+
{
110+
Debug.Assert(State.ContainsKey(type), "Telemetry type is not valid");
111+
if (GetState(type) != TelemetryState.Enabled) return false;
112+
// If the frequency is not set, it is always due (i.e. not rate limited)
113+
if (!Frequency.ContainsKey(type)) return true;
114+
var lastPeriod = State[type].Value.Ticks / Frequency[type].Ticks;
115+
var thisPeriod = DateTime.Now.Ticks / Frequency[type].Ticks;
116+
return lastPeriod != thisPeriod;
117+
}
118+
119+
/// <summary>
120+
/// Submits the specified telemetry type if it is enabled and due to be sent.
121+
/// </summary>
122+
/// <param name="type">Which telemetry type to submit</param>
123+
/// <param name="generator">Function to generate the telemetry data</param>
124+
public async Task SubmitIfDue(TelemetryType type, Func<object> generator)
125+
{
126+
Debug.Assert(State.ContainsKey(type), "Telemetry type is not valid");
127+
if (!IsDue(type)) return;
128+
var url = $"{Settings.ServerURL}/api/collect/{type.ToString().ToLowerInvariant()}";
129+
var data = JsonConvert.SerializeObject(generator());
130+
try
131+
{
132+
await HttpClient.PostAsync(url, new StringContent(data, System.Text.Encoding.UTF8, "application/json"));
133+
SetSent(type);
134+
}
135+
catch (Exception)
136+
{
137+
// FIXME:
138+
}
139+
}
140+
141+
/// <summary>
142+
/// Sets the specified telemetry type as sent, recording the current date/time.
143+
/// </summary>
144+
/// <param name="type">Which telemetry type to set</param>
145+
public void SetSent(TelemetryType type)
146+
{
147+
Debug.Assert(State.ContainsKey(type), "Telemetry type is not valid");
148+
State[type].Value = DateTime.Now;
149+
}
98150
}
99151
}

Source/Orts.Settings/TelemetrySettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// COPYRIGHT 2009 - 2024 by the Open Rails project.
1+
// COPYRIGHT 2009 - 2024 by the Open Rails project.
22
//
33
// This file is part of Open Rails.
44
//

0 commit comments

Comments
 (0)