Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 04d6d9e

Browse files
Adding a user guid to to UsageModel
This is a cherry pick of relevant changes to code using e6a2f1e as a reference Co-authored-by: Steven Kirk <[email protected]>
1 parent 9eb8dfb commit 04d6d9e

File tree

5 files changed

+96
-12
lines changed

5 files changed

+96
-12
lines changed

src/GitHub.Exports/Models/UsageModel.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace GitHub.Models
55
{
66
public class UsageModel
77
{
8+
public Guid Guid { get; set; }
89
public bool IsGitHubUser { get; set; }
910
public bool IsEnterpriseUser { get; set; }
1011
public string AppVersion { get; set; }
@@ -40,9 +41,9 @@ public class UsageModel
4041
public int NumberOfPRReviewDiffViewInlineCommentOpen { get; set; }
4142
public int NumberOfPRReviewDiffViewInlineCommentPost { get; set; }
4243

43-
public UsageModel Clone(bool includeWeekly, bool includeMonthly)
44+
public UsageModel Clone(Guid guid, bool includeWeekly, bool includeMonthly)
4445
{
45-
var result = new UsageModel();
46+
var result = Create(guid);
4647
var properties = result.GetType().GetRuntimeProperties();
4748

4849
foreach (var property in properties)
@@ -63,5 +64,13 @@ public UsageModel Clone(bool includeWeekly, bool includeMonthly)
6364

6465
return result;
6566
}
67+
68+
public static UsageModel Create(Guid guid)
69+
{
70+
return new UsageModel
71+
{
72+
Guid = guid
73+
};
74+
}
6675
}
6776
}

src/GitHub.Exports/Services/IUsageService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public interface IUsageService
2929
/// <param name="lastUpdated">The last updated date.</param>
3030
/// <returns>True if the last updated date is the same month as today; otherwise false.</returns>
3131
bool IsSameMonth(DateTimeOffset lastUpdated);
32+
33+
/// <summary>
34+
/// Gets a GUID that anonymously represents the user.
35+
/// </summary>
36+
Task<Guid> GetUserGuid();
3237

3338
/// <summary>
3439
/// Starts a timer.

src/GitHub.VisualStudio/Services/UsageService.cs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
using GitHub.Helpers;
9+
using GitHub.Logging;
910
using GitHub.Models;
11+
using Serilog;
1012
using Task = System.Threading.Tasks.Task;
1113

1214
namespace GitHub.Services
@@ -15,16 +17,60 @@ namespace GitHub.Services
1517
public class UsageService : IUsageService
1618
{
1719
const string StoreFileName = "ghfvs.usage";
20+
const string UserStoreFileName = "user.json";
21+
private static readonly ILogger log = LogManager.ForContext<UsageService>();
1822
static readonly Calendar cal = CultureInfo.InvariantCulture.Calendar;
1923
readonly IGitHubServiceProvider serviceProvider;
2024
string storePath;
25+
string userStorePath;
26+
Guid? userGuid;
2127

2228
[ImportingConstructor]
2329
public UsageService(IGitHubServiceProvider serviceProvider)
2430
{
2531
this.serviceProvider = serviceProvider;
2632
}
2733

34+
public async Task<Guid> GetUserGuid()
35+
{
36+
await Initialize();
37+
38+
if (!userGuid.HasValue)
39+
{
40+
try
41+
{
42+
if (File.Exists(userStorePath))
43+
{
44+
var json = await ReadAllTextAsync(userStorePath);
45+
var data = SimpleJson.DeserializeObject<UserData>(json);
46+
userGuid = data.UserGuid;
47+
}
48+
}
49+
catch (Exception ex)
50+
{
51+
log.Error(ex, "Failed reading user metrics GUID");
52+
}
53+
}
54+
55+
if (!userGuid.HasValue || userGuid.Value == Guid.Empty)
56+
{
57+
userGuid = Guid.NewGuid();
58+
59+
try
60+
{
61+
var data = new UserData { UserGuid = userGuid.Value };
62+
var json = SimpleJson.SerializeObject(data);
63+
await WriteAllTextAsync(userStorePath, json);
64+
}
65+
catch (Exception ex)
66+
{
67+
log.Error(ex, "Failed reading writing metrics GUID");
68+
}
69+
}
70+
71+
return userGuid.Value;
72+
}
73+
2874
public bool IsSameDay(DateTimeOffset lastUpdated)
2975
{
3076
return lastUpdated.Date == DateTimeOffset.Now.Date;
@@ -46,7 +92,7 @@ public IDisposable StartTimer(Func<Task> callback, TimeSpan dueTime, TimeSpan pe
4692
async _ =>
4793
{
4894
try { await callback(); }
49-
catch { /* log.Warn("Failed submitting usage data", ex); */ }
95+
catch (Exception ex) { log.Warning(ex, "Failed submitting usage data"); }
5096
},
5197
null,
5298
dueTime,
@@ -79,9 +125,9 @@ public async Task WriteLocalData(UsageData data)
79125
var json = SimpleJson.SerializeObject(data);
80126
await WriteAllTextAsync(storePath, json);
81127
}
82-
catch
128+
catch (Exception ex)
83129
{
84-
// log.Warn("Failed to write usage data", ex);
130+
log.Warning(ex, "Failed to write usage data");
85131
}
86132
}
87133

@@ -96,6 +142,10 @@ async Task Initialize()
96142
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
97143
program.ApplicationName,
98144
StoreFileName);
145+
userStorePath = Path.Combine(
146+
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
147+
program.ApplicationName,
148+
UserStoreFileName);
99149
}
100150
}
101151

@@ -132,5 +182,10 @@ static int GetIso8601WeekOfYear(DateTimeOffset time)
132182
// Return the week of our adjusted day
133183
return cal.GetWeekOfYear(time.UtcDateTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
134184
}
185+
186+
class UserData
187+
{
188+
public Guid UserGuid { get; set; }
189+
}
135190
}
136191
}

src/GitHub.VisualStudio/Services/UsageTracker.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ async Task SendUsage(UsageModel usage, bool weekly, bool monthly)
144144
usage.IsEnterpriseUser = true;
145145
}
146146

147-
var model = usage.Clone(weekly, monthly);
147+
var guid = await service.GetUserGuid();
148+
var model = usage.Clone(guid, weekly, monthly);
148149
await client.PostUsage(model);
149150
}
150151

test/UnitTests/GitHub.VisualStudio/Services/UsageTrackerTests.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,16 @@ public async Task TickShouldSendDataIfDifferentDay()
101101
[Test]
102102
public async Task NonWeeklyOrMonthlyCountersShouldBeZeroed()
103103
{
104-
var service = CreateUsageService(new UsageModel
104+
var model = new UsageModel
105105
{
106+
Guid = Guid.NewGuid(),
106107
NumberOfStartups = 1,
107108
NumberOfStartupsWeek = 1,
108109
NumberOfStartupsMonth = 1,
109110
NumberOfClones = 1,
110-
}, sameDay: false);
111+
};
112+
113+
var service = CreateUsageService(model, sameDay: false);
111114
Func<Task> tick = null;
112115

113116
service.WhenForAnyArgs(x => x.StartTimer(null, new TimeSpan(), new TimeSpan()))
@@ -120,6 +123,7 @@ public async Task NonWeeklyOrMonthlyCountersShouldBeZeroed()
120123

121124
await service.Received().WriteLocalData(
122125
Arg.Is<UsageData>(x =>
126+
x.Model.Guid == model.Guid &&
123127
x.Model.NumberOfStartups == 0 &&
124128
x.Model.NumberOfStartupsWeek == 2 &&
125129
x.Model.NumberOfStartupsMonth == 2 &&
@@ -129,13 +133,16 @@ await service.Received().WriteLocalData(
129133
[Test]
130134
public async Task NonMonthlyCountersShouldBeZeroed()
131135
{
132-
var service = CreateUsageService(new UsageModel
136+
var model = new UsageModel
133137
{
138+
Guid = Guid.NewGuid(),
134139
NumberOfStartups = 1,
135140
NumberOfStartupsWeek = 1,
136141
NumberOfStartupsMonth = 1,
137142
NumberOfClones = 1,
138-
}, sameDay: false, sameWeek: false);
143+
};
144+
145+
var service = CreateUsageService(model, sameDay: false, sameWeek: false);
139146
Func<Task> tick = null;
140147

141148
service.WhenForAnyArgs(x => x.StartTimer(null, new TimeSpan(), new TimeSpan()))
@@ -148,6 +155,7 @@ public async Task NonMonthlyCountersShouldBeZeroed()
148155

149156
await service.Received().WriteLocalData(
150157
Arg.Is<UsageData>(x =>
158+
x.Model.Guid == model.Guid &&
151159
x.Model.NumberOfStartups == 0 &&
152160
x.Model.NumberOfStartupsWeek == 0 &&
153161
x.Model.NumberOfStartupsMonth == 2 &&
@@ -157,13 +165,16 @@ await service.Received().WriteLocalData(
157165
[Test]
158166
public async Task AllCountersShouldBeZeroed()
159167
{
160-
var service = CreateUsageService(new UsageModel
168+
var model = new UsageModel
161169
{
170+
Guid = Guid.NewGuid(),
162171
NumberOfStartups = 1,
163172
NumberOfStartupsWeek = 1,
164173
NumberOfStartupsMonth = 1,
165174
NumberOfClones = 1,
166-
}, sameDay: false, sameWeek: false, sameMonth: false);
175+
};
176+
177+
var service = CreateUsageService(model, sameDay: false, sameWeek: false, sameMonth: false);
167178
Func<Task> tick = null;
168179

169180
service.WhenForAnyArgs(x => x.StartTimer(null, new TimeSpan(), new TimeSpan()))
@@ -176,6 +187,7 @@ public async Task AllCountersShouldBeZeroed()
176187

177188
await service.Received().WriteLocalData(
178189
Arg.Is<UsageData>(x =>
190+
x.Model.Guid == model.Guid &&
179191
x.Model.NumberOfStartups == 0 &&
180192
x.Model.NumberOfStartupsWeek == 0 &&
181193
x.Model.NumberOfStartupsMonth == 0 &&
@@ -233,12 +245,14 @@ static IGitHubServiceProvider CreateServiceProvider(bool hasMetricsService = tru
233245
var connectionManager = Substitute.For<IConnectionManager>();
234246
var metricsService = Substitute.For<IMetricsService>();
235247
var packageSettings = Substitute.For<IPackageSettings>();
248+
var vsservices = Substitute.For<IVSServices>();
236249

237250
connectionManager.Connections.Returns(new ObservableCollectionEx<IConnection>());
238251
packageSettings.CollectMetrics.Returns(true);
239252

240253
result.GetService<IConnectionManager>().Returns(connectionManager);
241254
result.GetService<IPackageSettings>().Returns(packageSettings);
255+
result.GetService<IVSServices>().Returns(vsservices);
242256
result.TryGetService<IMetricsService>().Returns(hasMetricsService ? metricsService : null);
243257

244258
return result;

0 commit comments

Comments
 (0)