pages-server/server/gitea/cache.go

117 lines
3 KiB
Go
Raw Normal View History

package gitea
2022-09-18 19:02:55 +00:00
import (
2022-09-18 20:41:52 +00:00
"bytes"
"fmt"
2022-09-18 20:41:52 +00:00
"io"
2022-09-18 19:02:55 +00:00
"net/http"
"time"
2022-09-18 20:41:52 +00:00
2022-11-07 22:43:20 +00:00
"github.com/rs/zerolog/log"
2022-09-18 20:41:52 +00:00
"codeberg.org/codeberg/pages/server/cache"
)
const (
// defaultBranchCacheTimeout specifies the timeout for the default branch cache. It can be quite long.
defaultBranchCacheTimeout = 15 * time.Minute
// branchExistenceCacheTimeout specifies the timeout for the branch timestamp & existence cache. It should be shorter
// than fileCacheTimeout, as that gets invalidated if the branch timestamp has changed. That way, repo changes will be
// picked up faster, while still allowing the content to be cached longer if nothing changes.
branchExistenceCacheTimeout = 5 * time.Minute
// fileCacheTimeout specifies the timeout for the file content cache - you might want to make this quite long, depending
// on your available memory.
// TODO: move as option into cache interface
fileCacheTimeout = 5 * time.Minute
// fileCacheSizeLimit limits the maximum file size that will be cached, and is set to 1 MB by default.
2022-11-11 23:08:56 +00:00
fileCacheSizeLimit = int64(1000 * 1000)
2022-09-18 19:02:55 +00:00
)
2022-07-27 13:39:46 +00:00
type FileResponse struct {
2022-09-18 19:02:55 +00:00
Exists bool
IsSymlink bool
ETag string
MimeType string
Body []byte
}
func (f FileResponse) IsEmpty() bool {
return len(f.Body) != 0
}
2022-07-27 13:39:46 +00:00
2022-11-07 23:15:09 +00:00
func (f FileResponse) createHttpResponse(cacheKey string) (http.Header, int) {
2022-11-07 23:05:27 +00:00
header := make(http.Header)
2022-11-07 23:06:10 +00:00
var statusCode int
2022-09-18 19:02:55 +00:00
if f.Exists {
2022-11-07 23:05:27 +00:00
statusCode = http.StatusOK
2022-09-18 19:02:55 +00:00
} else {
2022-11-07 23:05:27 +00:00
statusCode = http.StatusNotFound
2022-09-18 19:02:55 +00:00
}
if f.IsSymlink {
2022-11-07 23:05:27 +00:00
header.Set(giteaObjectTypeHeader, objTypeSymlink)
2022-09-18 19:02:55 +00:00
}
2022-11-07 23:05:27 +00:00
header.Set(ETagHeader, f.ETag)
header.Set(ContentTypeHeader, f.MimeType)
header.Set(ContentLengthHeader, fmt.Sprintf("%d", len(f.Body)))
2022-11-07 23:05:27 +00:00
header.Set(PagesCacheIndicatorHeader, "true")
2022-09-18 19:02:55 +00:00
2022-11-11 23:15:06 +00:00
log.Trace().Msgf("fileCache for %q used", cacheKey)
2022-11-07 23:05:27 +00:00
return header, statusCode
2022-09-18 19:02:55 +00:00
}
2022-07-27 13:39:46 +00:00
type BranchTimestamp struct {
Branch string
Timestamp time.Time
notFound bool
2022-07-27 13:39:46 +00:00
}
2022-09-18 20:41:52 +00:00
type writeCacheReader struct {
originalReader io.ReadCloser
buffer *bytes.Buffer
rileResponse *FileResponse
cacheKey string
cache cache.SetGetKey
hasError bool
2022-09-18 20:41:52 +00:00
}
2022-07-27 13:39:46 +00:00
2022-09-18 20:41:52 +00:00
func (t *writeCacheReader) Read(p []byte) (n int, err error) {
n, err = t.originalReader.Read(p)
2022-09-18 20:41:52 +00:00
if err != nil {
log.Trace().Err(err).Msgf("[cache] original reader for %q has returned an error", t.cacheKey)
t.hasError = true
2022-09-18 20:41:52 +00:00
} else if n > 0 {
_, _ = t.buffer.Write(p[:n])
2022-09-18 20:41:52 +00:00
}
return
}
2022-07-27 15:25:08 +00:00
2022-09-18 20:41:52 +00:00
func (t *writeCacheReader) Close() error {
if !t.hasError {
fc := *t.rileResponse
fc.Body = t.buffer.Bytes()
2022-09-19 10:15:14 +00:00
_ = t.cache.Set(t.cacheKey, fc, fileCacheTimeout)
2022-09-18 20:41:52 +00:00
}
log.Trace().Msgf("cacheReader for %q saved=%t closed", t.cacheKey, !t.hasError)
return t.originalReader.Close()
2022-09-18 20:41:52 +00:00
}
2022-07-27 15:25:08 +00:00
2022-09-18 20:41:52 +00:00
func (f FileResponse) CreateCacheReader(r io.ReadCloser, cache cache.SetGetKey, cacheKey string) io.ReadCloser {
2022-11-07 22:43:20 +00:00
if r == nil || cache == nil || cacheKey == "" {
log.Error().Msg("could not create CacheReader")
2022-11-11 23:15:06 +00:00
return nil
2022-11-07 22:43:20 +00:00
}
2022-11-11 23:15:06 +00:00
2022-09-18 20:41:52 +00:00
return &writeCacheReader{
originalReader: r,
buffer: bytes.NewBuffer(make([]byte, 0)),
rileResponse: &f,
cache: cache,
cacheKey: cacheKey,
2022-09-18 20:41:52 +00:00
}
}