feat: 添加推送通知功能,支持订阅和发送通知
This commit is contained in:
93
Service/NotificationService.cs
Normal file
93
Service/NotificationService.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using WebPush;
|
||||
|
||||
namespace Service;
|
||||
|
||||
public interface INotificationService
|
||||
{
|
||||
Task<string> GetVapidPublicKeyAsync();
|
||||
Task SubscribeAsync(PushSubscriptionEntity subscription);
|
||||
Task SendNotificationAsync(string message, string? url = null);
|
||||
}
|
||||
|
||||
public class NotificationService(
|
||||
IPushSubscriptionRepository subscriptionRepo,
|
||||
IConfiguration configuration,
|
||||
ILogger<NotificationService> logger) : INotificationService
|
||||
{
|
||||
private NotificationSettings GetSettings()
|
||||
{
|
||||
var settings = configuration.GetSection("NotificationSettings").Get<NotificationSettings>();
|
||||
if (settings == null)
|
||||
{
|
||||
// Fallback or throw. For now, let's return empty to avoid crashing if not configured,
|
||||
// but logging error is better.
|
||||
logger.LogWarning("NotificationSettings not configured");
|
||||
return new NotificationSettings();
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
public Task<string> GetVapidPublicKeyAsync()
|
||||
{
|
||||
return Task.FromResult(GetSettings().PublicKey);
|
||||
}
|
||||
|
||||
public async Task SubscribeAsync(PushSubscriptionEntity subscription)
|
||||
{
|
||||
var existing = await subscriptionRepo.GetByEndpointAsync(subscription.Endpoint);
|
||||
if (existing != null)
|
||||
{
|
||||
existing.P256DH = subscription.P256DH;
|
||||
existing.Auth = subscription.Auth;
|
||||
existing.UpdateTime = DateTime.Now;
|
||||
await subscriptionRepo.UpdateAsync(existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
await subscriptionRepo.AddAsync(subscription);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendNotificationAsync(string message, string? url = null)
|
||||
{
|
||||
var settings = GetSettings();
|
||||
if (string.IsNullOrEmpty(settings.PublicKey) || string.IsNullOrEmpty(settings.PrivateKey))
|
||||
{
|
||||
logger.LogWarning("VAPID keys not configured, skipping notification");
|
||||
return;
|
||||
}
|
||||
|
||||
var vapidDetails = new VapidDetails(settings.Subject, settings.PublicKey, settings.PrivateKey);
|
||||
var webPushClient = new WebPushClient();
|
||||
|
||||
var subscriptions = await subscriptionRepo.GetAllAsync();
|
||||
var payload = System.Text.Json.JsonSerializer.Serialize(new
|
||||
{
|
||||
title = "System Notification",
|
||||
body = message,
|
||||
url = url ?? "/",
|
||||
icon = "/pwa-192x192.png"
|
||||
});
|
||||
|
||||
foreach (var sub in subscriptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
var pushSubscription = new PushSubscription(sub.Endpoint, sub.P256DH, sub.Auth);
|
||||
await webPushClient.SendNotificationAsync(pushSubscription, payload, vapidDetails);
|
||||
}
|
||||
catch (WebPushException ex)
|
||||
{
|
||||
if (ex.StatusCode == System.Net.HttpStatusCode.Gone || ex.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
await subscriptionRepo.DeleteAsync(sub.Id);
|
||||
}
|
||||
logger.LogError(ex, "Error sending push notification to {Endpoint}", sub.Endpoint);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error sending push notification to {Endpoint}", sub.Endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user