Skip to content

Commit 6513d33

Browse files
Fallback tracking.
1 parent 0ca092b commit 6513d33

10 files changed

+109
-29
lines changed

sdk/Notifo.SDK/INotifoMobilePush.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// ==========================================================================
77

88
using System;
9+
using System.Net.Http;
910
using Notifo.SDK.PushEventProvider;
1011

1112
namespace Notifo.SDK
@@ -35,6 +36,11 @@ public partial interface INotifoMobilePush : INotifoClient
3536
/// </summary>
3637
ApiVersion ApiVersion { get; }
3738

39+
/// <summary>
40+
/// Indicates whether the client is configured.
41+
/// </summary>
42+
bool IsConfigured { get; }
43+
3844
/// <summary>
3945
/// Sets the API key to use.
4046
/// </summary>
@@ -73,6 +79,12 @@ public partial interface INotifoMobilePush : INotifoClient
7379
/// <param name="source">The source of the error.</param>
7480
void RaiseError(string error, Exception? exception, object? source);
7581

82+
/// <summary>
83+
/// Creates a HTTP client.
84+
/// </summary>
85+
/// <returns>The HTTP client.</returns>
86+
HttpClient CreateHttpClient();
87+
7688
/// <summary>
7789
/// Register for notifications on demand.
7890
/// </summary>

sdk/Notifo.SDK/NotifoMobilePush/ISeenNotificationsStore.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
// ==========================================================================
77

88
using System;
9+
using System.Collections.Generic;
910
using System.Threading.Tasks;
1011
using Notifo.SDK.Helpers;
1112

1213
namespace Notifo.SDK.NotifoMobilePush
1314
{
1415
internal interface ISeenNotificationsStore
1516
{
16-
ValueTask AddSeenNotificationIdsAsync(int maxCapacity, params Guid[] ids);
17+
ValueTask AddSeenNotificationIdsAsync(int maxCapacity, IEnumerable<Guid> ids);
1718

1819
ValueTask<SlidingSet<Guid>> GetSeenNotificationIdsAsync();
1920
}

sdk/Notifo.SDK/NotifoMobilePush/NotifoClientProvider.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ internal sealed class NotifoClientProvider
1818
private string apiUrl = "https://app.notifo.io";
1919
private INotifoClient? clientInstance;
2020

21+
public bool IsConfigured
22+
{
23+
get => !string.IsNullOrEmpty(apiKey) && !string.IsNullOrEmpty(apiUrl);
24+
}
25+
2126
public string? ApiKey
2227
{
2328
get => apiKey;

sdk/Notifo.SDK/NotifoMobilePush/NotifoMobilePushImplementation.ios.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal partial class NotifoMobilePushImplementation : NSObject
2828

2929
partial void SetupPlatform()
3030
{
31-
httpClient = clientProvider.CreateHttpClient();
31+
httpClient = CreateHttpClient();
3232
}
3333

3434
public INotifoMobilePush SetNotificationHandler(INotificationHandler? notificationHandler)

sdk/Notifo.SDK/NotifoMobilePush/NotifoMobilePushImplementation.shared.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ internal partial class NotifoMobilePushImplementation : INotifoMobilePush
8282
/// <inheritdoc/>
8383
public IUserClient User => clientProvider.Client.User;
8484

85+
/// <inheritdoc/>
86+
public bool IsConfigured => clientProvider.IsConfigured;
87+
8588
public NotifoMobilePushImplementation(Func<HttpClient> httpClientFactory,
8689
ISeenNotificationsStore seenNotificationsStore, ICommandQueue commandQueue)
8790
{
@@ -121,6 +124,12 @@ public INotifoMobilePush SetApiVersion(ApiVersion apiVersion)
121124
return this;
122125
}
123126

127+
/// <inheritdoc/>
128+
public HttpClient CreateHttpClient()
129+
{
130+
return clientProvider.CreateHttpClient();
131+
}
132+
124133
/// <inheritdoc/>
125134
public INotifoMobilePush SetPushEventsProvider(IPushEventsProvider pushEventsProvider)
126135
{

sdk/Notifo.SDK/NotifoMobilePush/NotifoMobilePushImplementation.tracking.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using System.Linq;
1111
using System.Threading;
1212
using System.Threading.Tasks;
13-
using Notifo.SDK.Helpers;
1413
using Notifo.SDK.Resources;
1514

1615
namespace Notifo.SDK.NotifoMobilePush
@@ -41,29 +40,26 @@ public async Task<HashSet<Guid>> GetSeenNotificationsAsync()
4140
}
4241
}
4342

44-
public Task TrackNotificationsAsync(params UserNotificationDto[] notifications)
45-
{
46-
return TrackNotificationsAsync(notifications.Select(x => x.Id).ToArray());
47-
}
48-
49-
public async Task TrackNotificationsAsync(params Guid[] ids)
43+
public async Task TrackNotificationsAsync(params UserNotificationDto[] notifications)
5044
{
5145
await semaphoreSlim.WaitAsync();
5246
try
5347
{
48+
var idsAndUrls = notifications.ToDictionary(x => x.Id, x => (string?)x.TrackSeenUrl);
49+
5450
// Always load the notifications from the preferences, because they could have been modified by the service extension.
5551
var loaded = await seenNotificationsStore.GetSeenNotificationIdsAsync();
5652

5753
// Store the seen notifications immediately as a cache, if the actual command to the server fails.
58-
await seenNotificationsStore.AddSeenNotificationIdsAsync(Capacity, ids);
54+
await seenNotificationsStore.AddSeenNotificationIdsAsync(Capacity, idsAndUrls.Keys);
5955

60-
foreach (var id in ids)
56+
foreach (var id in idsAndUrls.Keys)
6157
{
6258
loaded.Add(id, Capacity);
6359
}
6460

6561
// Track all notifications with one HTTP request.
66-
commandQueue.Run(new TrackSeenCommand { Ids = ids.ToHashSet(), Token = token });
62+
commandQueue.Run(new TrackSeenCommand { IdsAndUrls = idsAndUrls, Token = token });
6763
}
6864
catch (Exception ex)
6965
{

sdk/Notifo.SDK/NotifoMobilePush/TrackSeenCommand.cs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ namespace Notifo.SDK.NotifoMobilePush
1717
{
1818
internal sealed class TrackSeenCommand : ICommand
1919
{
20-
public HashSet<Guid> Ids { get; set; }
20+
[Obsolete]
21+
public HashSet<Guid> Ids
22+
{
23+
set => IdsAndUrls = value.ToDictionary(x => x, x => (string?)null);
24+
}
25+
26+
public Dictionary<Guid, string?> IdsAndUrls { get; set; }
2127

2228
public string? Token { get; set; }
2329

@@ -26,20 +32,14 @@ public async ValueTask ExecuteAsync(
2632
{
2733
try
2834
{
29-
var seenIds = Ids.Select(x => x.ToString()).ToList();
30-
31-
var trackRequest = new TrackNotificationDto
35+
if (!NotifoIO.Current.IsConfigured)
3236
{
33-
// Track all notifications at once.
34-
Seen = seenIds,
35-
36-
// Track individual channels.
37-
Channel = Providers.MobilePush
38-
};
39-
40-
// Track twice to support backwards compatibility with older Notifo versions.
41-
await TrackByTokenAsync(trackRequest, ct);
42-
await TrackByIdentifierAsync(trackRequest, ct);
37+
await TrackWithUrlsAsync(ct);
38+
}
39+
else
40+
{
41+
await TrackWithIdsAsync(ct);
42+
}
4343
}
4444
catch (Exception ex)
4545
{
@@ -48,6 +48,50 @@ public async ValueTask ExecuteAsync(
4848
}
4949
}
5050

51+
private async Task TrackWithUrlsAsync(
52+
CancellationToken ct)
53+
{
54+
var urls = IdsAndUrls.Values.Where(x => x != null).ToList();
55+
56+
if (urls.Count < IdsAndUrls.Count)
57+
{
58+
NotifoIO.Current.RaiseError(Strings.TrackingURLMissing, null, this);
59+
}
60+
61+
if (!urls.Any())
62+
{
63+
return;
64+
}
65+
66+
var httpClient = NotifoIO.Current.CreateHttpClient();
67+
68+
foreach (var url in urls)
69+
{
70+
var response = await httpClient.GetAsync(url, ct);
71+
72+
response.EnsureSuccessStatusCode();
73+
}
74+
}
75+
76+
private async Task TrackWithIdsAsync(
77+
CancellationToken ct)
78+
{
79+
var seenIds = IdsAndUrls.Select(x => x.Key.ToString()).ToList();
80+
81+
var trackRequest = new TrackNotificationDto
82+
{
83+
// Track all notifications at once.
84+
Seen = seenIds,
85+
86+
// Track individual channels.
87+
Channel = Providers.MobilePush
88+
};
89+
90+
// Track twice to support backwards compatibility with older Notifo versions.
91+
await TrackByTokenAsync(trackRequest, ct);
92+
await TrackByIdentifierAsync(trackRequest, ct);
93+
}
94+
5195
private async Task TrackByTokenAsync(TrackNotificationDto trackRequest,
5296
CancellationToken ct)
5397
{
@@ -69,9 +113,10 @@ public bool Merge(ICommand other)
69113
// Do not merge commands with different mobile tokens.
70114
if (other is TrackSeenCommand trackSeen && string.Equals(Token, trackSeen.Token))
71115
{
72-
foreach (var id in trackSeen.Ids)
116+
foreach (var (id, url) in trackSeen.IdsAndUrls)
73117
{
74-
Ids.Add(id);
118+
// Ensure that we do not override the URL with null.
119+
IdsAndUrls[id] = url ?? IdsAndUrls.GetValueOrDefault(id);
75120
}
76121

77122
return true;

sdk/Notifo.SDK/Resources/Strings.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sdk/Notifo.SDK/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,7 @@
174174
<data name="TrackingUrl" xml:space="preserve">
175175
<value>Tracking URL: {0}</value>
176176
</data>
177+
<data name="TrackingURLMissing" xml:space="preserve">
178+
<value>Tracking URL missing for at least one notification.</value>
179+
</data>
177180
</root>

sdk/Notifo.SDK/Services/Settings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal sealed class Settings : ISeenNotificationsStore, ICommandStore
3030
TypeNameHandling = TypeNameHandling.Auto
3131
};
3232

33-
public async ValueTask AddSeenNotificationIdsAsync(int maxCapacity, params Guid[] ids)
33+
public async ValueTask AddSeenNotificationIdsAsync(int maxCapacity, IEnumerable<Guid> ids)
3434
{
3535
await Task.Run(() =>
3636
{

0 commit comments

Comments
 (0)