✨ Push token clean up when invalid
This commit is contained in:
@@ -6,11 +6,11 @@ using Quartz;
|
|||||||
|
|
||||||
namespace DysonNetwork.Pass.Handlers;
|
namespace DysonNetwork.Pass.Handlers;
|
||||||
|
|
||||||
public class ActionLogFlushHandler(IServiceProvider serviceProvider) : IFlushHandler<SnActionLog>
|
public class ActionLogFlushHandler(IServiceProvider sp) : IFlushHandler<SnActionLog>
|
||||||
{
|
{
|
||||||
public async Task FlushAsync(IReadOnlyList<SnActionLog> items)
|
public async Task FlushAsync(IReadOnlyList<SnActionLog> items)
|
||||||
{
|
{
|
||||||
using var scope = serviceProvider.CreateScope();
|
using var scope = sp.CreateScope();
|
||||||
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
|
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
|
||||||
|
|
||||||
var now = SystemClock.Instance.GetCurrentInstant();
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using CorePush.Apple;
|
|||||||
using CorePush.Firebase;
|
using CorePush.Firebase;
|
||||||
using DysonNetwork.Ring.Connection;
|
using DysonNetwork.Ring.Connection;
|
||||||
using DysonNetwork.Ring.Services;
|
using DysonNetwork.Ring.Services;
|
||||||
|
using DysonNetwork.Shared.Cache;
|
||||||
using DysonNetwork.Shared.Models;
|
using DysonNetwork.Shared.Models;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -17,12 +18,14 @@ public class PushService
|
|||||||
private readonly ILogger<PushService> _logger;
|
private readonly ILogger<PushService> _logger;
|
||||||
private readonly FirebaseSender? _fcm;
|
private readonly FirebaseSender? _fcm;
|
||||||
private readonly ApnSender? _apns;
|
private readonly ApnSender? _apns;
|
||||||
|
private readonly FlushBufferService _fbs;
|
||||||
private readonly string? _apnsTopic;
|
private readonly string? _apnsTopic;
|
||||||
|
|
||||||
public PushService(
|
public PushService(
|
||||||
IConfiguration config,
|
IConfiguration config,
|
||||||
AppDatabase db,
|
AppDatabase db,
|
||||||
QueueService queueService,
|
QueueService queueService,
|
||||||
|
FlushBufferService fbs,
|
||||||
IHttpClientFactory httpFactory,
|
IHttpClientFactory httpFactory,
|
||||||
ILogger<PushService> logger
|
ILogger<PushService> logger
|
||||||
)
|
)
|
||||||
@@ -52,6 +55,7 @@ public class PushService
|
|||||||
}
|
}
|
||||||
|
|
||||||
_db = db;
|
_db = db;
|
||||||
|
_fbs = fbs;
|
||||||
_queueService = queueService;
|
_queueService = queueService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@@ -144,14 +148,15 @@ public class PushService
|
|||||||
_ = _queueService.EnqueuePushNotification(notification, Guid.Parse(accountId), save);
|
_ = _queueService.EnqueuePushNotification(notification, Guid.Parse(accountId), save);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeliverPushNotification(SnNotification notification, CancellationToken cancellationToken = default)
|
public async Task DeliverPushNotification(SnNotification notification,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
WebSocketService.SendPacketToAccount(notification.AccountId, new WebSocketPacket()
|
WebSocketService.SendPacketToAccount(notification.AccountId, new WebSocketPacket()
|
||||||
{
|
{
|
||||||
Type = "notifications.new",
|
Type = "notifications.new",
|
||||||
Data = notification,
|
Data = notification,
|
||||||
});
|
});
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
@@ -260,7 +265,8 @@ public class PushService
|
|||||||
await DeliverPushNotification(notification);
|
await DeliverPushNotification(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendPushNotificationAsync(SnNotificationPushSubscription subscription, SnNotification notification)
|
private async Task SendPushNotificationAsync(SnNotificationPushSubscription subscription,
|
||||||
|
SnNotification notification)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -302,7 +308,9 @@ public class PushService
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fcmResult.Error != null)
|
if (fcmResult.StatusCode is 404 or 410)
|
||||||
|
_fbs.Enqueue(new PushSubRemovalRequest { SubId = subscription.Id });
|
||||||
|
else if (fcmResult.Error != null)
|
||||||
throw new Exception($"Notification pushed failed ({fcmResult.StatusCode}) {fcmResult.Error}");
|
throw new Exception($"Notification pushed failed ({fcmResult.StatusCode}) {fcmResult.Error}");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -338,7 +346,10 @@ public class PushService
|
|||||||
apnsPriority: notification.Priority,
|
apnsPriority: notification.Priority,
|
||||||
apnPushType: ApnPushType.Alert
|
apnPushType: ApnPushType.Alert
|
||||||
);
|
);
|
||||||
if (apnResult.Error != null)
|
|
||||||
|
if (apnResult.StatusCode is 404 or 410)
|
||||||
|
_fbs.Enqueue(new PushSubRemovalRequest { SubId = subscription.Id });
|
||||||
|
else if (apnResult.Error != null)
|
||||||
throw new Exception($"Notification pushed failed ({apnResult.StatusCode}) {apnResult.Error}");
|
throw new Exception($"Notification pushed failed ({apnResult.StatusCode}) {apnResult.Error}");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
35
DysonNetwork.Ring/Services/PushSubFlushHandler.cs
Normal file
35
DysonNetwork.Ring/Services/PushSubFlushHandler.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using DysonNetwork.Shared.Cache;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Ring.Services;
|
||||||
|
|
||||||
|
public class PushSubRemovalRequest
|
||||||
|
{
|
||||||
|
public Guid SubId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PushSubFlushHandler(IServiceProvider sp) : IFlushHandler<PushSubRemovalRequest>
|
||||||
|
{
|
||||||
|
public async Task FlushAsync(IReadOnlyList<PushSubRemovalRequest> items)
|
||||||
|
{
|
||||||
|
using var scope = sp.CreateScope();
|
||||||
|
var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
|
||||||
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<PushSubFlushHandler>>();
|
||||||
|
|
||||||
|
var tokenIds = items.Select(x => x.SubId).Distinct().ToList();
|
||||||
|
|
||||||
|
var count = await db.PushSubscriptions
|
||||||
|
.Where(s => tokenIds.Contains(s.Id))
|
||||||
|
.ExecuteDeleteAsync();
|
||||||
|
logger.LogInformation("Removed {Count} invalid push notification tokens...", count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PushSubFlushJob(FlushBufferService fbs, PushSubFlushHandler hdl) : IJob
|
||||||
|
{
|
||||||
|
public async Task Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
await fbs.FlushAsync(hdl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using DysonNetwork.Ring.Notification;
|
using DysonNetwork.Ring.Services;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
|
|
||||||
namespace DysonNetwork.Ring.Startup;
|
namespace DysonNetwork.Ring.Startup;
|
||||||
@@ -15,6 +15,15 @@ public static class ScheduledJobsConfiguration
|
|||||||
.ForJob(appDatabaseRecyclingJob)
|
.ForJob(appDatabaseRecyclingJob)
|
||||||
.WithIdentity("AppDatabaseRecyclingTrigger")
|
.WithIdentity("AppDatabaseRecyclingTrigger")
|
||||||
.WithCronSchedule("0 0 0 * * ?"));
|
.WithCronSchedule("0 0 0 * * ?"));
|
||||||
|
|
||||||
|
q.AddJob<PushSubFlushJob>(opts => opts.WithIdentity("PushSubFlush"));
|
||||||
|
q.AddTrigger(opts => opts
|
||||||
|
.ForJob("PushSubFlush")
|
||||||
|
.WithIdentity("PushSubFlushTrigger")
|
||||||
|
.WithSimpleSchedule(o => o
|
||||||
|
.WithIntervalInMinutes(5)
|
||||||
|
.RepeatForever())
|
||||||
|
);
|
||||||
});
|
});
|
||||||
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
|
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public static class ServiceCollectionExtensions
|
|||||||
public static IServiceCollection AddAppFlushHandlers(this IServiceCollection services)
|
public static IServiceCollection AddAppFlushHandlers(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<FlushBufferService>();
|
services.AddSingleton<FlushBufferService>();
|
||||||
|
services.AddScoped<PushSubFlushHandler>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user