public async Task SendFcmNotification(long accountId) { Session[] sessions; using (IServiceScope scope = serviceProvider.CreateScope()) { var database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); sessions = await database.Sessions.AsQueryable() .Where(s => s.AccountId == accountId && s.FcmToken != null && (s.LastFcmMessage < s.LastConnected || options.Value.NotifyForEveryMessage)) .ToArrayAsync().ConfigureAwait(false); } async Task process(Session session) { using IServiceScope scope = serviceProvider.CreateScope(); var database = scope.ServiceProvider.GetRequiredService <DatabaseContext>(); var injector = scope.ServiceProvider.GetRequiredService <MessageInjectionService>(); var delivery = scope.ServiceProvider.GetRequiredService <DeliveryService>(); var logger = scope.ServiceProvider.GetRequiredService <ILogger <NotificationService> >(); try { await firebase.SendAsync(session.FcmToken).ConfigureAwait(false); session.LastFcmMessage = DateTime.Now; database.Entry(session).Property(s => s.LastFcmMessage).IsModified = true; await database.SaveChangesAsync().ConfigureAwait(false); logger.LogInformation($"Successfully sent FCM message to {session.FcmToken.Remove(16)}... last connected {session.LastConnected}"); } catch (FirebaseMessagingException ex) when(ex.MessagingErrorCode == MessagingErrorCode.Unregistered) { logger.LogWarning($"Failed to send FCM message to {session.FcmToken.Remove(16)}... {ex.Message}"); if (options.Value.DeleteSessionOnError) { // Prevent quick re-login after kick session.SessionTokenHash = Array.Empty <byte>(); database.Entry(session).Property(s => s.SessionTokenHash).IsModified = true; await database.SaveChangesAsync().ConfigureAwait(false); // Kick client if connected to avoid conflicting information in RAM vs DB if (connections.TryGet(session.SessionId, out IClient client)) { await client.DisposeAsync().ConfigureAwait(false); } database.Sessions.Remove(session); await database.SaveChangesAsync().ConfigureAwait(false); Message deviceList = await injector.CreateDeviceList(session.AccountId).ConfigureAwait(false); await delivery.StartSendMessage(deviceList, null).ConfigureAwait(false); } } } await Task.WhenAll(sessions.Select(s => process(s))).ConfigureAwait(false); }
public async Task <int> Handle(NewNotificationCommand request, CancellationToken cancellationToken) { var targetFcmTokens = request.Recipients .Select(observer => _context.NotificationRegistrationData.AsQueryable().Where(regData => regData.ObserverId == int.Parse(observer)) .First(regData => regData.ChannelName == request.Channel)) .Select(regDataResult => regDataResult.Token) .ToList(); var response = 0; if (targetFcmTokens.Count > 0) { response = _firebaseService.SendAsync(request.From, request.Title, request.Message, targetFcmTokens); } var notification = _mapper.Map <Entities.Notification>(request); _context.Notifications.AddRange(notification); await _context.SaveChangesAsync(cancellationToken); return(response); }