From e8ecf764d4b5c7e48c806d55aa41595597714d3e Mon Sep 17 00:00:00 2001 From: ShukeBta <272197458+ShukeBta@users.noreply.github.com> Date: Sat, 27 Jun 2026 10:56:31 +0800 Subject: [PATCH] split telegram api client helpers --- internal/service/telegram_api.go | 114 ---------------------- internal/service/telegram_api_client.go | 124 ++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 114 deletions(-) create mode 100644 internal/service/telegram_api_client.go diff --git a/internal/service/telegram_api.go b/internal/service/telegram_api.go index f30306f..6ea8383 100644 --- a/internal/service/telegram_api.go +++ b/internal/service/telegram_api.go @@ -10,109 +10,10 @@ import ( "mime/multipart" "net/http" "net/url" - "os" - "regexp" "strings" "time" ) -const defaultTelegramAPIBaseURL = "https://api.telegram.org" - -var telegramTokenPattern = regexp.MustCompile(`bot[0-9]+:[^/\s"'?]+`) - -func telegramAPIBaseURL(cfg map[string]string) string { - base := strings.TrimSpace(cfg["api_base_url"]) - if base == "" { - base = strings.TrimSpace(os.Getenv("MEDIASTATION_TELEGRAM_API_BASE_URL")) - } - if base == "" { - base = defaultTelegramAPIBaseURL - } - return strings.TrimRight(base, "/") -} - -func telegramMethodURL(cfg map[string]string, botToken, method string) (string, error) { - botToken = strings.TrimSpace(botToken) - method = strings.TrimSpace(method) - if botToken == "" { - return "", errors.New("telegram bot_token required") - } - if method == "" { - return "", errors.New("telegram method required") - } - base := telegramAPIBaseURL(cfg) - if _, err := url.ParseRequestURI(base); err != nil { - return "", fmt.Errorf("telegram api_base_url invalid") - } - return fmt.Sprintf("%s/bot%s/%s", base, botToken, method), nil -} - -func telegramHTTPClient(timeout time.Duration, cfg map[string]string) *http.Client { - clients := telegramHTTPClients(timeout, cfg) - return clients[0] -} - -func telegramHTTPClients(timeout time.Duration, cfg map[string]string) []*http.Client { - clients := []*http.Client{} - seen := map[string]bool{} - customAPIBase := telegramUsesCustomAPIBase(cfg) - for _, proxyRaw := range telegramProxyCandidates(cfg) { - proxyURL, err := normalizeProxyURL(proxyRaw, "http") - if err != nil || proxyURL == nil { - continue - } - key := proxyURL.String() - if seen[key] { - continue - } - seen[key] = true - transport := NewExternalTransport() - transport.Proxy = http.ProxyURL(proxyURL) - clients = append(clients, &http.Client{Timeout: timeout, Transport: transport}) - } - transport := NewExternalTransport() - if customAPIBase { - transport = NewInternalTransport() - } - clients = append(clients, &http.Client{Timeout: timeout, Transport: transport}) - return clients -} - -func telegramProxyCandidates(cfg map[string]string) []string { - out := []string{} - for _, value := range []string{ - cfg["proxy_url"], - os.Getenv("MEDIASTATION_TELEGRAM_PROXY_URL"), - } { - if strings.TrimSpace(value) != "" { - out = append(out, value) - } - } - if len(out) > 0 { - return out - } - if telegramUsesCustomAPIBase(cfg) { - return out - } - for _, value := range []string{ - "http://127.0.0.1:10808", - "http://127.0.0.1:10809", - "http://127.0.0.1:7890", - "http://127.0.0.1:7891", - "http://host.docker.internal:7890", - "http://host.docker.internal:10808", - "http://172.17.0.1:7890", - "http://172.17.0.1:10808", - } { - out = append(out, value) - } - return out -} - -func telegramUsesCustomAPIBase(cfg map[string]string) bool { - return telegramAPIBaseURL(cfg) != defaultTelegramAPIBaseURL -} - func telegramPostForm(ctx context.Context, cfg map[string]string, method string, form url.Values, timeout time.Duration) error { apiURL, err := telegramMethodURL(cfg, cfg["bot_token"], method) if err != nil { @@ -329,18 +230,3 @@ func telegramStringConfigFromAny(cfg map[string]any) map[string]string { normalizeTelegramConfig(out) return out } - -func sanitizeTelegramError(err error) error { - if err == nil { - return nil - } - msg := sanitizeTelegramText(err.Error()) - if strings.Contains(msg, "Client.Timeout exceeded") || strings.Contains(msg, "context deadline exceeded") { - return errors.New("telegram request timeout: 请检查 NAS/Docker 到 Telegram API 的代理、反代或网络连通性") - } - return errors.New(msg) -} - -func sanitizeTelegramText(text string) string { - return telegramTokenPattern.ReplaceAllString(text, "bot") -} diff --git a/internal/service/telegram_api_client.go b/internal/service/telegram_api_client.go new file mode 100644 index 0000000..3a88709 --- /dev/null +++ b/internal/service/telegram_api_client.go @@ -0,0 +1,124 @@ +package service + +import ( + "errors" + "fmt" + "net/http" + "net/url" + "os" + "regexp" + "strings" + "time" +) + +const defaultTelegramAPIBaseURL = "https://api.telegram.org" + +var telegramTokenPattern = regexp.MustCompile(`bot[0-9]+:[^/\s"'?]+`) + +func telegramAPIBaseURL(cfg map[string]string) string { + base := strings.TrimSpace(cfg["api_base_url"]) + if base == "" { + base = strings.TrimSpace(os.Getenv("MEDIASTATION_TELEGRAM_API_BASE_URL")) + } + if base == "" { + base = defaultTelegramAPIBaseURL + } + return strings.TrimRight(base, "/") +} + +func telegramMethodURL(cfg map[string]string, botToken, method string) (string, error) { + botToken = strings.TrimSpace(botToken) + method = strings.TrimSpace(method) + if botToken == "" { + return "", errors.New("telegram bot_token required") + } + if method == "" { + return "", errors.New("telegram method required") + } + base := telegramAPIBaseURL(cfg) + if _, err := url.ParseRequestURI(base); err != nil { + return "", fmt.Errorf("telegram api_base_url invalid") + } + return fmt.Sprintf("%s/bot%s/%s", base, botToken, method), nil +} + +func telegramHTTPClient(timeout time.Duration, cfg map[string]string) *http.Client { + clients := telegramHTTPClients(timeout, cfg) + return clients[0] +} + +func telegramHTTPClients(timeout time.Duration, cfg map[string]string) []*http.Client { + clients := []*http.Client{} + seen := map[string]bool{} + customAPIBase := telegramUsesCustomAPIBase(cfg) + for _, proxyRaw := range telegramProxyCandidates(cfg) { + proxyURL, err := normalizeProxyURL(proxyRaw, "http") + if err != nil || proxyURL == nil { + continue + } + key := proxyURL.String() + if seen[key] { + continue + } + seen[key] = true + transport := NewExternalTransport() + transport.Proxy = http.ProxyURL(proxyURL) + clients = append(clients, &http.Client{Timeout: timeout, Transport: transport}) + } + transport := NewExternalTransport() + if customAPIBase { + transport = NewInternalTransport() + } + clients = append(clients, &http.Client{Timeout: timeout, Transport: transport}) + return clients +} + +func telegramProxyCandidates(cfg map[string]string) []string { + out := []string{} + for _, value := range []string{ + cfg["proxy_url"], + os.Getenv("MEDIASTATION_TELEGRAM_PROXY_URL"), + } { + if strings.TrimSpace(value) != "" { + out = append(out, value) + } + } + if len(out) > 0 { + return out + } + if telegramUsesCustomAPIBase(cfg) { + return out + } + for _, value := range []string{ + "http://127.0.0.1:10808", + "http://127.0.0.1:10809", + "http://127.0.0.1:7890", + "http://127.0.0.1:7891", + "http://host.docker.internal:7890", + "http://host.docker.internal:10808", + "http://172.17.0.1:7890", + "http://172.17.0.1:10808", + } { + out = append(out, value) + } + return out +} + +func telegramUsesCustomAPIBase(cfg map[string]string) bool { + return telegramAPIBaseURL(cfg) != defaultTelegramAPIBaseURL +} + +func sanitizeTelegramError(err error) error { + if err == nil { + return nil + } + msg := sanitizeTelegramText(err.Error()) + if strings.Contains(msg, "Client.Timeout exceeded") || strings.Contains(msg, "context deadline exceeded") { + return errors.New("telegram request timeout: 请检查 NAS/Docker 到 Telegram API 的代理、反代或网络连通性") + } + return errors.New(msg) +} + +func sanitizeTelegramText(text string) string { + return telegramTokenPattern.ReplaceAllString(text, "bot") +}