Skip to content

Commit

Permalink
add cache for webdav redirect url
Browse files Browse the repository at this point in the history
  • Loading branch information
zyxkad committed Feb 20, 2024
1 parent 0df8aa0 commit 17d83e5
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 15 deletions.
1 change: 1 addition & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ dashboard:
pwa-description: Go-Openbmclapi Internal Dashboard

# 子存储节点列表
# 注意: measure 测量请求总是以第一个存储为准
storages:
# local 为本地存储
- type: local
Expand Down
2 changes: 1 addition & 1 deletion cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func NewCluster(
func (cr *Cluster) Init(ctx context.Context) error {
// Init storaged
for _, s := range cr.storages {
s.Init(ctx)
s.Init(ctx, cr)
}
// read old stats
if err := cr.stats.Load(cr.dataDir); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd_webdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func cmdUploadWebdav(args []string) {

var local LocalStorage
local.SetOptions(localOpt)
if err := local.Init(ctx); err != nil {
if err := local.Init(ctx, nil); err != nil {
logErrorf("Cannot initialize %s: %v", local.String(), err)
os.Exit(1)
}
Expand All @@ -71,7 +71,7 @@ func cmdUploadWebdav(args []string) {
for i, opt := range webdavOpts {
s := new(WebDavStorage)
s.SetOptions(opt)
if err := s.Init(ctx); err != nil {
if err := s.Init(ctx, nil); err != nil {
logErrorf("Cannot initialize %s: %v", s.String(), err)
os.Exit(1)
}
Expand Down
6 changes: 5 additions & 1 deletion handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@ func (cr *Cluster) handleDownload(rw http.ResponseWriter, req *http.Request, has
http.Error(rw, "404 Status Not Found", http.StatusNotFound)
return
}
http.Error(rw, err.Error(), http.StatusInternalServerError)
if _, ok := err.(*HTTPStatusError); ok {
http.Error(rw, err.Error(), http.StatusBadGateway)
} else {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
return
}
logDebug("[handler]: download served successed")
Expand Down
2 changes: 1 addition & 1 deletion storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Storage interface {
// SetOptions will be called with the same type of the Options() result
SetOptions(any)
// Init will be called before start to use a storage
Init(context.Context) error
Init(context.Context, *Cluster) error

Size(hash string) (int64, error)
Open(hash string) (io.ReadCloser, error)
Expand Down
2 changes: 1 addition & 1 deletion storage_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (s *LocalStorage) SetOptions(newOpts any) {
s.opt = *(newOpts.(*LocalStorageOption))
}

func (s *LocalStorage) Init(context.Context) (err error) {
func (s *LocalStorage) Init(context.Context, *Cluster) (err error) {
tmpDir := s.opt.TmpPath()
os.RemoveAll(tmpDir)
// should be 0755 here because Windows permission issue
Expand Down
2 changes: 1 addition & 1 deletion storage_mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ var checkerClient = &http.Client{
Timeout: time.Minute,
}

func (s *MountStorage) Init(ctx context.Context) (err error) {
func (s *MountStorage) Init(ctx context.Context, _ *Cluster) (err error) {
logInfof("Initalizing mounted folder %s", s.opt.Path)
if err = initCache(s.opt.CachePath()); err != nil {
return
Expand Down
48 changes: 41 additions & 7 deletions storage_webdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ import (
)

type WebDavStorageOption struct {
PreGenMeasures bool `yaml:"pre-gen-measures"`
PreGenMeasures bool `yaml:"pre-gen-measures"`
FollowRedirect bool `yaml:"follow-redirect"`
RedirectLinkCache YAMLDuration `yaml:"redirect-link-cache"`

Alias string `yaml:"alias,omitempty"`
aliasUser *WebDavUser
Alias string `yaml:"alias,omitempty"`
WebDavUser `yaml:",inline,omitempty"`

WebDavUser `yaml:",inline,omitempty"`
aliasUser *WebDavUser
fullEndPoint string
}

Expand Down Expand Up @@ -95,7 +97,8 @@ func (o *WebDavStorageOption) GetPassword() string {
type WebDavStorage struct {
opt WebDavStorageOption

cli *gowebdav.Client
cache Cache
cli *gowebdav.Client
}

var _ Storage = (*WebDavStorage)(nil)
Expand Down Expand Up @@ -124,7 +127,7 @@ func webdavIsHTTPError(err error, code int) bool {
return strings.Contains(err.Error(), expect)
}

func (s *WebDavStorage) Init(ctx context.Context) (err error) {
func (s *WebDavStorage) Init(ctx context.Context, cluster *Cluster) (err error) {
if alias := s.opt.Alias; alias != "" {
user, ok := config.WebdavUsers[alias]
if !ok {
Expand All @@ -149,6 +152,12 @@ func (s *WebDavStorage) Init(ctx context.Context) (err error) {
s.opt.fullEndPoint = s.opt.EndPoint
}

if cluster == nil {
s.cache = NoCache
} else {
s.cache = NewCacheWithNamespace(cluster.cache, fmt.Sprintf("redirect-cache@%s;%s@", s.opt.GetUsername(), s.opt.GetEndPoint()))
}

s.cli = gowebdav.NewClient(s.opt.GetEndPoint(), s.opt.GetUsername(), s.opt.GetPassword())
s.cli.SetHeader("User-Agent", ClusterUserAgentFull)

Expand Down Expand Up @@ -258,6 +267,26 @@ func copyHeader(key string, dst, src http.Header) {
}

func (s *WebDavStorage) ServeDownload(rw http.ResponseWriter, req *http.Request, hash string, size int64) (int64, error) {
if s.opt.RedirectLinkCache > 0 {
if location, ok := s.cache.Get(hash); ok {
// fix the size for Ranged request
rgs, err := gosrc.ParseRange(req.Header.Get("Range"), size)
if err == nil && len(rgs) > 0 {
var newSize int64 = 0
for _, r := range rgs {
newSize += r.Length
}
if newSize < size {
size = newSize
}
}
rw.Header().Set("Location", location)
rw.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d", (int64)(s.opt.RedirectLinkCache.Dur().Seconds())))
rw.WriteHeader(http.StatusFound)
return size, nil
}
}

target, err := url.JoinPath(s.opt.GetEndPoint(), s.hashToPath(hash))
if err != nil {
return 0, err
Expand Down Expand Up @@ -296,9 +325,14 @@ func (s *WebDavStorage) ServeDownload(rw http.ResponseWriter, req *http.Request,
size = newSize
}
}
copyHeader("Location", rwh, resp.Header)
location := resp.Header.Get("Location")
rwh.Set("Location", location)
copyHeader("ETag", rwh, resp.Header)
copyHeader("Last-Modified", rwh, resp.Header)
if s.opt.RedirectLinkCache > 0 {
rwh.Set("Cache-Control", fmt.Sprintf("public,max-age=%d", (int64)(s.opt.RedirectLinkCache.Dur().Seconds())))
s.cache.Set(hash, location, CacheOpt{Expiration: s.opt.RedirectLinkCache.Dur()})
}
rw.WriteHeader(resp.StatusCode)
return size, nil
case 2:
Expand Down
25 changes: 24 additions & 1 deletion util.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ var (
_ yaml.Unmarshaler = (*RawYAML)(nil)
)

func (r RawYAML) MarshalYAML() (interface{}, error) {
func (r RawYAML) MarshalYAML() (any, error) {
return r.Node, nil
}

Expand All @@ -418,6 +418,29 @@ func (r *RawYAML) UnmarshalYAML(n *yaml.Node) (err error) {
return nil
}

type YAMLDuration time.Duration

func (d YAMLDuration) Dur() time.Duration {
return (time.Duration)(d)
}

func (d YAMLDuration) MarshalYAML() (any, error) {
return (time.Duration)(d).String(), nil
}

func (d *YAMLDuration) UnmarshalYAML(n *yaml.Node) (err error) {
var v string
if err = n.Decode(v); err != nil {
return
}
var td time.Duration
if td, err = time.ParseDuration(v); err != nil {
return
}
*d = (YAMLDuration)(td)
return nil
}

type slotInfo struct {
id int
buf []byte
Expand Down

0 comments on commit 17d83e5

Please sign in to comment.