From 405fa56c286a42c5d2b83903b7f5ecedaef8b860 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Thu, 12 Dec 2024 09:32:02 +0100 Subject: [PATCH 1/2] Dont use listeners in telegram config update --- internal/adapters/api/api_adapter.go | 10 ++- .../adapters/notifier/notifier_adapter.go | 66 +++++++++---------- internal/adapters/storage/telegram.go | 40 +---------- internal/application/ports/notifier_port.go | 1 + internal/application/ports/storage_port.go | 1 - 5 files changed, 45 insertions(+), 73 deletions(-) diff --git a/internal/adapters/api/api_adapter.go b/internal/adapters/api/api_adapter.go index a199687..db1020d 100644 --- a/internal/adapters/api/api_adapter.go +++ b/internal/adapters/api/api_adapter.go @@ -170,13 +170,21 @@ func (h *APIHandler) UpdateTelegramConfig(w http.ResponseWriter, r *http.Request return } + // Update storage if err := h.StoragePort.SaveTelegramConfig(domain.TelegramConfig(req)); err != nil { logger.ErrorWithPrefix("API", "Failed to update Telegram configuration: %v", err) writeErrorResponse(w, "Failed to update Telegram configuration", http.StatusInternalServerError) return } - // send update notification to verify the chat id exists + // Synchronously update the Telegram bot configuration + if err := h.NotifierPort.UpdateBotConfig(); err != nil { + logger.ErrorWithPrefix("API", "Failed to update Telegram bot configuration: %v", err) + writeErrorResponse(w, "Failed to update Telegram bot configuration", http.StatusInternalServerError) + return + } + + // Send a test notification after the bot has been updated if err := h.NotifierPort.SendNotification("🔑 Updated telegram configuration successfully"); err != nil { logger.ErrorWithPrefix("API", "Failed to send test notification: %v", err) writeErrorResponse(w, "Failed to send test notification", http.StatusInternalServerError) diff --git a/internal/adapters/notifier/notifier_adapter.go b/internal/adapters/notifier/notifier_adapter.go index a083c71..d248350 100644 --- a/internal/adapters/notifier/notifier_adapter.go +++ b/internal/adapters/notifier/notifier_adapter.go @@ -13,6 +13,7 @@ type TelegramBot struct { Bot *tgbotapi.BotAPI UserID int64 servicePrefix string + storagePort ports.StoragePort } func NewNotifierAdapter(ctx context.Context, storageAdapter ports.StoragePort) (*TelegramBot, error) { @@ -20,62 +21,61 @@ func NewNotifierAdapter(ctx context.Context, storageAdapter ports.StoragePort) ( adapter := &TelegramBot{ servicePrefix: servicePrefix, + storagePort: storageAdapter, } - // Attempt to load the initial configuration for Telegram - initialConfig, err := storageAdapter.GetTelegramConfig() + // Initialize if config exists. + config, err := storageAdapter.GetTelegramConfig() if err != nil { logger.WarnWithPrefix(servicePrefix, "Failed to load initial Telegram configuration: %v", err) - } else if initialConfig.Token != "" && initialConfig.UserID != 0 { - // Initialize the bot if the configuration is valid - bot, err := tgbotapi.NewBotAPI(initialConfig.Token) + } else if config.Token != "" && config.UserID != 0 { + bot, err := tgbotapi.NewBotAPI(config.Token) if err != nil { logger.WarnWithPrefix(servicePrefix, "Failed to initialize Telegram bot: %v", err) } else { adapter.Bot = bot - adapter.UserID = initialConfig.UserID + adapter.UserID = config.UserID logger.InfoWithPrefix(servicePrefix, "Telegram bot initialized successfully.") } } else { - logger.WarnWithPrefix(servicePrefix, "Initial Telegram configuration is incomplete. Notifications will be disabled.") + logger.WarnWithPrefix(servicePrefix, "Initial Telegram configuration is incomplete. Notifications disabled.") } - // Listen for configuration updates in a separate goroutine - telegramConfigUpdates := storageAdapter.RegisterTelegramConfigListener() - go func() { - for newConfig := range telegramConfigUpdates { - adapter.UserID = newConfig.UserID - // Update the bot API instance with the new token - if newConfig.Token != "" { - updatedBot, err := tgbotapi.NewBotAPI(newConfig.Token) - if err == nil { - adapter.Bot = updatedBot - logger.InfoWithPrefix(servicePrefix, "Telegram bot configuration updated successfully.") - } else { - logger.ErrorWithPrefix(servicePrefix, "Failed to update Telegram bot: %v", err) - adapter.Bot = nil // Disable notifications on failure - } - } else { - logger.WarnWithPrefix(servicePrefix, "Received incomplete Telegram configuration. Notifications will be disabled.") - adapter.Bot = nil // Disable notifications if the new config is invalid - } - } - }() - return adapter, nil } -// SendNotification sends a message via Telegram +func (tb *TelegramBot) UpdateBotConfig() error { + config, err := tb.storagePort.GetTelegramConfig() + if err != nil { + return fmt.Errorf("failed to get Telegram config: %v", err) + } + + if config.Token == "" || config.UserID == 0 { + tb.Bot = nil + tb.UserID = 0 + logger.WarnWithPrefix(tb.servicePrefix, "Incomplete Telegram configuration. Notifications disabled.") + return nil + } + + bot, err := tgbotapi.NewBotAPI(config.Token) + if err != nil { + tb.Bot = nil + return fmt.Errorf("failed to update Telegram bot: %v", err) + } + + tb.Bot = bot + tb.UserID = config.UserID + logger.InfoWithPrefix(tb.servicePrefix, "Telegram bot configuration updated successfully.") + return nil +} + func (tb *TelegramBot) SendNotification(message string) error { - // Check if the bot is initialized if tb.Bot == nil { logger.WarnWithPrefix(tb.servicePrefix, "Telegram bot is not initialized. Skipping notification.") return nil } - // print user id logger.DebugWithPrefix(tb.servicePrefix, "Sending notification to user ID: %d", tb.UserID) - msg := tgbotapi.NewMessage(tb.UserID, message) _, err := tb.Bot.Send(msg) if err != nil { diff --git a/internal/adapters/storage/telegram.go b/internal/adapters/storage/telegram.go index df7e59f..8992611 100644 --- a/internal/adapters/storage/telegram.go +++ b/internal/adapters/storage/telegram.go @@ -2,14 +2,10 @@ package storage import ( "lido-events/internal/application/domain" - "sync" ) -// TODO: determine if token should be stored hashed +// Telegram Config Methods -// Telegram Configuration Methods - -// SaveTelegramConfig saves the Telegram configuration to storage and notifies listeners of the update. func (fs *Storage) SaveTelegramConfig(config domain.TelegramConfig) error { db, err := fs.LoadDatabase() if err != nil { @@ -21,11 +17,10 @@ func (fs *Storage) SaveTelegramConfig(config domain.TelegramConfig) error { return err } - fs.notifyTelegramConfigListenersSync() // Notify listeners of the change + // No notification to listeners needed anymore since we are doing synchronous updates. return nil } -// GetTelegramConfig retrieves the Telegram configuration from storage. func (fs *Storage) GetTelegramConfig() (domain.TelegramConfig, error) { db, err := fs.LoadDatabase() if err != nil { @@ -33,34 +28,3 @@ func (fs *Storage) GetTelegramConfig() (domain.TelegramConfig, error) { } return db.Telegram, nil } - -// RegisterTelegramConfigListener registers a channel to receive updates when the Telegram config changes. -func (fs *Storage) RegisterTelegramConfigListener() chan domain.TelegramConfig { - updateChan := make(chan domain.TelegramConfig, 1) - fs.telegramConfigListeners = append(fs.telegramConfigListeners, updateChan) - return updateChan -} - -// notifyTelegramConfigListenersSync sends updates to all registered listeners of Telegram config changes. -func (fs *Storage) notifyTelegramConfigListenersSync() { - config, err := fs.GetTelegramConfig() - if err != nil { - return - } - - var wg sync.WaitGroup - for _, listener := range fs.telegramConfigListeners { - wg.Add(1) - go func(listener chan domain.TelegramConfig) { - defer wg.Done() - select { - case listener <- config: - // Config sent successfully - default: - // Ignore if channel is full to prevent blocking - } - }(listener) - } - - wg.Wait() // Wait for all listeners to process the update -} diff --git a/internal/application/ports/notifier_port.go b/internal/application/ports/notifier_port.go index d6e2a02..043948f 100644 --- a/internal/application/ports/notifier_port.go +++ b/internal/application/ports/notifier_port.go @@ -2,4 +2,5 @@ package ports type NotifierPort interface { SendNotification(message string) error + UpdateBotConfig() error } diff --git a/internal/application/ports/storage_port.go b/internal/application/ports/storage_port.go index 0d8d826..426f644 100644 --- a/internal/application/ports/storage_port.go +++ b/internal/application/ports/storage_port.go @@ -37,5 +37,4 @@ type StoragePort interface { // telegram GetTelegramConfig() (domain.TelegramConfig, error) SaveTelegramConfig(config domain.TelegramConfig) error - RegisterTelegramConfigListener() chan domain.TelegramConfig } From 41fd50dab76e9e5d8ccaf043fc30860f7efda38c Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Thu, 12 Dec 2024 09:40:43 +0100 Subject: [PATCH 2/2] send test notification in notifier adapter --- internal/adapters/api/api_adapter.go | 7 ------- internal/adapters/notifier/notifier_adapter.go | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/adapters/api/api_adapter.go b/internal/adapters/api/api_adapter.go index db1020d..fee4833 100644 --- a/internal/adapters/api/api_adapter.go +++ b/internal/adapters/api/api_adapter.go @@ -184,13 +184,6 @@ func (h *APIHandler) UpdateTelegramConfig(w http.ResponseWriter, r *http.Request return } - // Send a test notification after the bot has been updated - if err := h.NotifierPort.SendNotification("🔑 Updated telegram configuration successfully"); err != nil { - logger.ErrorWithPrefix("API", "Failed to send test notification: %v", err) - writeErrorResponse(w, "Failed to send test notification", http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) } diff --git a/internal/adapters/notifier/notifier_adapter.go b/internal/adapters/notifier/notifier_adapter.go index d248350..3a8f309 100644 --- a/internal/adapters/notifier/notifier_adapter.go +++ b/internal/adapters/notifier/notifier_adapter.go @@ -65,7 +65,14 @@ func (tb *TelegramBot) UpdateBotConfig() error { tb.Bot = bot tb.UserID = config.UserID + + // Send a test notification after the bot has been updated + if err := tb.SendNotification("🔑 Updated telegram configuration successfully"); err != nil { + return fmt.Errorf("failed to send test notification: %w", err) + } + logger.InfoWithPrefix(tb.servicePrefix, "Telegram bot configuration updated successfully.") + return nil }