mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 20:30:51 +08:00
feat(updater): add fallback URL and logic for missing management asset
This commit is contained in:
@@ -24,10 +24,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultManagementReleaseURL = "https://api.github.com/repos/router-for-me/Cli-Proxy-API-Management-Center/releases/latest"
|
defaultManagementReleaseURL = "https://api.github.com/repos/router-for-me/Cli-Proxy-API-Management-Center/releases/latest"
|
||||||
managementAssetName = "management.html"
|
defaultManagementFallbackURL = "https://cpamc.router-for.me/"
|
||||||
httpUserAgent = "CLIProxyAPI-management-updater"
|
managementAssetName = "management.html"
|
||||||
updateCheckInterval = 3 * time.Hour
|
httpUserAgent = "CLIProxyAPI-management-updater"
|
||||||
|
updateCheckInterval = 3 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
// ManagementFileName exposes the control panel asset filename.
|
// ManagementFileName exposes the control panel asset filename.
|
||||||
@@ -198,6 +199,16 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localPath := filepath.Join(staticDir, managementAssetName)
|
||||||
|
localFileMissing := false
|
||||||
|
if _, errStat := os.Stat(localPath); errStat != nil {
|
||||||
|
if errors.Is(errStat, os.ErrNotExist) {
|
||||||
|
localFileMissing = true
|
||||||
|
} else {
|
||||||
|
log.WithError(errStat).Debug("failed to stat local management asset")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Rate limiting: check only once every 3 hours
|
// Rate limiting: check only once every 3 hours
|
||||||
lastUpdateCheckMu.Lock()
|
lastUpdateCheckMu.Lock()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -210,15 +221,14 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL
|
|||||||
lastUpdateCheckTime = now
|
lastUpdateCheckTime = now
|
||||||
lastUpdateCheckMu.Unlock()
|
lastUpdateCheckMu.Unlock()
|
||||||
|
|
||||||
if err := os.MkdirAll(staticDir, 0o755); err != nil {
|
if errMkdirAll := os.MkdirAll(staticDir, 0o755); errMkdirAll != nil {
|
||||||
log.WithError(err).Warn("failed to prepare static directory for management asset")
|
log.WithError(errMkdirAll).Warn("failed to prepare static directory for management asset")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseURL := resolveReleaseURL(panelRepository)
|
releaseURL := resolveReleaseURL(panelRepository)
|
||||||
client := newHTTPClient(proxyURL)
|
client := newHTTPClient(proxyURL)
|
||||||
|
|
||||||
localPath := filepath.Join(staticDir, managementAssetName)
|
|
||||||
localHash, err := fileSHA256(localPath)
|
localHash, err := fileSHA256(localPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
@@ -229,6 +239,13 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL
|
|||||||
|
|
||||||
asset, remoteHash, err := fetchLatestAsset(ctx, client, releaseURL)
|
asset, remoteHash, err := fetchLatestAsset(ctx, client, releaseURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if localFileMissing {
|
||||||
|
log.WithError(err).Warn("failed to fetch latest management release information, trying fallback page")
|
||||||
|
if ensureFallbackManagementHTML(ctx, client, localPath) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
log.WithError(err).Warn("failed to fetch latest management release information")
|
log.WithError(err).Warn("failed to fetch latest management release information")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -240,6 +257,13 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL
|
|||||||
|
|
||||||
data, downloadedHash, err := downloadAsset(ctx, client, asset.BrowserDownloadURL)
|
data, downloadedHash, err := downloadAsset(ctx, client, asset.BrowserDownloadURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if localFileMissing {
|
||||||
|
log.WithError(err).Warn("failed to download management asset, trying fallback page")
|
||||||
|
if ensureFallbackManagementHTML(ctx, client, localPath) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
log.WithError(err).Warn("failed to download management asset")
|
log.WithError(err).Warn("failed to download management asset")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -256,6 +280,22 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL
|
|||||||
log.Infof("management asset updated successfully (hash=%s)", downloadedHash)
|
log.Infof("management asset updated successfully (hash=%s)", downloadedHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ensureFallbackManagementHTML(ctx context.Context, client *http.Client, localPath string) bool {
|
||||||
|
data, downloadedHash, err := downloadAsset(ctx, client, defaultManagementFallbackURL)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Warn("failed to download fallback management control panel page")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = atomicWriteFile(localPath, data); err != nil {
|
||||||
|
log.WithError(err).Warn("failed to persist fallback management control panel page")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("management asset updated from fallback page successfully (hash=%s)", downloadedHash)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func resolveReleaseURL(repo string) string {
|
func resolveReleaseURL(repo string) string {
|
||||||
repo = strings.TrimSpace(repo)
|
repo = strings.TrimSpace(repo)
|
||||||
if repo == "" {
|
if repo == "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user