132 lines
3.6 KiB
Go
132 lines
3.6 KiB
Go
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
|
||
}
|