diff --git a/src/Managing.Application.Abstractions/Services/IWebhookService.cs b/src/Managing.Application.Abstractions/Services/IWebhookService.cs index 5d92d11..fa6ef75 100644 --- a/src/Managing.Application.Abstractions/Services/IWebhookService.cs +++ b/src/Managing.Application.Abstractions/Services/IWebhookService.cs @@ -5,4 +5,5 @@ namespace Managing.Application.Abstractions.Services; public interface IWebhookService { Task SendTradeNotification(User user, string message, bool isBadBehavior = false); + Task SendMessage(string message, string? telegramChannel = null); } \ No newline at end of file diff --git a/src/Managing.Application/Shared/MessengerService.cs b/src/Managing.Application/Shared/MessengerService.cs index 5b62f0e..7af1cda 100644 --- a/src/Managing.Application/Shared/MessengerService.cs +++ b/src/Managing.Application/Shared/MessengerService.cs @@ -46,7 +46,58 @@ public class MessengerService : IMessengerService public async Task SendPosition(Position position) { - await _discordService.SendPosition(position); + // Send to Discord with try-catch to not block + try + { + await _discordService.SendPosition(position); + } + catch (Exception e) + { + Console.WriteLine(e); + } + + // Send to webhook (n8n/telegram) + try + { + var message = BuildPositionMessage(position); + await _webhookService.SendMessage(message, position.User?.TelegramChannel); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + private string BuildPositionMessage(Position position) + { + var direction = position.OriginDirection.ToString(); + var status = position.Status.ToString(); + + var message = $"🎯 Position {status}\n" + + $"Symbol: {position.Ticker}\n" + + $"Direction: {direction}\n" + + $"Account: {position.AccountName}\n" + + $"Identifier: {position.Identifier}\n" + + $"Initiator: {position.Initiator}\n" + + $"Date: {position.Date:yyyy-MM-dd HH:mm:ss}"; + + if (position.Open != null) + { + message += $"\nOpen Trade: {position.Open.Quantity} @ {position.Open.Price:F4}"; + } + + if (position.ProfitAndLoss != null) + { + var pnlEmoji = position.ProfitAndLoss.Realized >= 0 ? "✅" : "❌"; + message += $"\nPnL: {pnlEmoji} ${position.ProfitAndLoss.Realized:F2}"; + } + + if (!string.IsNullOrEmpty(position.SignalIdentifier)) + { + message += $"\nSignal: {position.SignalIdentifier}"; + } + + return message; } public async Task SendSignal(string message, Enums.TradingExchanges exchange, Enums.Ticker ticker, diff --git a/src/Managing.Application/Shared/WebhookService.cs b/src/Managing.Application/Shared/WebhookService.cs index 1d392cd..4263af2 100644 --- a/src/Managing.Application/Shared/WebhookService.cs +++ b/src/Managing.Application/Shared/WebhookService.cs @@ -55,8 +55,46 @@ public class WebhookService : IWebhookService } catch (Exception ex) { - _logger.LogError(ex, $"Error sending webhook notification for user {user.Name}: {ex.Message}"); - // Don't throw - webhook failures shouldn't break the main flow + _logger.LogError(ex, "Error sending webhook notification"); + } + } + + public async Task SendMessage(string message, string? telegramChannel = null) + { + try + { + // Get the n8n webhook URL from configuration + var webhookUrl = _configuration["N8n:WebhookUrl"]; + if (string.IsNullOrEmpty(webhookUrl)) + { + _logger.LogWarning("N8n webhook URL not configured, skipping webhook message"); + return; + } + + // Prepare the payload for n8n webhook + var payload = new + { + message = message, + timestamp = DateTime.UtcNow, + type = "general_message", + telegramChannel = telegramChannel + }; + + // Send the webhook notification + var response = await _httpClient.PostAsJsonAsync(webhookUrl, payload); + + if (response.IsSuccessStatusCode) + { + _logger.LogInformation("Successfully sent webhook message"); + } + else + { + _logger.LogWarning($"Failed to send webhook message. Status: {response.StatusCode}"); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error sending webhook message"); } } } \ No newline at end of file