diff --git a/pkg/core/backend.go b/pkg/core/backend.go index 9af6ca5..5415fc7 100644 --- a/pkg/core/backend.go +++ b/pkg/core/backend.go @@ -2,8 +2,10 @@ package core import ( "encoding/json" + "errors" "fmt" "net/http" + "os" "time" "code.d7z.net/d7z-project/gitea-pages/pkg/utils" @@ -35,6 +37,9 @@ func (c *CacheBackend) Repos(owner string) (map[string]string, error) { if err != nil { ret, err = c.backend.Repos(owner) if err != nil { + if errors.Is(err, os.ErrNotExist) { + _ = c.config.Put(key, "{}", c.ttl) + } return nil, err } data, err := json.Marshal(data) @@ -49,6 +54,9 @@ func (c *CacheBackend) Repos(owner string) (map[string]string, error) { return nil, err } } + if len(ret) == 0 { + return ret, os.ErrNotExist + } return ret, nil } @@ -59,6 +67,9 @@ func (c *CacheBackend) Branches(owner, repo string) (map[string]string, error) { if err != nil { ret, err = c.backend.Branches(owner, repo) if err != nil { + if errors.Is(err, os.ErrNotExist) { + _ = c.config.Put(key, "{}", c.ttl) + } return nil, err } data, err := json.Marshal(data) @@ -73,6 +84,9 @@ func (c *CacheBackend) Branches(owner, repo string) (map[string]string, error) { return nil, err } } + if len(ret) == 0 { + return ret, os.ErrNotExist + } return ret, nil } diff --git a/pkg/core/meta.go b/pkg/core/meta.go index a784b1e..223b3c4 100644 --- a/pkg/core/meta.go +++ b/pkg/core/meta.go @@ -14,83 +14,108 @@ import ( ) type ServerMeta struct { - client *http.Client - backend Backend - cache utils.Config - ttl time.Duration + client *http.Client + Backend + cache utils.Config + ttl time.Duration + + locker *utils.Locker } type PageMeta struct { - CommitID string `json:"commit_id"` // 提交 COMMIT ID - IsPage bool `json:"is_page"` // 是否为 Page - Domain string `json:"domain"` // 匹配的域名和路径 - HistoryRouteMode bool `json:"route_history"` // 路由模式 + CommitID string `json:"id"` // 提交 COMMIT ID + IsPage bool `json:"pg"` // 是否为 Page + Domain string `json:"dm"` // 匹配的域名 + HistoryRouteMode bool `json:"rt"` // 路由模式 + CustomNotFound bool `json:"404"` // 注册了自定义 404 页面 + +} + +func (m *PageMeta) From(data string) error { + return json.Unmarshal([]byte(data), m) +} + +func (m *PageMeta) String() string { + marshal, _ := json.Marshal(m) + return string(marshal) } func NewServerMeta(client *http.Client, backend Backend, config utils.Config, ttl time.Duration) *ServerMeta { - return &ServerMeta{client, backend, config, ttl} + return &ServerMeta{client, backend, config, ttl, utils.NewLocker()} } -func (s *ServerMeta) Meta(owner, repo, branch string) (*PageMeta, error) { +func (s *ServerMeta) GetMeta(owner, repo, branch string) (*PageMeta, error) { rel := &PageMeta{ IsPage: false, } - key := fmt.Sprintf("meta/%s/%s/%s", owner, repo, branch) - pushMeta := func() error { - data, err := json.Marshal(rel) - if err != nil { - return err + if repos, err := s.Repos(owner); err != nil { + return nil, err + } else { + defBranch := repos[repo] + if defBranch == "" { + return nil, os.ErrNotExist + } + if branch == "" { + branch = defBranch + } + } + if branches, err := s.Branches(owner, repo); err != nil { + return nil, err + } else { + rel.CommitID = branches[branch] + if rel.CommitID == "" { + return nil, os.ErrNotExist } - return s.cache.Put(key, string(data), s.ttl) } + key := fmt.Sprintf("meta/%s/%s/%s", owner, repo, branch) cache, err := s.cache.Get(key) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - return nil, err - } - } else { - if err = json.Unmarshal([]byte(cache), rel); err == nil { + if err != nil && !errors.Is(err, os.ErrNotExist) { + return nil, err + } + if err == nil { + if err = rel.From(cache); err == nil { + if !rel.IsPage { + return nil, os.ErrNotExist + } return rel, nil } } - repos, err := s.backend.Repos(owner) - if err != nil { - return nil, err - } - rel.CommitID = repos[repo] - if rel.CommitID == "" { - _ = pushMeta() - return nil, os.ErrNotExist - } - if branch != "" { - branches, err := s.backend.Branches(owner, repo) - if err != nil { - return nil, err + mux := s.locker.Open(key) + mux.Lock() + defer mux.Unlock() + cache, err = s.cache.Get(key) + if err == nil { + if err = rel.From(cache); err == nil { + if !rel.IsPage { + return nil, os.ErrNotExist + } + return rel, nil } - rel.CommitID = branches[branch] } - if rel.CommitID == "" { - _ = pushMeta() + + if find, _ := s.FileExists(owner, repo, rel.CommitID, "index.html"); !find { + rel.IsPage = false + _ = s.cache.Put(key, rel.String(), s.ttl) return nil, os.ErrNotExist } + if find, _ := s.FileExists(owner, repo, rel.CommitID, "404.html"); !find { + rel.CustomNotFound = true + } if cname, err := s.ReadString(owner, repo, rel.CommitID, "CNAME"); err != nil && !errors.Is(err, os.ErrNotExist) { return nil, err } else { rel.Domain = strings.TrimSpace(cname) } - if find, _ := s.FileExists(owner, repo, rel.CommitID, "index.html"); find { - rel.IsPage = true - } - if find, _ := s.FileExists(owner, repo, rel.CommitID, ".history-mode"); find { + if find, _ := s.FileExists(owner, repo, rel.CommitID, ".history"); find { rel.HistoryRouteMode = true } - _ = pushMeta() + _ = s.cache.Put(key, rel.String(), s.ttl) return rel, nil } func (s *ServerMeta) ReadString(owner, repo, branch, path string) (string, error) { - resp, err := s.backend.Open(s.client, owner, repo, branch, path, nil) + resp, err := s.Open(s.client, owner, repo, branch, path, nil) if err != nil { return "", err } @@ -106,7 +131,7 @@ 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.backend.Open(s.client, owner, repo, branch, path, nil) + resp, err := s.Open(s.client, owner, repo, branch, path, nil) if err != nil { return false, err } diff --git a/pkg/core/page.go b/pkg/core/page.go new file mode 100644 index 0000000..f692a5e --- /dev/null +++ b/pkg/core/page.go @@ -0,0 +1,9 @@ +package core + +type PageContent struct { + meta PageMeta +} + +func (p *PageContent) GetMeta(domain, path string) (*PageMeta, error) { + +} diff --git a/pkg/server.go b/pkg/server.go index 18f220e..733a929 100644 --- a/pkg/server.go +++ b/pkg/server.go @@ -15,6 +15,8 @@ type ServerOptions struct { Cache utils.Cache MaxCacheSize int + + HttpClient *http.Client } func DefaultOptions(domain string) ServerOptions { @@ -24,22 +26,25 @@ func DefaultOptions(domain string) ServerOptions { Config: configMemory, Cache: utils.NewCacheMemory(1024*1024*10, int(memory.FreeMemory()/3*2)), MaxCacheSize: 1024 * 1024 * 10, + HttpClient: http.DefaultClient, } } type Server struct { - backend core.Backend + meta *core.ServerMeta options *ServerOptions } func NewPageServer(backend core.Backend, options ServerOptions) *Server { + backend = core.NewCacheBackend(backend, options.Config, time.Minute) return &Server{ - backend: core.NewCacheBackend(backend, options.Config, time.Minute), + meta: core.NewServerMeta(options.HttpClient, backend, options.Config, time.Minute), options: &options, } } func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { + } func (s *Server) Close() error { diff --git a/pkg/utils/locker.go b/pkg/utils/locker.go new file mode 100644 index 0000000..728953b --- /dev/null +++ b/pkg/utils/locker.go @@ -0,0 +1,17 @@ +package utils + +import "sync" + +type Locker struct { + sy sync.Map +} + +func NewLocker() *Locker { + return &Locker{ + sy: sync.Map{}, + } +} +func (l *Locker) Open(key string) *sync.Mutex { + actual, _ := l.sy.LoadOrStore(key, &sync.Mutex{}) + return actual.(*sync.Mutex) +}