package notify import ( "fmt" "strings" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "rocketgit.ru/rsmon/worker/app/models" ) // Telegram sends a text message to the given chat ID using the given Telegram // bot credential. chatID is the numeric Telegram chat id assigned by Telegram // to a private chat, group or channel. func Telegram(cred *models.NotificationCredential, chatID int64, text string) error { if cred == nil { return fmt.Errorf("credential is nil") } if cred.Kind != models.CredentialKindTelegram { return fmt.Errorf("credential %d is not telegram (kind=%s)", cred.ID, cred.Kind) } token, err := cred.GetSecret() if err != nil { return fmt.Errorf("decrypt telegram token: %w", err) } if token == "" { return fmt.Errorf("credential %d has empty token", cred.ID) } apiURL := "" if cred.APIURL != nil && *cred.APIURL != "" { apiURL = *cred.APIURL } bot, err := tgbotapi.NewBotAPIWithAPIEndpoint(token, telegramEndpoint(apiURL)) if err != nil { return fmt.Errorf("init telegram bot: %w", err) } msg := tgbotapi.NewMessage(chatID, text) if _, err := bot.Send(msg); err != nil { return fmt.Errorf("send telegram via credential %d: %w", cred.ID, err) } return nil } // telegramEndpoint returns the Bot API endpoint pattern that tgbotapi expects // (".../bot%s/%s"). If rawURL is empty, returns the default Telegram endpoint. // // rawURL may be a base URL with optional basic-auth credentials in the // userinfo (https://user:pass@host/) — net/http applies the userinfo as the // Authorization header automatically, so reverse proxies with basic auth // work transparently. // // We deliberately avoid url.Parse here: it percent-encodes the literal "%" // in "/bot%s/%s" to "/bot%25s/%25s", which makes tgbotapi's fmt.Sprintf // produce a malformed URL (verified against the deploy.rscz.ru proxy). // Stripping the path and appending the bot-method pattern as a string is // both simpler and safe. func telegramEndpoint(rawURL string) string { if rawURL == "" { return tgbotapi.APIEndpoint } return strings.TrimRight(rawURL, "/") + "/bot%s/%s" }