diff --git a/internal/adapters/api/api_adapter.go b/internal/adapters/api/api_adapter.go index a199687..fee4833 100644 --- a/internal/adapters/api/api_adapter.go +++ b/internal/adapters/api/api_adapter.go @@ -170,16 +170,17 @@ 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 - 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) + // 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 } diff --git a/internal/adapters/notifier/notifier_adapter.go b/internal/adapters/notifier/notifier_adapter.go index a083c71..3a8f309 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,68 @@ 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 + + // 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 +} + 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 }