package main import ( "bytes" "context" "encoding/json" "fmt" "io" "log" "net" "net/http" "net/url" "time" "golang.org/x/net/proxy" ) // telegramHTTPClient возвращает http.Client — обычный или через SOCKS5 прокси. // Если TELEGRAM_SOCKS5_PROXY не задан — прямое соединение. // Логин и пароль задаются отдельными параметрами TELEGRAM_SOCKS5_USER / TELEGRAM_SOCKS5_PASSWORD // чтобы избежать проблем со спецсимволами при парсинге URL. func telegramHTTPClient() (*http.Client, error) { timeout := 15 * time.Second if cfgTelegramSocks5Proxy == "" { // Прямое соединение return &http.Client{Timeout: timeout}, nil } var auth *proxy.Auth if cfgTelegramSocks5User != "" { auth = &proxy.Auth{ User: cfgTelegramSocks5User, Password: cfgTelegramSocks5Password, } } dialer, err := proxy.SOCKS5("tcp", cfgTelegramSocks5Proxy, auth, proxy.Direct) if err != nil { return nil, fmt.Errorf("ошибка создания SOCKS5 диалера: %w", err) } transport := &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return dialer.Dial(network, addr) }, } log.Printf("[Telegram] Используется SOCKS5 прокси: %s", cfgTelegramSocks5Proxy) return &http.Client{ Transport: transport, Timeout: timeout, }, nil } // telegramSendHTML отправляет HTML-сообщение в Telegram func telegramSendHTML(message string) error { if !isTelegramConfigured() { log.Printf("[Telegram] Не настроен. Сообщение:\n%s\n", message) return fmt.Errorf("telegram не настроен") } client, err := telegramHTTPClient() if err != nil { return fmt.Errorf("ошибка создания HTTP клиента: %w", err) } type tgMessage struct { ChatID string `json:"chat_id"` Text string `json:"text"` ParseMode string `json:"parse_mode"` } msg := tgMessage{ ChatID: cfgTelegramChatID, Text: message, ParseMode: "HTML", } jsonData, err := json.Marshal(msg) if err != nil { return fmt.Errorf("marshal error: %w", err) } apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", cfgTelegramBotToken) resp, err := client.Post(apiURL, "application/json", bytes.NewBuffer(jsonData)) if err != nil { return fmt.Errorf("http error: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("telegram api error: status %d, body: %s", resp.StatusCode, string(body)) } return nil } // telegramSendPlainText отправляет текстовое сообщение без форматирования func telegramSendPlainText(message string) error { if !isTelegramConfigured() { log.Printf("[Telegram] Не настроен. Сообщение:\n%s\n", message) return fmt.Errorf("telegram не настроен") } client, err := telegramHTTPClient() if err != nil { return fmt.Errorf("ошибка создания HTTP клиента: %w", err) } apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", cfgTelegramBotToken) data := url.Values{} data.Set("chat_id", cfgTelegramChatID) data.Set("text", message) resp, err := client.PostForm(apiURL, data) if err != nil { return fmt.Errorf("http error: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("telegram api error: status %d, body: %s", resp.StatusCode, string(body)) } return nil }