Files
gpt-plus-gpt/pkg/proxy/b2proxy.go
2026-03-15 20:48:19 +08:00

59 lines
1.7 KiB
Go

package proxy
import (
"encoding/json"
"fmt"
"net/http"
"time"
"gpt-plus/config"
)
// b2proxyResponse represents the JSON response from the B2Proxy API.
type b2proxyResponse struct {
Code int `json:"code"`
Data []struct {
IP string `json:"ip"`
Port int `json:"port"`
} `json:"data"`
}
// FetchB2Proxy calls the B2Proxy API to get a proxy IP for the given country.
// Returns a proxy URL like "socks5://1.2.3.4:10000" or "http://1.2.3.4:10000".
// Uses a direct HTTP client (no proxy) with a 10-second timeout.
func FetchB2Proxy(cfg config.B2ProxyConfig, countryCode string) (string, error) {
// Build the API URL
url := fmt.Sprintf("%s/gen?zone=%s&ptype=%d&count=1&proto=%s&stype=json&sessType=sticky&sessTime=%d&sessAuto=1&region=%s",
cfg.APIBase, cfg.Zone, cfg.PType, cfg.Proto, cfg.SessTime, countryCode)
// Use a direct HTTP client (must not go through proxy to fetch proxy)
directClient := &http.Client{Timeout: 10 * time.Second}
resp, err := directClient.Get(url)
if err != nil {
return "", fmt.Errorf("b2proxy API request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("b2proxy API returned status %d", resp.StatusCode)
}
var result b2proxyResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("b2proxy API decode failed: %w", err)
}
if result.Code != 200 {
return "", fmt.Errorf("b2proxy API error code: %d", result.Code)
}
if len(result.Data) == 0 {
return "", fmt.Errorf("b2proxy API returned no proxy for region %s", countryCode)
}
entry := result.Data[0]
proxyURL := fmt.Sprintf("%s://%s:%d", cfg.Proto, entry.IP, entry.Port)
return proxyURL, nil
}