From 56851f48929c8a73073ac9b5ced1ef6eec7ba4d5 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Sat, 5 Dec 2020 01:24:33 +0100 Subject: [PATCH] WebDAV: Add timeout for fetching directories #664 --- internal/entity/account.go | 2 +- internal/remote/webdav/webdav.go | 28 ++++++++++++++++++++++----- internal/remote/webdav/webdav_test.go | 4 ++-- internal/workers/sync_refresh.go | 2 +- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/internal/entity/account.go b/internal/entity/account.go index 2ab96a058..a3307e159 100644 --- a/internal/entity/account.go +++ b/internal/entity/account.go @@ -106,7 +106,7 @@ func (m *Account) Delete() error { func (m *Account) Directories() (result fs.FileInfos, err error) { if m.AccType == remote.ServiceWebDAV { c := webdav.New(m.AccURL, m.AccUser, m.AccPass) - result, err = c.Directories("/", true) + result, err = c.Directories("/", true, webdav.SyncTimeout) } sort.Sort(result) diff --git a/internal/remote/webdav/webdav.go b/internal/remote/webdav/webdav.go index 27641c6f1..8f84480a6 100644 --- a/internal/remote/webdav/webdav.go +++ b/internal/remote/webdav/webdav.go @@ -45,6 +45,9 @@ import ( var log = event.Log +const SyncTimeout = time.Second * 45 +const AsyncTimeout = time.Minute * 20 + type Client struct { client *gowebdav.Client } @@ -55,7 +58,9 @@ func New(url, user, pass string) Client { clt.SetTimeout(10 * time.Minute) // TODO: Change timeout if needed - result := Client{client: clt} + result := Client{ + client: clt, + } return result } @@ -90,7 +95,20 @@ func (c Client) Files(dir string) (result fs.FileInfos, err error) { } // Directories returns all sub directories in path as string slice. -func (c Client) Directories(root string, recursive bool) (result fs.FileInfos, err error) { +func (c Client) Directories(root string, recursive bool, timeout time.Duration) (result fs.FileInfos, err error) { + start := time.Now() + + result, err = c.fetchDirs(root, recursive, start, timeout) + + if time.Now().Sub(start) >= timeout { + log.Warnf("webdav: read dir timeout reached") + } + + return result, err +} + +// fetchDirs recursively fetches all directories until the timeout is reached. +func (c Client) fetchDirs(root string, recursive bool, start time.Time, timeout time.Duration) (result fs.FileInfos, err error) { files, err := c.readDir(root) if err != nil { @@ -110,8 +128,8 @@ func (c Client) Directories(root string, recursive bool) (result fs.FileInfos, e result = append(result, info) - if recursive { - subDirs, err := c.Directories(info.Abs, true) + if recursive && time.Now().Sub(start) < timeout { + subDirs, err := c.fetchDirs(info.Abs, true, start, timeout) if err != nil { return result, err @@ -182,7 +200,7 @@ func (c Client) DownloadDir(from, to string, recursive, force bool) (errs []erro return errs } - dirs, err := c.Directories(from, false) + dirs, err := c.Directories(from, false, AsyncTimeout) for _, dir := range dirs { errs = append(errs, c.DownloadDir(dir.Abs, to, true, force)...) diff --git a/internal/remote/webdav/webdav_test.go b/internal/remote/webdav/webdav_test.go index 4194a2246..cf66c7700 100644 --- a/internal/remote/webdav/webdav_test.go +++ b/internal/remote/webdav/webdav_test.go @@ -44,7 +44,7 @@ func TestClient_Directories(t *testing.T) { assert.IsType(t, Client{}, c) t.Run("non-recursive", func(t *testing.T) { - dirs, err := c.Directories("", false) + dirs, err := c.Directories("", false, SyncTimeout) if err != nil { t.Fatal(err) @@ -62,7 +62,7 @@ func TestClient_Directories(t *testing.T) { }) t.Run("recursive", func(t *testing.T) { - dirs, err := c.Directories("", true) + dirs, err := c.Directories("", true, SyncTimeout) if err != nil { t.Fatal(err) diff --git a/internal/workers/sync_refresh.go b/internal/workers/sync_refresh.go index a7ffbe17d..eed0ff5d7 100644 --- a/internal/workers/sync_refresh.go +++ b/internal/workers/sync_refresh.go @@ -16,7 +16,7 @@ func (worker *Sync) refresh(a entity.Account) (complete bool, err error) { client := webdav.New(a.AccURL, a.AccUser, a.AccPass) - subDirs, err := client.Directories(a.SyncPath, true) + subDirs, err := client.Directories(a.SyncPath, true, webdav.AsyncTimeout) if err != nil { log.Error(err)