feat(management): add proxy support for management asset synchronization

- Introduced `proxyURL` parameter for `EnsureLatestManagementHTML` to enable proxy configuration.
- Refactored HTTP client initialization with new `newHTTPClient` to support proxy-aware requests.
- Updated asset download and fetch logic to utilize the proxy-aware HTTP client.
- Adjusted `server.go` to pass `cfg.ProxyURL` for management asset synchronization calls.
This commit is contained in:
Luis Pater
2025-10-01 20:18:26 +08:00
parent 6629cadb87
commit 4a31f763af
2 changed files with 21 additions and 10 deletions

View File

@@ -405,7 +405,7 @@ func (s *Server) serveManagementControlPanel(c *gin.Context) {
if _, err := os.Stat(filePath); err != nil { if _, err := os.Stat(filePath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
go managementasset.EnsureLatestManagementHTML(context.Background(), managementasset.StaticDir(s.configFilePath)) go managementasset.EnsureLatestManagementHTML(context.Background(), managementasset.StaticDir(s.configFilePath), cfg.ProxyURL)
c.AbortWithStatus(http.StatusNotFound) c.AbortWithStatus(http.StatusNotFound)
return return
} }
@@ -647,7 +647,7 @@ func (s *Server) UpdateClients(cfg *config.Config) {
if !cfg.RemoteManagement.DisableControlPanel { if !cfg.RemoteManagement.DisableControlPanel {
staticDir := managementasset.StaticDir(s.configFilePath) staticDir := managementasset.StaticDir(s.configFilePath)
go managementasset.EnsureLatestManagementHTML(context.Background(), staticDir) go managementasset.EnsureLatestManagementHTML(context.Background(), staticDir, cfg.ProxyURL)
} }
if s.mgmt != nil { if s.mgmt != nil {
s.mgmt.SetConfig(cfg) s.mgmt.SetConfig(cfg)

View File

@@ -14,6 +14,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
sdkconfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -26,7 +28,14 @@ const (
// ManagementFileName exposes the control panel asset filename. // ManagementFileName exposes the control panel asset filename.
const ManagementFileName = managementAssetName const ManagementFileName = managementAssetName
var httpClient = &http.Client{Timeout: 15 * time.Second} func newHTTPClient(proxyURL string) *http.Client {
client := &http.Client{Timeout: 15 * time.Second}
sdkCfg := &sdkconfig.SDKConfig{ProxyURL: strings.TrimSpace(proxyURL)}
util.SetProxy(sdkCfg, client)
return client
}
type releaseAsset struct { type releaseAsset struct {
Name string `json:"name"` Name string `json:"name"`
@@ -59,7 +68,7 @@ func FilePath(configFilePath string) string {
// EnsureLatestManagementHTML checks the latest management.html asset and updates the local copy when needed. // EnsureLatestManagementHTML checks the latest management.html asset and updates the local copy when needed.
// The function is designed to run in a background goroutine and will never panic. // The function is designed to run in a background goroutine and will never panic.
func EnsureLatestManagementHTML(ctx context.Context, staticDir string) { func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL string) {
if ctx == nil { if ctx == nil {
ctx = context.Background() ctx = context.Background()
} }
@@ -75,6 +84,8 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string) {
return return
} }
client := newHTTPClient(proxyURL)
localPath := filepath.Join(staticDir, managementAssetName) localPath := filepath.Join(staticDir, managementAssetName)
localHash, err := fileSHA256(localPath) localHash, err := fileSHA256(localPath)
if err != nil { if err != nil {
@@ -84,7 +95,7 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string) {
localHash = "" localHash = ""
} }
asset, remoteHash, err := fetchLatestAsset(ctx) asset, remoteHash, err := fetchLatestAsset(ctx, client)
if err != nil { if err != nil {
log.WithError(err).Warn("failed to fetch latest management release information") log.WithError(err).Warn("failed to fetch latest management release information")
return return
@@ -95,7 +106,7 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string) {
return return
} }
data, downloadedHash, err := downloadAsset(ctx, asset.BrowserDownloadURL) data, downloadedHash, err := downloadAsset(ctx, client, asset.BrowserDownloadURL)
if err != nil { if err != nil {
log.WithError(err).Warn("failed to download management asset") log.WithError(err).Warn("failed to download management asset")
return return
@@ -113,7 +124,7 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string) {
log.Infof("management asset updated successfully (hash=%s)", downloadedHash) log.Infof("management asset updated successfully (hash=%s)", downloadedHash)
} }
func fetchLatestAsset(ctx context.Context) (*releaseAsset, string, error) { func fetchLatestAsset(ctx context.Context, client *http.Client) (*releaseAsset, string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, managementReleaseURL, nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, managementReleaseURL, nil)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("create release request: %w", err) return nil, "", fmt.Errorf("create release request: %w", err)
@@ -121,7 +132,7 @@ func fetchLatestAsset(ctx context.Context) (*releaseAsset, string, error) {
req.Header.Set("Accept", "application/vnd.github+json") req.Header.Set("Accept", "application/vnd.github+json")
req.Header.Set("User-Agent", httpUserAgent) req.Header.Set("User-Agent", httpUserAgent)
resp, err := httpClient.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("execute release request: %w", err) return nil, "", fmt.Errorf("execute release request: %w", err)
} }
@@ -150,7 +161,7 @@ func fetchLatestAsset(ctx context.Context) (*releaseAsset, string, error) {
return nil, "", fmt.Errorf("management asset %s not found in latest release", managementAssetName) return nil, "", fmt.Errorf("management asset %s not found in latest release", managementAssetName)
} }
func downloadAsset(ctx context.Context, downloadURL string) ([]byte, string, error) { func downloadAsset(ctx context.Context, client *http.Client, downloadURL string) ([]byte, string, error) {
if strings.TrimSpace(downloadURL) == "" { if strings.TrimSpace(downloadURL) == "" {
return nil, "", fmt.Errorf("empty download url") return nil, "", fmt.Errorf("empty download url")
} }
@@ -161,7 +172,7 @@ func downloadAsset(ctx context.Context, downloadURL string) ([]byte, string, err
} }
req.Header.Set("User-Agent", httpUserAgent) req.Header.Set("User-Agent", httpUserAgent)
resp, err := httpClient.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("execute download request: %w", err) return nil, "", fmt.Errorf("execute download request: %w", err)
} }