From 1e9d24096c04bb2257c8f3b7e4bc7061856f8af2 Mon Sep 17 00:00:00 2001 From: dragon Date: Wed, 8 Jan 2025 17:10:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=AE=9E=E7=8E=B0=E7=BB=86?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 3 +++ go.sum | 6 ++++++ main.go | 24 ++++++++++++++++-------- pkg/core/backend.go | 36 ++++++++++++++++++++---------------- pkg/core/backend_test.go | 14 ++++++++++++++ pkg/core/meta.go | 29 ++++++++++++++++++----------- pkg/core/page.go | 31 +++++++++++++++++++------------ pkg/providers/gitea.go | 6 +----- pkg/server.go | 19 +++++++++++-------- pkg/utils/cache.go | 3 ++- pkg/utils/error.go | 7 +++++++ 11 files changed, 117 insertions(+), 61 deletions(-) create mode 100644 pkg/core/backend_test.go create mode 100644 pkg/utils/error.go diff --git a/go.mod b/go.mod index 8d01e42..9ec68aa 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,10 @@ require ( github.com/go-fed/httpsig v1.1.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/sys v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 09adaf7..139cccb 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -20,6 +22,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= diff --git a/main.go b/main.go index 63f02e7..34a775e 100644 --- a/main.go +++ b/main.go @@ -3,10 +3,11 @@ package main import ( "flag" "log" - "log/slog" "net/http" "os" + "go.uber.org/zap" + "code.d7z.net/d7z-project/gitea-pages/pkg" "code.d7z.net/d7z-project/gitea-pages/pkg/providers" @@ -26,7 +27,8 @@ func init() { func main() { flag.Parse() - debugInject() + inject := debugInject() + defer inject() loadConf() gitea, err := providers.NewGitea(config.Auth.Server, config.Auth.Token) if err != nil { @@ -39,14 +41,20 @@ func main() { _ = http.ListenAndServe(config.Bind, mux) } -func debugInject() { - programLevel := new(slog.LevelVar) - programLevel.Set(slog.LevelDebug) +func debugInject() func() error { + atom := zap.NewAtomicLevel() if debug { - h := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - slog.SetDefault(slog.New(h)) + atom.SetLevel(zap.DebugLevel) + } else { + atom.SetLevel(zap.InfoLevel) } - slog.Debug("debug mode") + cfg := zap.NewProductionConfig() + cfg.Level = atom + + logger, _ := cfg.Build() + zap.ReplaceGlobals(logger) + zap.L().Debug("debug enabled") + return logger.Sync } func loadConf() { diff --git a/pkg/core/backend.go b/pkg/core/backend.go index a3d6718..3accb20 100644 --- a/pkg/core/backend.go +++ b/pkg/core/backend.go @@ -3,15 +3,17 @@ package core import ( "bytes" "encoding/json" - "errors" + stdErr "errors" "fmt" "io" - "log/slog" "net/http" "os" "strconv" "time" + "github.com/pkg/errors" + "go.uber.org/zap" + "code.d7z.net/d7z-project/gitea-pages/pkg/utils" ) @@ -25,7 +27,7 @@ type Backend interface { Repos(owner string) (map[string]string, error) // Branches return branch + commit id Branches(owner, repo string) (map[string]*BranchInfo, error) - // Open return file or error + // Open return file or error (error) Open(client *http.Client, owner, repo, commit, path string, headers http.Header) (*http.Response, error) } @@ -42,7 +44,7 @@ func NewCacheBackend(backend Backend, config utils.Config, ttl time.Duration) *C func (c *CacheBackend) Repos(owner string) (map[string]string, error) { ret := make(map[string]string) key := fmt.Sprintf("repos/%s", owner) - data, err := c.config.Get(key) + store, err := c.config.Get(key) if err != nil { ret, err = c.backend.Repos(owner) if err != nil { @@ -51,15 +53,15 @@ func (c *CacheBackend) Repos(owner string) (map[string]string, error) { } return nil, err } - data, err := json.Marshal(data) + storeBin, err := json.Marshal(ret) if err != nil { return nil, err } - if err = c.config.Put(key, string(data), c.ttl); err != nil { + if err = c.config.Put(key, string(storeBin), c.ttl); err != nil { return nil, err } } else { - if err := json.Unmarshal([]byte(data), &ret); err != nil { + if err := json.Unmarshal([]byte(store), &ret); err != nil { return nil, err } } @@ -81,7 +83,7 @@ func (c *CacheBackend) Branches(owner, repo string) (map[string]*BranchInfo, err } return nil, err } - data, err := json.Marshal(data) + data, err := json.Marshal(ret) if err != nil { return nil, err } @@ -115,7 +117,7 @@ func NewCacheBackendBlobReader(client *http.Client, base Backend, cache utils.Ca } func (c *CacheBackendBlobReader) Open(owner, repo, commit, path string) (io.ReadCloser, error) { - key := fmt.Sprintf("%s/%s/%s%s", owner, repo, commit, path) + key := fmt.Sprintf("%s/%s/%s/%s", owner, repo, commit, path) lastCache, err := c.cache.Get(key) if err != nil && !errors.Is(err, os.ErrNotExist) { return nil, err @@ -126,15 +128,17 @@ func (c *CacheBackendBlobReader) Open(owner, repo, commit, path string) (io.Read return lastCache, nil } open, err := c.base.Open(c.client, owner, repo, commit, path, http.Header{}) - if err != nil { + if err != nil || open == nil { if open != nil { - if open.StatusCode == http.StatusNotFound { - // 缓存 404 路由 - _ = c.cache.Put(key, nil) - } _ = open.Body.Close() } - return nil, errors.Join(err, os.ErrNotExist) + return nil, stdErr.Join(err, os.ErrNotExist) + } + if open.StatusCode == http.StatusNotFound { + // 缓存 404 路由 + _ = c.cache.Put(key, nil) + _ = open.Body.Close() + return nil, os.ErrNotExist } lastMod, err := time.Parse(http.TimeFormat, open.Header.Get("Last-Modified")) @@ -158,7 +162,7 @@ func (c *CacheBackendBlobReader) Open(owner, repo, commit, path string) (io.Read return nil, err } if err = c.cache.Put(key, bytes.NewBuffer(allBytes)); err != nil { - slog.Warn("缓存归档失败", "error", err) + zap.S().Warn("缓存归档失败", zap.Error(err)) } return &utils.CacheContent{ ReadSeekCloser: utils.NopCloser{ diff --git a/pkg/core/backend_test.go b/pkg/core/backend_test.go new file mode 100644 index 0000000..478c01e --- /dev/null +++ b/pkg/core/backend_test.go @@ -0,0 +1,14 @@ +package core + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAny(t *testing.T) { + data := make(map[string]string) + err := json.Unmarshal([]byte(`{}`), &data) + require.NoError(t, err) +} diff --git a/pkg/core/meta.go b/pkg/core/meta.go index 13ae92f..2423322 100644 --- a/pkg/core/meta.go +++ b/pkg/core/meta.go @@ -2,7 +2,6 @@ package core import ( "encoding/json" - "errors" "fmt" "io" "net/http" @@ -10,6 +9,8 @@ import ( "strings" "time" + "github.com/pkg/errors" + "code.d7z.net/d7z-project/gitea-pages/pkg/utils" ) @@ -24,12 +25,12 @@ type ServerMeta struct { } type PageMetaContent struct { - CommitID string `json:"id"` // 提交 COMMIT ID - IsPage bool `json:"pg"` // 是否为 Page - Domain string `json:"dm"` // 匹配的域名 - HistoryRouteMode bool `json:"rt"` // 路由模式 - CustomNotFound bool `json:"404"` // 注册了自定义 404 页面 - LastModified time.Time `json:"up"` // 上次更新时间 + CommitID string `json:"id"` // 提交 COMMIT ID + IsPage bool `json:"pg"` // 是否为 Page + Domain string `json:"domain"` // 匹配的域名 + HistoryRouteMode bool `json:"historyRouteMode"` // 路由模式 + CustomNotFound bool `json:"404"` // 注册了自定义 404 页面 + LastModified time.Time `json:"up"` // 上次更新时间 } func (m *PageMetaContent) From(data string) error { @@ -101,6 +102,8 @@ func (s *ServerMeta) GetMeta(owner, repo, branch string) (*PageMetaContent, erro rel.IsPage = false _ = s.cache.Put(key, rel.String(), s.ttl) return nil, os.ErrNotExist + } else { + rel.IsPage = true } if find, _ := s.FileExists(owner, repo, rel.CommitID, "404.html"); !find { rel.CustomNotFound = true @@ -119,10 +122,12 @@ func (s *ServerMeta) GetMeta(owner, repo, branch string) (*PageMetaContent, erro func (s *ServerMeta) ReadString(owner, repo, branch, path string) (string, error) { resp, err := s.Open(s.client, owner, repo, branch, path, nil) - if err != nil { + if resp != nil { + defer resp.Body.Close() + } + if err != nil || resp == nil { return "", err } - defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "", os.ErrNotExist } @@ -135,10 +140,12 @@ func (s *ServerMeta) ReadString(owner, repo, branch, path string) (string, error func (s *ServerMeta) FileExists(owner, repo, branch, path string) (bool, error) { resp, err := s.Open(s.client, owner, repo, branch, path, nil) - if err != nil { + if resp != nil { + defer resp.Body.Close() + } + if err != nil || resp == nil { return false, err } - defer resp.Body.Close() if resp.StatusCode == http.StatusOK { return true, nil } diff --git a/pkg/core/page.go b/pkg/core/page.go index 7255b0e..5491cbd 100644 --- a/pkg/core/page.go +++ b/pkg/core/page.go @@ -1,11 +1,13 @@ package core import ( - "errors" "fmt" - "log/slog" "os" + "regexp" "strings" + + "github.com/pkg/errors" + "go.uber.org/zap" ) type PageDomain struct { @@ -32,27 +34,28 @@ type PageDomainContent struct { } func (m *PageDomainContent) CacheKey() string { - return fmt.Sprintf("%s/%s/%s%s", m.Owner, m.Repo, m.CommitID, m.Path) + return fmt.Sprintf("%s/%s/%s/%s", m.Owner, m.Repo, m.CommitID, m.Path) } func (p *PageDomain) ParseDomainMeta(domain, path, branch string) (*PageDomainContent, error) { if branch == "" { branch = p.defaultBranch } + domain = regexp.MustCompile(`:\d+$`).ReplaceAllString(domain, "") rel := &PageDomainContent{} if !strings.HasSuffix(domain, "."+p.baseDomain) { - slog.Debug("Page Domain does not end with ."+p.baseDomain, "domain", domain) + zap.L().Warn("Page Domain does not end with ."+p.baseDomain, zap.String("domain", domain)) return nil, os.ErrNotExist } - rel.Owner = strings.TrimSuffix(domain, "."+p.baseDomain) pathS := strings.Split(strings.TrimPrefix(path, "/"), "/") - repo := pathS[0] + rel.Repo = pathS[0] defaultRepo := rel.Owner + "." + p.baseDomain - if repo == "" { + if rel.Repo == "" { // 回退到默认仓库 rel.Repo = defaultRepo + zap.L().Debug("fail back to default repo", zap.String("repo", defaultRepo)) } meta, err := p.GetMeta(rel.Owner, rel.Repo, branch) @@ -60,7 +63,10 @@ func (p *PageDomain) ParseDomainMeta(domain, path, branch string) (*PageDomainCo return nil, err } if err == nil { - rel.Path = "/" + strings.Join(pathS[1:], "/") + rel.Path = strings.Join(pathS[1:], "/") + if strings.HasSuffix(rel.Path, "/") || rel.Path == "" { + rel.Path = rel.Path + "index.html" + } rel.PageMetaContent = meta return rel, nil } @@ -70,11 +76,12 @@ func (p *PageDomain) ParseDomainMeta(domain, path, branch string) (*PageDomainCo if meta, err := p.GetMeta(rel.Owner, defaultRepo, branch); err == nil { rel.PageMetaContent = meta rel.Repo = defaultRepo - rel.Path = "/" + strings.Join(pathS, "/") + rel.Path = strings.Join(pathS[1:], "/") + if strings.HasSuffix(rel.Path, "/") || rel.Path == "" { + rel.Path = rel.Path + "index.html" + } return rel, nil } - if strings.HasSuffix(path, "/") { - rel.Path = rel.Path + "/index.html" - } + return nil, os.ErrNotExist } diff --git a/pkg/providers/gitea.go b/pkg/providers/gitea.go index 6891eff..df84f58 100644 --- a/pkg/providers/gitea.go +++ b/pkg/providers/gitea.go @@ -121,9 +121,5 @@ func (g *ProviderGitea) Open(client *http.Client, owner, repo, commit, path stri } } req.Header.Add("Authorization", "token "+g.Token) - resp, err := client.Do(req) - if err != nil && resp == nil { - return nil, err - } - return resp, nil + return client.Do(req) } diff --git a/pkg/server.go b/pkg/server.go index d40aa80..8e68f5b 100644 --- a/pkg/server.go +++ b/pkg/server.go @@ -1,7 +1,6 @@ package pkg import ( - "errors" "io" "mime" "net/http" @@ -9,6 +8,9 @@ import ( "path/filepath" "time" + "github.com/pkg/errors" + "go.uber.org/zap" + "code.d7z.net/d7z-project/gitea-pages/pkg/core" "code.d7z.net/d7z-project/gitea-pages/pkg/utils" "github.com/pbnjay/memory" @@ -57,7 +59,7 @@ func NewPageServer(backend core.Backend, options ServerOptions) *Server { } func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { - meta, err := s.meta.ParseDomainMeta(request.Host, request.RequestURI, request.URL.Query().Get("branch")) + meta, err := s.meta.ParseDomainMeta(request.Host, request.URL.Path, request.URL.Query().Get("branch")) if err != nil { if errors.Is(err, os.ErrNotExist) { s.writeNotfoundError(writer, request.RequestURI) @@ -68,6 +70,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { } result, err := s.reader.Open(meta.Owner, meta.Repo, meta.CommitID, meta.Path) if err != nil { + // todo: 添加默认返回 if errors.Is(err, os.ErrNotExist) { s.writeNotfoundError(writer, request.RequestURI) } else { @@ -80,16 +83,16 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { http.ServeContent(writer, request, fileName, reader.LastModified, reader) _ = reader.Close() return - } else { - writer.Header().Set("Content-Type", mime.TypeByExtension(meta.Path)) - writer.WriteHeader(http.StatusOK) - _, _ = io.Copy(writer, reader) - _ = reader.Close() - return } + writer.Header().Set("Content-Type", mime.TypeByExtension(meta.Path)) + writer.WriteHeader(http.StatusOK) + _, _ = io.Copy(writer, result) + _ = result.Close() + return } func (s *Server) writeError(writer http.ResponseWriter, err error) { + zap.L().Error("write error", zap.Error(err)) http.Error(writer, err.Error(), http.StatusInternalServerError) } diff --git a/pkg/utils/cache.go b/pkg/utils/cache.go index 88e9d11..973d614 100644 --- a/pkg/utils/cache.go +++ b/pkg/utils/cache.go @@ -2,12 +2,13 @@ package utils import ( "bytes" - "errors" "io" "os" "strings" "sync" "time" + + "github.com/pkg/errors" ) type CacheContent struct { diff --git a/pkg/utils/error.go b/pkg/utils/error.go new file mode 100644 index 0000000..1d23fc1 --- /dev/null +++ b/pkg/utils/error.go @@ -0,0 +1,7 @@ +package utils + +import "github.com/pkg/errors" + +type StackTracer interface { + StackTrace() errors.StackTrace +}