83 lines
3.2 KiB
C#
83 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.Http;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using FinlyticCore.Dtos.Trading;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace FinlyticBackend.Services;
|
|
|
|
/// <summary>
|
|
/// Defines a service for dispatching push notifications via Firebase Cloud Messaging (FCM).
|
|
/// </summary>
|
|
public interface IFirebaseNotificationService
|
|
{
|
|
/// <summary>
|
|
/// Sends a push notification about a new trade proposal.
|
|
/// </summary>
|
|
Task SendTradeProposalNotificationAsync(TradeProposalDto proposal, List<string> fcmTokens, CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Sends a push notification about an update to an existing trade.
|
|
/// </summary>
|
|
Task SendTradeUpdateNotificationAsync(ActiveTradeDto update, List<string> fcmTokens, CancellationToken cancellationToken = default);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public class FirebaseNotificationService : IFirebaseNotificationService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly ILogger<FirebaseNotificationService> _logger;
|
|
|
|
public FirebaseNotificationService(HttpClient httpClient, ILogger<FirebaseNotificationService> logger)
|
|
{
|
|
_httpClient = httpClient;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task SendTradeProposalNotificationAsync(TradeProposalDto proposal, List<string> fcmTokens, CancellationToken cancellationToken = default)
|
|
{
|
|
if (fcmTokens == null || fcmTokens.Count == 0) return;
|
|
|
|
string title = $"🚀 Trade Signal: {proposal.Direction} {proposal.Symbol} ({proposal.StrategyKey})";
|
|
string body = $"{proposal.Symbol} ({proposal.UnderlyingIsin}) - Entry: €{proposal.EntryPrice:F2}, Score: {proposal.CompositeScore:F0} Pkt. {proposal.AiValidation?.ThesisSummary}";
|
|
|
|
foreach (var token in fcmTokens)
|
|
{
|
|
await DispatchFcmMessageAsync(token, title, body, cancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task SendTradeUpdateNotificationAsync(ActiveTradeDto update, List<string> fcmTokens, CancellationToken cancellationToken = default)
|
|
{
|
|
if (fcmTokens == null || fcmTokens.Count == 0) return;
|
|
|
|
string title = $"📊 Trade Update: {update.Symbol} (Status: {update.Status})";
|
|
string body = $"Status: {update.Status} @ €{update.CurrentPrice:F2}, PnL: {update.UnrealizedPnlPercent:+0.0;-0.0}% (€{update.UnrealizedPnlEur:+0.00;-0.00}).";
|
|
|
|
foreach (var token in fcmTokens)
|
|
{
|
|
await DispatchFcmMessageAsync(token, title, body, cancellationToken);
|
|
}
|
|
}
|
|
|
|
private Task DispatchFcmMessageAsync(string fcmToken, string title, string body, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation("[{Channel}] FCM Push Notification dispatched to Token [{TokenPrefix}...]: Title='{Title}', Body='{Body}'",
|
|
"NotificationChannel", fcmToken.Length > 10 ? fcmToken[..10] : fcmToken, title, body);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "[{Channel}] Failed to send FCM push notification to token {Token}", "NotificationChannel", fcmToken);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|