This repository has been archived by the owner on Sep 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
/
PushService.cs
126 lines (106 loc) · 4.75 KB
/
PushService.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PushnotificationsDemo.Models;
using WebPush;
using PushSubscription = PushnotificationsDemo.Models.PushSubscription;
namespace PushnotificationsDemo.Services
{
/// <inheritdoc />
public class PushService : IPushService
{
private readonly WebPushClient _client;
private readonly DemoDbContext _context;
private readonly VapidDetails _vapidDetails;
/// <inheritdoc />
public PushService(DemoDbContext context, string vapidSubject, string vapidPublicKey, string vapidPrivateKey)
{
_context = context;
_client = new WebPushClient();
CheckOrGenerateVapidDetails(vapidSubject, vapidPublicKey, vapidPrivateKey);
_vapidDetails = new VapidDetails(vapidSubject, vapidPublicKey, vapidPrivateKey);
}
/// <inheritdoc />
public PushService(DemoDbContext context, IConfiguration configuration)
{
_context = context;
_client = new WebPushClient();
var vapidSubject = configuration.GetValue<string>("Vapid:Subject");
var vapidPublicKey = configuration.GetValue<string>("Vapid:PublicKey");
var vapidPrivateKey = configuration.GetValue<string>("Vapid:PrivateKey");
CheckOrGenerateVapidDetails(vapidSubject, vapidPublicKey, vapidPrivateKey);
_vapidDetails = new VapidDetails(vapidSubject, vapidPublicKey, vapidPrivateKey);
}
/// <inheritdoc />
public void CheckOrGenerateVapidDetails(string vapidSubject, string vapidPublicKey, string vapidPrivateKey)
{
if (string.IsNullOrEmpty(vapidSubject) ||
string.IsNullOrEmpty(vapidPublicKey) ||
string.IsNullOrEmpty(vapidPrivateKey))
{
var vapidKeys = VapidHelper.GenerateVapidKeys();
// Prints 2 URL Safe Base64 Encoded Strings
Debug.WriteLine($"Public {vapidKeys.PublicKey}");
Debug.WriteLine($"Private {vapidKeys.PrivateKey}");
throw new Exception(
"You must set the Vapid:Subject, Vapid:PublicKey and Vapid:PrivateKey application settings or pass them to the service in the constructor. You can use the ones just printed to the debug console.");
}
}
/// <inheritdoc />
public string GetVapidPublicKey() => _vapidDetails.PublicKey;
/// <inheritdoc />
public async Task<PushSubscription> Subscribe(PushSubscription subscription)
{
if (await _context.PushSubscription.AnyAsync(s => s.P256Dh == subscription.P256Dh))
return await _context.PushSubscription.FindAsync(subscription.P256Dh);
await _context.PushSubscription.AddAsync(subscription);
await _context.SaveChangesAsync();
return subscription;
}
/// <inheritdoc />
public async Task Unsubscribe(PushSubscription subscription)
{
if (!await _context.PushSubscription.AnyAsync(s => s.P256Dh == subscription.P256Dh)) return;
_context.PushSubscription.Remove(subscription);
await _context.SaveChangesAsync();
}
/// <inheritdoc />
public async Task Send(string userId, Notification notification)
{
foreach (var subscription in await GetUserSubscriptions(userId))
try
{
_client.SendNotification(subscription.ToWebPushSubscription(), JsonConvert.SerializeObject(notification), _vapidDetails);
}
catch (WebPushException e)
{
if (e.Message == "Subscription no longer valid")
{
_context.PushSubscription.Remove(subscription);
await _context.SaveChangesAsync();
}
else
{
// Track exception with eg. AppInsights
}
}
}
/// <inheritdoc />
public async Task Send(string userId, string text)
{
await Send(userId, new Notification(text));
}
/// <summary>
/// Loads a list of user subscriptions from the database
/// </summary>
/// <param name="userId">user id</param>
/// <returns>List of subscriptions</returns>
private async Task<List<PushSubscription>> GetUserSubscriptions(string userId) =>
await _context.PushSubscription.Where(s => s.UserId == userId).ToListAsync();
}
}