补充实现细节

This commit is contained in:
dragon
2025-01-07 17:04:39 +08:00
parent bb8966521c
commit 0172dceaa8
9 changed files with 278 additions and 49 deletions

View File

@@ -1,23 +1,32 @@
package core
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"strconv"
"time"
"code.d7z.net/d7z-project/gitea-pages/pkg/utils"
)
type BranchInfo struct {
ID string `json:"id"`
LastModified time.Time `json:"last_modified"`
}
type Backend interface {
// Repos return repo name + default branch
Repos(owner string) (map[string]string, error)
// Branches return branch + commit id
Branches(owner, repo string) (map[string]string, error)
Branches(owner, repo string) (map[string]*BranchInfo, error)
// Open return file or error
Open(client *http.Client, owner, repo, commit, path string, headers map[string]string) (*http.Response, error)
Open(client *http.Client, owner, repo, commit, path string, headers http.Header) (*http.Response, error)
}
type CacheBackend struct {
@@ -60,8 +69,8 @@ func (c *CacheBackend) Repos(owner string) (map[string]string, error) {
return ret, nil
}
func (c *CacheBackend) Branches(owner, repo string) (map[string]string, error) {
ret := make(map[string]string)
func (c *CacheBackend) Branches(owner, repo string) (map[string]*BranchInfo, error) {
ret := make(map[string]*BranchInfo)
key := fmt.Sprintf("branches/%s/%s", owner, repo)
data, err := c.config.Get(key)
if err != nil {
@@ -90,6 +99,72 @@ func (c *CacheBackend) Branches(owner, repo string) (map[string]string, error) {
return ret, nil
}
func (c *CacheBackend) Open(client *http.Client, owner, repo, commit, path string, headers map[string]string) (*http.Response, error) {
func (c *CacheBackend) Open(client *http.Client, owner, repo, commit, path string, headers http.Header) (*http.Response, error) {
return c.backend.Open(client, owner, repo, commit, path, headers)
}
type CacheBackendBlobReader struct {
client *http.Client
cache utils.Cache
base Backend
maxSize int
}
func NewCacheBackendBlobReader(client *http.Client, base Backend, cache utils.Cache, maxCacheSize int) *CacheBackendBlobReader {
return &CacheBackendBlobReader{client: client, base: base, cache: cache, maxSize: maxCacheSize}
}
func (c *CacheBackendBlobReader) Open(owner, repo, commit, path string) (io.ReadCloser, error) {
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
} else if lastCache == nil && err == nil {
// 边界缓存
return nil, os.ErrNotExist
} else if lastCache != nil {
return lastCache, nil
}
open, err := c.base.Open(c.client, owner, repo, commit, path, http.Header{})
if err != 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)
}
lastMod, err := time.Parse(http.TimeFormat, open.Header.Get("Last-Modified"))
if err != nil {
// 无时间,跳过
return open.Body, nil
}
// 没法计算大小,跳过
lengthStr := open.Header.Get("Content-Length")
if lengthStr == "" {
return open.Body, nil
}
length, err := strconv.Atoi(lengthStr)
if err != nil || length > c.maxSize {
// 超过最大大小,跳过
return open.Body, err
}
defer open.Body.Close()
allBytes, err := io.ReadAll(open.Body)
if err != nil {
return nil, err
}
if err = c.cache.Put(key, bytes.NewBuffer(allBytes)); err != nil {
slog.Warn("缓存归档失败", "error", err)
}
return &utils.CacheContent{
ReadSeekCloser: utils.NopCloser{
ReadSeeker: bytes.NewReader(allBytes),
},
LastModified: lastMod,
Length: length,
}, nil
}