From 042cfd448c54bfef2386260ffd7ec5efe54951d5 Mon Sep 17 00:00:00 2001 From: kone Date: Fri, 15 May 2026 23:06:59 +0800 Subject: [PATCH] release: prepare v0.1.133 --- backend/cmd/server/VERSION | 2 +- backend/internal/config/config.go | 4 +++ .../repository/github_release_service.go | 34 +++++++++++++++--- .../repository/github_release_service_test.go | 36 +++++++++++++++++++ backend/internal/repository/wire.go | 2 +- deploy/config.example.yaml | 8 +++++ deploy/docker-compose.local.yml | 3 ++ deploy/docker-compose.standalone.yml | 7 ++++ deploy/docker-compose.yml | 3 ++ 9 files changed, 93 insertions(+), 6 deletions(-) diff --git a/backend/cmd/server/VERSION b/backend/cmd/server/VERSION index 7b9dfc4d..56ebc9e5 100644 --- a/backend/cmd/server/VERSION +++ b/backend/cmd/server/VERSION @@ -1 +1 @@ -0.1.132 +0.1.133 diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 8fd823ac..592fdc45 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -150,6 +150,9 @@ type GeminiTierQuotaConfig struct { type UpdateConfig struct { // GitHubRepo 用于在线更新的 GitHub 仓库,格式 owner/repo GitHubRepo string `mapstructure:"github_repo"` + // GitHubMirrorBaseURL 用于通过 GitHub 镜像站访问 API 和 Release 下载地址。 + // 为空时不启用;不含 {url} 时会拼接为 /。 + GitHubMirrorBaseURL string `mapstructure:"github_mirror_base_url"` // ProxyURL 用于访问 GitHub 的代理地址 // 支持 http/https/socks5/socks5h 协议 // 例如: "http://127.0.0.1:7890", "socks5://127.0.0.1:1080" @@ -1613,6 +1616,7 @@ func setDefaults() { // Update viper.SetDefault("update.github_repo", "man209111-cpu/sub2api") + viper.SetDefault("update.github_mirror_base_url", "") viper.SetDefault("update.proxy_url", "") // Timezone (default to Asia/Shanghai for Chinese users) diff --git a/backend/internal/repository/github_release_service.go b/backend/internal/repository/github_release_service.go index ad1f22e3..74eb340c 100644 --- a/backend/internal/repository/github_release_service.go +++ b/backend/internal/repository/github_release_service.go @@ -7,6 +7,7 @@ import ( "io" "log/slog" "net/http" + "net/url" "os" "strings" "time" @@ -18,6 +19,7 @@ import ( type githubReleaseClient struct { httpClient *http.Client downloadHTTPClient *http.Client + mirrorBaseURL string } type githubReleaseClientError struct { @@ -29,7 +31,7 @@ type githubReleaseClientError struct { // 代理配置失败时行为由 allowDirectOnProxyError 控制: // - false(默认):返回错误占位客户端,禁止回退到直连 // - true:回退到直连(仅限管理员显式开启) -func NewGitHubReleaseClient(proxyURL string, allowDirectOnProxyError bool) service.GitHubReleaseClient { +func NewGitHubReleaseClient(proxyURL string, githubMirrorBaseURL string, allowDirectOnProxyError bool) service.GitHubReleaseClient { // 安全说明:httpclient.GetClient 的错误链(url.Parse / proxyutil)不含明文代理凭据, // 但仍通过 slog 仅在服务端日志记录,不会暴露给 HTTP 响应。 sharedClient, err := httpclient.GetClient(httpclient.Options{ @@ -60,6 +62,7 @@ func NewGitHubReleaseClient(proxyURL string, allowDirectOnProxyError bool) servi return &githubReleaseClient{ httpClient: sharedClient, downloadHTTPClient: downloadClient, + mirrorBaseURL: normalizeMirrorBaseURL(githubMirrorBaseURL), } } @@ -78,7 +81,7 @@ func (c *githubReleaseClientError) FetchChecksumFile(ctx context.Context, url st func (c *githubReleaseClient) FetchLatestRelease(ctx context.Context, repo string) (*service.GitHubRelease, error) { url := fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", repo) - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.rewriteURL(url), nil) if err != nil { return nil, err } @@ -104,7 +107,7 @@ func (c *githubReleaseClient) FetchLatestRelease(ctx context.Context, repo strin } func (c *githubReleaseClient) DownloadFile(ctx context.Context, url, dest string, maxSize int64) error { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.rewriteURL(url), nil) if err != nil { return err } @@ -152,7 +155,7 @@ func (c *githubReleaseClient) DownloadFile(ctx context.Context, url, dest string } func (c *githubReleaseClient) FetchChecksumFile(ctx context.Context, url string) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.rewriteURL(url), nil) if err != nil { return nil, err } @@ -169,3 +172,26 @@ func (c *githubReleaseClient) FetchChecksumFile(ctx context.Context, url string) return io.ReadAll(resp.Body) } + +func (c *githubReleaseClient) rewriteURL(originalURL string) string { + if c == nil || c.mirrorBaseURL == "" { + return originalURL + } + if strings.Contains(c.mirrorBaseURL, "{url}") { + return strings.ReplaceAll(c.mirrorBaseURL, "{url}", originalURL) + } + return strings.TrimRight(c.mirrorBaseURL, "/") + "/" + originalURL +} + +func normalizeMirrorBaseURL(raw string) string { + raw = strings.TrimSpace(raw) + if raw == "" { + return "" + } + parsed, err := url.Parse(raw) + if err != nil || parsed.Scheme != "https" || parsed.Host == "" { + slog.Warn("invalid github mirror base url, mirror disabled", "service", "github_release") + return "" + } + return strings.TrimRight(raw, "/") +} diff --git a/backend/internal/repository/github_release_service_test.go b/backend/internal/repository/github_release_service_test.go index d375a193..9dcb65af 100644 --- a/backend/internal/repository/github_release_service_test.go +++ b/backend/internal/repository/github_release_service_test.go @@ -245,6 +245,42 @@ func (s *GitHubReleaseServiceSuite) TestFetchLatestRelease_Success() { require.Equal(s.T(), "app-linux-amd64.tar.gz", release.Assets[0].Name) } +func (s *GitHubReleaseServiceSuite) TestFetchLatestRelease_UsesMirrorBaseURL() { + releaseJSON := `{ + "tag_name": "v1.0.0", + "name": "Release 1.0.0", + "body": "Release notes", + "html_url": "https://github.com/test/repo/releases/v1.0.0", + "assets": [] + }` + + s.srv = newLocalTestServer(s.T(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(s.T(), "/https://api.github.com/repos/test/repo/releases/latest", r.URL.Path) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(releaseJSON)) + })) + + s.client = &githubReleaseClient{ + httpClient: s.srv.Client(), + downloadHTTPClient: &http.Client{}, + mirrorBaseURL: s.srv.URL, + } + + release, err := s.client.FetchLatestRelease(context.Background(), "test/repo") + require.NoError(s.T(), err) + require.Equal(s.T(), "v1.0.0", release.TagName) +} + +func (s *GitHubReleaseServiceSuite) TestRewriteURL_UsesTemplateMirror() { + s.client = &githubReleaseClient{ + mirrorBaseURL: "https://mirror.example.com/{url}", + } + + got := s.client.rewriteURL("https://github.com/test/repo/releases/download/v1/app.tar.gz") + require.Equal(s.T(), "https://mirror.example.com/https://github.com/test/repo/releases/download/v1/app.tar.gz", got) +} + func (s *GitHubReleaseServiceSuite) TestFetchLatestRelease_Non200() { s.srv = newLocalTestServer(s.T(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) diff --git a/backend/internal/repository/wire.go b/backend/internal/repository/wire.go index 3c0ee9cb..e9c09dfa 100644 --- a/backend/internal/repository/wire.go +++ b/backend/internal/repository/wire.go @@ -28,7 +28,7 @@ func ProvideConcurrencyCache(rdb *redis.Client, cfg *config.Config) service.Conc // ProvideGitHubReleaseClient 创建 GitHub Release 客户端 // 从配置中读取代理设置,支持国内服务器通过代理访问 GitHub func ProvideGitHubReleaseClient(cfg *config.Config) service.GitHubReleaseClient { - return NewGitHubReleaseClient(cfg.Update.ProxyURL, cfg.Security.ProxyFallback.AllowDirectOnError) + return NewGitHubReleaseClient(cfg.Update.ProxyURL, cfg.Update.GitHubMirrorBaseURL, cfg.Security.ProxyFallback.AllowDirectOnError) } // ProvidePricingRemoteClient 创建定价数据远程客户端 diff --git a/deploy/config.example.yaml b/deploy/config.example.yaml index 188b5fcf..1015757e 100644 --- a/deploy/config.example.yaml +++ b/deploy/config.example.yaml @@ -1084,6 +1084,14 @@ update: # GitHub repository used for online update checks and binary downloads. # 在线更新检查和二进制下载使用的 GitHub 仓库。 github_repo: "man209111-cpu/sub2api" + # GitHub mirror base URL for online updates. + # 在线更新使用的 GitHub 镜像站前缀。 + # Examples: + # - "https://gh.llkk.cc" + # - "https://mirror.example.com/{url}" + # Leave empty for direct GitHub URLs. + # 留空表示使用原始 GitHub 地址。 + github_mirror_base_url: "" # Proxy URL for accessing GitHub (used for online updates and pricing data) # 用于访问 GitHub 的代理地址(用于在线更新和定价数据获取) # Supports: http, https, socks5, socks5h diff --git a/deploy/docker-compose.local.yml b/deploy/docker-compose.local.yml index a9e5a223..18f4ce83 100644 --- a/deploy/docker-compose.local.yml +++ b/deploy/docker-compose.local.yml @@ -146,6 +146,9 @@ services: # ======================================================================= # GitHub repo for online update checks and binary downloads - UPDATE_GITHUB_REPO=${UPDATE_GITHUB_REPO:-man209111-cpu/sub2api} + # GitHub mirror base URL for online updates. + # Example: https://gh.llkk.cc or https://mirror.example.com/{url} + - UPDATE_GITHUB_MIRROR_BASE_URL=${UPDATE_GITHUB_MIRROR_BASE_URL:-} # Proxy for accessing GitHub (online updates + pricing data) # Examples: http://host:port, socks5://host:port - UPDATE_PROXY_URL=${UPDATE_PROXY_URL:-} diff --git a/deploy/docker-compose.standalone.yml b/deploy/docker-compose.standalone.yml index 44383dbe..aba48e65 100644 --- a/deploy/docker-compose.standalone.yml +++ b/deploy/docker-compose.standalone.yml @@ -89,6 +89,13 @@ services: - GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-} - GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-} + # ======================================================================= + # Update Configuration (在线更新配置) + # ======================================================================= + - UPDATE_GITHUB_REPO=${UPDATE_GITHUB_REPO:-man209111-cpu/sub2api} + - UPDATE_GITHUB_MIRROR_BASE_URL=${UPDATE_GITHUB_MIRROR_BASE_URL:-} + - UPDATE_PROXY_URL=${UPDATE_PROXY_URL:-} + # Built-in OAuth client secrets (optional) # SECURITY: This repo does not embed third-party client_secret. - GEMINI_CLI_OAUTH_CLIENT_SECRET=${GEMINI_CLI_OAUTH_CLIENT_SECRET:-} diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index fdaeb8fa..bd32d087 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -142,6 +142,9 @@ services: # ======================================================================= # GitHub repo for online update checks and binary downloads - UPDATE_GITHUB_REPO=${UPDATE_GITHUB_REPO:-man209111-cpu/sub2api} + # GitHub mirror base URL for online updates. + # Example: https://gh.llkk.cc or https://mirror.example.com/{url} + - UPDATE_GITHUB_MIRROR_BASE_URL=${UPDATE_GITHUB_MIRROR_BASE_URL:-} # Proxy for accessing GitHub (online updates + pricing data) # Examples: http://host:port, socks5://host:port - UPDATE_PROXY_URL=${UPDATE_PROXY_URL:-}