diff --git a/hupload/handlers.go b/hupload/handlers.go index d146f18..eddb068 100644 --- a/hupload/handlers.go +++ b/hupload/handlers.go @@ -47,7 +47,7 @@ func (h *Hupload) postShare(w http.ResponseWriter, r *http.Request) { // We ignore unmarshalling of JSON body as it is optional. _ = json.NewDecoder(r.Body).Decode(&options) - share, err := h.Config.Storage.CreateShare(code, user, options) + share, err := h.Config.Storage.CreateShare(r.Context(), code, user, options) if err != nil { slog.Error("postShare", slog.String("error", err.Error())) switch { @@ -83,7 +83,7 @@ func (h *Hupload) patchShare(w http.ResponseWriter, r *http.Request) { // We ignore unmarshalling of JSON body as it is optional. _ = json.NewDecoder(r.Body).Decode(&options) - result, err := h.Config.Storage.UpdateShare(r.PathValue("share"), options) + result, err := h.Config.Storage.UpdateShare(r.Context(), r.PathValue("share"), options) if err != nil { slog.Error("patchShare", slog.String("error", err.Error())) switch { @@ -103,7 +103,7 @@ func (h *Hupload) patchShare(w http.ResponseWriter, r *http.Request) { // postItem copies a new item in the share and returns the json description func (h *Hupload) postItem(w http.ResponseWriter, r *http.Request) { - share, err := h.Config.Storage.GetShare(r.PathValue("share")) + share, err := h.Config.Storage.GetShare(r.Context(), r.PathValue("share")) if err != nil { slog.Error("postItem", slog.String("error", err.Error())) switch { @@ -148,7 +148,7 @@ func (h *Hupload) postItem(w http.ResponseWriter, r *http.Request) { } b := bufio.NewReader(np) - item, err := h.Config.Storage.CreateItem(r.PathValue("share"), r.PathValue("item"), int64(cl), b) + item, err := h.Config.Storage.CreateItem(r.Context(), r.PathValue("share"), r.PathValue("item"), int64(cl), b) if err != nil { switch { case errors.Is(err, storage.ErrInvalidItemName): @@ -170,7 +170,7 @@ func (h *Hupload) postItem(w http.ResponseWriter, r *http.Request) { // postItem copies a new item in the share and returns the json description func (h *Hupload) deleteItem(w http.ResponseWriter, r *http.Request) { - share, err := h.Config.Storage.GetShare(r.PathValue("share")) + share, err := h.Config.Storage.GetShare(r.Context(), r.PathValue("share")) if err != nil { slog.Error("postItem", slog.String("error", err.Error())) switch { @@ -190,7 +190,7 @@ func (h *Hupload) deleteItem(w http.ResponseWriter, r *http.Request) { return } - err = h.Config.Storage.DeleteItem(r.PathValue("share"), r.PathValue("item")) + err = h.Config.Storage.DeleteItem(r.Context(), r.PathValue("share"), r.PathValue("item")) if err != nil { switch { case errors.Is(err, storage.ErrInvalidItemName): @@ -209,7 +209,7 @@ func (h *Hupload) deleteItem(w http.ResponseWriter, r *http.Request) { // getShares returns the list of shares as json func (h *Hupload) getShares(w http.ResponseWriter, r *http.Request) { - shares, err := h.Config.Storage.ListShares() + shares, err := h.Config.Storage.ListShares(r.Context()) if err != nil { slog.Error("getShares", slog.String("error", err.Error())) @@ -226,7 +226,7 @@ func (h *Hupload) getShares(w http.ResponseWriter, r *http.Request) { // getShareItems returns the share identified by the request parameter func (h *Hupload) getShare(w http.ResponseWriter, r *http.Request) { - share, err := h.Config.Storage.GetShare(r.PathValue("share")) + share, err := h.Config.Storage.GetShare(r.Context(), r.PathValue("share")) if err != nil { slog.Error("getShare", slog.String("error", err.Error())) @@ -256,7 +256,7 @@ func (h *Hupload) getShare(w http.ResponseWriter, r *http.Request) { // getShareItems returns the share content identified by the request parameter func (h *Hupload) getShareItems(w http.ResponseWriter, r *http.Request) { - share, err := h.Config.Storage.GetShare(r.PathValue("share")) + share, err := h.Config.Storage.GetShare(r.Context(), r.PathValue("share")) if err != nil { slog.Error("getShareItems", slog.String("error", err.Error())) switch { @@ -276,7 +276,7 @@ func (h *Hupload) getShareItems(w http.ResponseWriter, r *http.Request) { return } - content, err := h.Config.Storage.ListShare(share.Name) + content, err := h.Config.Storage.ListShare(r.Context(), share.Name) if err != nil { slog.Error("getShareItems", slog.String("error", err.Error())) writeError(w, http.StatusInternalServerError, err.Error()) @@ -287,7 +287,7 @@ func (h *Hupload) getShareItems(w http.ResponseWriter, r *http.Request) { // deleteShare deletes the share identified by the request parameter func (h *Hupload) deleteShare(w http.ResponseWriter, r *http.Request) { - err := h.Config.Storage.DeleteShare(r.PathValue("share")) + err := h.Config.Storage.DeleteShare(r.Context(), r.PathValue("share")) if err != nil { slog.Error("deleteShare", slog.String("error", err.Error())) switch { @@ -309,7 +309,7 @@ func (h *Hupload) getItem(w http.ResponseWriter, r *http.Request) { shareName := r.PathValue("share") itemName := r.PathValue("item") - share, err := h.Config.Storage.GetShare(shareName) + share, err := h.Config.Storage.GetShare(r.Context(), shareName) if err != nil { slog.Error("getItem", slog.String("error", err.Error())) switch { @@ -329,7 +329,7 @@ func (h *Hupload) getItem(w http.ResponseWriter, r *http.Request) { return } - item, err := h.Config.Storage.GetItem(shareName, itemName) + item, err := h.Config.Storage.GetItem(r.Context(), shareName, itemName) if err != nil { switch { case errors.Is(err, storage.ErrItemNotFound): @@ -343,7 +343,7 @@ func (h *Hupload) getItem(w http.ResponseWriter, r *http.Request) { return } - reader, err := h.Config.Storage.GetItemData(shareName, itemName) + reader, err := h.Config.Storage.GetItemData(r.Context(), shareName, itemName) if err != nil { slog.Error("getShares", slog.String("error", err.Error())) writeError(w, http.StatusInternalServerError, err.Error()) diff --git a/hupload/handlers_test.go b/hupload/handlers_test.go index 141802a..a601e43 100644 --- a/hupload/handlers_test.go +++ b/hupload/handlers_test.go @@ -3,6 +3,7 @@ package main import ( "bufio" "bytes" + "context" "crypto/rand" "encoding/json" "fmt" @@ -64,7 +65,7 @@ func getHupload(t *testing.T, cfg *config.Config) *Hupload { // makeShare creates a new share with the given name and parameters. func makeShare(t *testing.T, h *Hupload, name string, params storage.Options) *storage.Share { - share, err := h.Config.Storage.CreateShare(name, "admin", params) + share, err := h.Config.Storage.CreateShare(context.Background(), name, "admin", params) if err != nil { t.Fatal(err) } @@ -73,7 +74,7 @@ func makeShare(t *testing.T, h *Hupload, name string, params storage.Options) *s // makeItem creates a new item with the given name and size. func makeItem(t *testing.T, h *Hupload, shareName, fileName string, size int) { - _, err := h.Config.Storage.CreateItem(shareName, fileName, int64(size), bufio.NewReader(io.LimitReader(rand.Reader, int64(size)))) + _, err := h.Config.Storage.CreateItem(context.Background(), shareName, fileName, int64(size), bufio.NewReader(io.LimitReader(rand.Reader, int64(size)))) if err != nil { t.Fatal(err) } @@ -117,7 +118,7 @@ func TestCreateShare(t *testing.T) { } t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(share.Name) + _ = h.Config.Storage.DeleteShare(context.Background(), share.Name) }) }) @@ -150,7 +151,7 @@ func TestCreateShare(t *testing.T) { } t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(share.Name) + _ = h.Config.Storage.DeleteShare(context.Background(), share.Name) }) token = &w.Result().Cookies()[0].Value @@ -195,7 +196,7 @@ func TestCreateShare(t *testing.T) { } t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(share.Name) + _ = h.Config.Storage.DeleteShare(context.Background(), share.Name) }) // _, err := os.Stat(path.Join("tmptest/data/", share.Name)) @@ -229,7 +230,7 @@ func TestCreateShare(t *testing.T) { } t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("samename") + _ = h.Config.Storage.DeleteShare(context.Background(), "samename") }) }) @@ -251,7 +252,7 @@ func TestCreateShare(t *testing.T) { } t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("randomname") + _ = h.Config.Storage.DeleteShare(context.Background(), "randomname") }) }) @@ -294,7 +295,7 @@ func TestUpdateShare(t *testing.T) { Message: "message", }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("testupdate") + _ = h.Config.Storage.DeleteShare(context.Background(), "testupdate") }) t.Run("Update share should succeed", func(t *testing.T) { var ( @@ -415,8 +416,8 @@ func TestGetShare(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("test") - _ = h.Config.Storage.DeleteShare("test2") + _ = h.Config.Storage.DeleteShare(context.Background(), "test") + _ = h.Config.Storage.DeleteShare(context.Background(), "test2") }) t.Run("Get shares should succeed", func(t *testing.T) { @@ -602,7 +603,7 @@ func TestGetShare(t *testing.T) { makeShare(t, h, shareName, storage.Options{}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) makeItem(t, h, shareName, "newfile.txt", 1*1024*1024) @@ -710,7 +711,7 @@ func TestDeleteShare(t *testing.T) { shareName := "deleteshare" makeShare(t, h, shareName, storage.Options{Exposure: "download"}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) req = httptest.NewRequest("DELETE", path.Join("/api/v1/shares/", shareName), nil) req.SetBasicAuth("admin", "hupload") @@ -744,7 +745,7 @@ func TestDeleteShare(t *testing.T) { return } t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("deleteshare") + _ = h.Config.Storage.DeleteShare(context.Background(), "deleteshare") }) }) @@ -810,13 +811,13 @@ func TestGetItems(t *testing.T) { fileSize := 1 * 1024 * 1024 makeShare(t, h, shareName, storage.Options{Exposure: exp}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) makeItem(t, h, shareName, "newfile.txt", fileSize) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) req = httptest.NewRequest("GET", path.Join("/api/v1/shares/", shareName, "items", "newfile.txt"), nil) @@ -867,7 +868,7 @@ func TestGetItems(t *testing.T) { makeShare(t, h, shareName, storage.Options{Exposure: "download"}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) makeItem(t, h, shareName, "newfile.txt", 1*1024*1024) @@ -894,7 +895,7 @@ func TestGetItems(t *testing.T) { makeShare(t, h, shareName, storage.Options{Exposure: "download"}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) req = httptest.NewRequest("GET", path.Join("/api/v1/shares/", shareName, "items", "notexists"), nil) @@ -919,7 +920,7 @@ func TestGetItems(t *testing.T) { makeShare(t, h, shareName, storage.Options{Exposure: "upload"}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) makeItem(t, h, shareName, "newfile.txt", 1*1024*1024) @@ -1014,7 +1015,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("upload") + _ = h.Config.Storage.DeleteShare(context.Background(), "upload") }) makeItem(t, h, "upload", "newfile.txt", 1*1024*1024) @@ -1045,7 +1046,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("download") + _ = h.Config.Storage.DeleteShare(context.Background(), "download") }) fileSize := 3 * 1024 * 1024 @@ -1079,7 +1080,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare(shareName) + _ = h.Config.Storage.DeleteShare(context.Background(), shareName) }) fileSize := 3 * 1024 * 1024 @@ -1115,7 +1116,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("toobig") + _ = h.Config.Storage.DeleteShare(context.Background(), "toobig") }) // writer := multipart.NewWriter(body) @@ -1153,7 +1154,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("sharetoobig") + _ = h.Config.Storage.DeleteShare(context.Background(), "sharetoobig") }) fileSize := 3 * 1024 * 1024 @@ -1227,7 +1228,7 @@ func TestUpload(t *testing.T) { t.Run("Upload malformed data should fail", func(t *testing.T) { makeShare(t, h, "malformed", storage.Options{}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("malformed") + _ = h.Config.Storage.DeleteShare(context.Background(), "malformed") }) req = httptest.NewRequest("POST", path.Join("/api/v1/shares", "malformed", "items", "newfile.txt"), nil) @@ -1253,7 +1254,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("nofilesize") + _ = h.Config.Storage.DeleteShare(context.Background(), "nofilesize") }) fileSize := 1 * 1024 * 1024 @@ -1282,7 +1283,7 @@ func TestUpload(t *testing.T) { }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("upload") + _ = h.Config.Storage.DeleteShare(context.Background(), "upload") }) fileSize := 1 * 1024 * 1024 @@ -1329,7 +1330,7 @@ func TestDeleteItem(t *testing.T) { Validity: 7, }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("uploadadmin") + _ = h.Config.Storage.DeleteShare(context.Background(), "uploadadmin") }) makeItem(t, h, share.Name, "newfile.txt", 1*1024*1024) @@ -1354,7 +1355,7 @@ func TestDeleteItem(t *testing.T) { Validity: 7, }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("upload") + _ = h.Config.Storage.DeleteShare(context.Background(), "upload") }) makeItem(t, h, share.Name, "newfile.txt", 1*1024*1024) @@ -1377,7 +1378,7 @@ func TestDeleteItem(t *testing.T) { Validity: 7, }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("both") + _ = h.Config.Storage.DeleteShare(context.Background(), "both") }) makeItem(t, h, share.Name, "newfile.txt", 1*1024*1024) @@ -1401,7 +1402,7 @@ func TestDeleteItem(t *testing.T) { Validity: 7, }) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("download") + _ = h.Config.Storage.DeleteShare(context.Background(), "download") }) makeItem(t, h, share.Name, "newfile.txt", 1*1024*1024) @@ -1454,7 +1455,7 @@ func TestDeleteItem(t *testing.T) { t.Run("delete an invalid file name should fail", func(t *testing.T) { makeShare(t, h, "invaliditem", storage.Options{}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("invaliditem") + _ = h.Config.Storage.DeleteShare(context.Background(), "invaliditem") }) req = httptest.NewRequest("DELETE", path.Join("/api/v1/shares", "invaliditem", "items", url.QueryEscape("../file.txt")), nil) @@ -1473,7 +1474,7 @@ func TestDeleteItem(t *testing.T) { t.Run("delete an inexistant file should fail", func(t *testing.T) { makeShare(t, h, "inexistantfile", storage.Options{}) t.Cleanup(func() { - _ = h.Config.Storage.DeleteShare("inexistantfile") + _ = h.Config.Storage.DeleteShare(context.Background(), "inexistantfile") }) req = httptest.NewRequest("DELETE", path.Join("/api/v1/shares", "inexistantfile", "items", "newfile.txt"), nil) diff --git a/hupload/internal/storage/common_test.go b/hupload/internal/storage/common_test.go index c0fb63a..aa4564f 100644 --- a/hupload/internal/storage/common_test.go +++ b/hupload/internal/storage/common_test.go @@ -1,6 +1,7 @@ package storage_test import ( + "context" "errors" "io" "os" @@ -35,14 +36,14 @@ func TestFileOverflow(t *testing.T) { t.Cleanup(func() { for i := range storages { - _ = storages[i].DeleteShare("test") + _ = storages[i].DeleteShare(context.Background(), "test") } }) for i := range storages { s := storages[i] - share, err := s.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) + share, err := s.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -52,7 +53,7 @@ func TestFileOverflow(t *testing.T) { reader := readerForCapacity(fileSize) - _, err = s.CreateItem(share.Name, "test.txt", int64(fileSize), reader) + _, err = s.CreateItem(context.Background(), share.Name, "test.txt", int64(fileSize), reader) reader.Close() if !errors.Is(err, storage.ErrMaxFileSizeReached) { @@ -65,7 +66,7 @@ func TestFileOverflow(t *testing.T) { reader := readerForCapacity(fileSize) - _, err = s.CreateItem(share.Name, "test.txt", int64(fileSize), reader) + _, err = s.CreateItem(context.Background(), share.Name, "test.txt", int64(fileSize), reader) reader.Close() if err != nil { @@ -78,7 +79,7 @@ func TestFileOverflow(t *testing.T) { reader := readerForCapacity(fileSize) - _, err = s.CreateItem(share.Name, "test.txt", int64(fileSize), reader) + _, err = s.CreateItem(context.Background(), share.Name, "test.txt", int64(fileSize), reader) reader.Close() if !errors.Is(err, storage.ErrMaxShareSizeReached) { @@ -106,7 +107,7 @@ func TestShareOverflow(t *testing.T) { t.Errorf("Expected FileStorage to be created") } - share, err := f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) + share, err := f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -114,7 +115,7 @@ func TestShareOverflow(t *testing.T) { reader1 := readerForCapacity(3 * 1024 * 1024) defer reader1.Close() - _, err = f.CreateItem(share.Name, "test.txt", 0, reader1) + _, err = f.CreateItem(context.Background(), share.Name, "test.txt", 0, reader1) if err != nil { t.Errorf("Expected no error, got %v", err) @@ -123,7 +124,7 @@ func TestShareOverflow(t *testing.T) { reader2 := readerForCapacity(3 * 1024 * 1024) defer reader2.Close() - _, err = f.CreateItem(share.Name, "test2.txt", 0, reader2) + _, err = f.CreateItem(context.Background(), share.Name, "test2.txt", 0, reader2) if err == nil { t.Errorf("Expected error, got nil") diff --git a/hupload/internal/storage/file.go b/hupload/internal/storage/file.go index 5244eb1..18b7ef9 100644 --- a/hupload/internal/storage/file.go +++ b/hupload/internal/storage/file.go @@ -2,6 +2,7 @@ package storage import ( "bufio" + "context" "encoding/json" "io" "log/slog" @@ -143,7 +144,7 @@ func (b *FileBackend) Migrate() error { // in days. It returns an error if the share already exists or if the name is // invalid. owner is only used to populate metadata. -func (b *FileBackend) CreateShare(name, owner string, options Options) (*Share, error) { +func (b *FileBackend) CreateShare(ctx context.Context, name, owner string, options Options) (*Share, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } @@ -189,12 +190,12 @@ func (b *FileBackend) CreateShare(name, owner string, options Options) (*Share, // UpdateShare updates the metadata of a share with the provided name. It returns // an error if the share does not exist or if the name is invalid. -func (b *FileBackend) UpdateShare(name string, options *Options) (*Options, error) { +func (b *FileBackend) UpdateShare(ctx context.Context, name string, options *Options) (*Options, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } - m, err := b.GetShare(name) + m, err := b.GetShare(ctx, name) if err != nil { return nil, err } @@ -220,13 +221,13 @@ func (b *FileBackend) UpdateShare(name string, options *Options) (*Options, erro // doesn't fit in the share or if the share is full. The content is read from // the provided bufio.Reader. -func (b *FileBackend) CreateItem(s string, i string, size int64, r io.Reader) (*Item, error) { +func (b *FileBackend) CreateItem(ctx context.Context, s string, i string, size int64, r io.Reader) (*Item, error) { if !IsShareNameSafe(s) { return nil, ErrInvalidShareName } // Get Share metadata - share, err := b.GetShare(s) + share, err := b.GetShare(ctx, s) if err != nil { return nil, err } @@ -295,7 +296,7 @@ func (b *FileBackend) CreateItem(s string, i string, size int64, r io.Reader) (* return nil, err } - item, err := b.GetItem(s, i) + item, err := b.GetItem(ctx, s, i) if err != nil { return nil, err } @@ -308,7 +309,7 @@ func (b *FileBackend) CreateItem(s string, i string, size int64, r io.Reader) (* return item, nil } -func (b *FileBackend) DeleteItem(s string, i string) error { +func (b *FileBackend) DeleteItem(ctx context.Context, s string, i string) error { if !IsShareNameSafe(s) { return ErrInvalidShareName } @@ -337,7 +338,7 @@ func (b *FileBackend) DeleteItem(s string, i string) error { // GetShare retrieves the metadata for a share with the provided name. It // returns an error if the share does not exist or if the name is invalid. -func (b *FileBackend) GetShare(s string) (*Share, error) { +func (b *FileBackend) GetShare(ctx context.Context, s string) (*Share, error) { if !IsShareNameSafe(s) { return nil, ErrInvalidShareName } @@ -364,7 +365,7 @@ func (b *FileBackend) GetShare(s string) (*Share, error) { // decoded. // The returned shares are sorted by creation date, newest first. -func (b *FileBackend) ListShares() ([]Share, error) { +func (b *FileBackend) ListShares(ctx context.Context) ([]Share, error) { d, err := os.ReadDir(b.Options.Path) if err != nil { return nil, err @@ -374,7 +375,7 @@ func (b *FileBackend) ListShares() ([]Share, error) { // Shares loop for _, f := range d { if f.IsDir() { - m, err := b.GetShare(f.Name()) + m, err := b.GetShare(ctx, f.Name()) if err != nil { continue } @@ -391,7 +392,7 @@ func (b *FileBackend) ListShares() ([]Share, error) { // DeleteShare removes a share and all its content from the backend. It returns // an error if the share does not exist or if the name is invalid. -func (b *FileBackend) DeleteShare(s string) error { +func (b *FileBackend) DeleteShare(ctx context.Context, s string) error { if !IsShareNameSafe(s) { return ErrInvalidShareName } @@ -416,7 +417,7 @@ func (b *FileBackend) DeleteShare(s string) error { // modification date, newest first. // .* files and temporary upload files are excluded from the result. -func (b *FileBackend) ListShare(s string) ([]Item, error) { +func (b *FileBackend) ListShare(ctx context.Context, s string) ([]Item, error) { if !IsShareNameSafe(s) { return nil, ErrInvalidShareName } @@ -433,7 +434,7 @@ func (b *FileBackend) ListShare(s string) ([]Item, error) { continue } - i, err := b.GetItem(s, f.Name()) + i, err := b.GetItem(ctx, s, f.Name()) if err != nil { return nil, err } @@ -451,7 +452,7 @@ func (b *FileBackend) ListShare(s string) ([]Item, error) { // GetItem retrieves the metadata for an item in a share. It returns an error if // the share or the item do not exist or if the share name is invalid. -func (b *FileBackend) GetItem(s string, i string) (*Item, error) { +func (b *FileBackend) GetItem(ctx context.Context, s string, i string) (*Item, error) { if !IsShareNameSafe(s) { return nil, ErrInvalidShareName } @@ -479,7 +480,7 @@ func (b *FileBackend) GetItem(s string, i string) (*Item, error) { // GetItemData retrieves the content of an item in a share. It returns an error // if the share or the item do not exist or if the share name is invalid. -func (b *FileBackend) GetItemData(s string, i string) (io.ReadCloser, error) { +func (b *FileBackend) GetItemData(ctx context.Context, s string, i string) (io.ReadCloser, error) { if !IsShareNameSafe(s) { return nil, ErrInvalidShareName } diff --git a/hupload/internal/storage/file_test.go b/hupload/internal/storage/file_test.go index f8fe0b7..0c9639e 100644 --- a/hupload/internal/storage/file_test.go +++ b/hupload/internal/storage/file_test.go @@ -3,6 +3,7 @@ package storage_test import ( "bufio" "bytes" + "context" "fmt" "io" "os" @@ -43,7 +44,7 @@ func TestCreateShare(t *testing.T) { }{ { func() (*storage.Share, error) { - return f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) + return f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) }, storage.Share{ Version: 1, @@ -54,7 +55,7 @@ func TestCreateShare(t *testing.T) { }, { func() (*storage.Share, error) { - return f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "both"}) + return f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "both"}) }, storage.Share{ Version: 1, @@ -65,7 +66,7 @@ func TestCreateShare(t *testing.T) { }, { func() (*storage.Share, error) { - return f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "download"}) + return f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "download"}) }, storage.Share{ Version: 1, @@ -117,7 +118,7 @@ func TestUpdateShare(t *testing.T) { f := createFileBackend(t) - share, _ := f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload", Description: "description", Message: "message"}) + share, _ := f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload", Description: "description", Message: "message"}) newOptions := &storage.Options{ Validity: 20, @@ -126,7 +127,7 @@ func TestUpdateShare(t *testing.T) { Message: "new message", } - o, err := f.UpdateShare(share.Name, newOptions) + o, err := f.UpdateShare(context.Background(), share.Name, newOptions) if err != nil { t.Errorf("Expected no error, got %v", err) @@ -137,7 +138,7 @@ func TestUpdateShare(t *testing.T) { } share.Options = *newOptions - share2, _ := f.GetShare(share.Name) + share2, _ := f.GetShare(context.Background(), share.Name) if !share.DateCreated.Equal(share2.DateCreated) { t.Errorf("Expected %v, got %v", share.DateCreated, share2.DateCreated) @@ -157,13 +158,13 @@ func TestCreateItem(t *testing.T) { f := createFileBackend(t) - share, err := f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) + share, err := f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) if err != nil { t.Errorf("Expected no error, got %v", err) } reader := bufio.NewReader(bytes.NewReader([]byte("test"))) - item, err := f.CreateItem(share.Name, "test.txt", 0, reader) + item, err := f.CreateItem(context.Background(), share.Name, "test.txt", 0, reader) if err != nil { t.Errorf("Expected no error, got %v", err) @@ -191,19 +192,19 @@ func TestDeleteItem(t *testing.T) { f := createFileBackend(t) - share, _ := f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) + share, _ := f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) t.Run("Delete inexistant item should fail", func(t *testing.T) { - err := f.DeleteItem(share.Name, "test.txt") + err := f.DeleteItem(context.Background(), share.Name, "test.txt") if err != storage.ErrItemNotFound { t.Errorf("Expected ErrItemNotFound, got %v", err) } }) reader := bufio.NewReader(bytes.NewReader([]byte("test"))) - _, _ = f.CreateItem(share.Name, "test.txt", 0, reader) + _, _ = f.CreateItem(context.Background(), share.Name, "test.txt", 0, reader) - err := f.DeleteItem(share.Name, "test.txt") + err := f.DeleteItem(context.Background(), share.Name, "test.txt") if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -229,9 +230,9 @@ func TestDeleteShare(t *testing.T) { t.Errorf("Expected FileStorage to be created") } - share, _ := f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) + share, _ := f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload"}) - err := f.DeleteShare(share.Name) + err := f.DeleteShare(context.Background(), share.Name) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -256,26 +257,6 @@ func TestSafeShareName(t *testing.T) { } } -// func createFile(path string, size int) { -// s := int64(size * 1024 * 1024) -// fd, err := os.Create(path) -// if err != nil { -// log.Fatal("Failed to create output") -// } -// _, err = fd.Seek(s-1, 0) -// if err != nil { -// log.Fatal("Failed to seek") -// } -// _, err = fd.Write([]byte{0}) -// if err != nil { -// log.Fatal("Write failed") -// } -// err = fd.Close() -// if err != nil { -// log.Fatal("Failed to close file") -// } -// } - func TestGetItemData(t *testing.T) { c := storage.FileStorageConfig{ Path: "file_testdata/data", @@ -288,7 +269,7 @@ func TestGetItemData(t *testing.T) { t.Errorf("Expected FileStorage to be created") } - r, err := f.GetItemData("test", "test.txt") + r, err := f.GetItemData(context.Background(), "test", "test.txt") if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -314,7 +295,7 @@ func TestGetShare(t *testing.T) { f := storage.NewFileStorage(c) - share, err := f.GetShare("test") + share, err := f.GetShare(context.Background(), "test") if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -347,7 +328,7 @@ func TestListShare(t *testing.T) { f := storage.NewFileStorage(c) - items, err := f.ListShare("test") + items, err := f.ListShare(context.Background(), "test") if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -378,7 +359,7 @@ func TestListShares(t *testing.T) { f := storage.NewFileStorage(c) - shares, err := f.ListShares() + shares, err := f.ListShares(context.Background()) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -492,7 +473,7 @@ func TestMigrate(t *testing.T) { for _, test := range tests { t.Run(fmt.Sprintf("Get share %s", test.name), func(t *testing.T) { - share, _ := f.GetShare(test.name) + share, _ := f.GetShare(context.Background(), test.name) if !reflect.DeepEqual(*share, test.want) { t.Errorf("Expected %v, got %v", test.want, share) @@ -517,7 +498,7 @@ func TestShareWithDescriptionAndMessage(t *testing.T) { t.Errorf("Expected FileStorage to be created") } - share, err := f.CreateShare("test", "admin", storage.Options{Validity: 10, Exposure: "upload", Description: "test description", Message: "test message"}) + share, err := f.CreateShare(context.Background(), "test", "admin", storage.Options{Validity: 10, Exposure: "upload", Description: "test description", Message: "test message"}) if err != nil { t.Errorf("Expected no error, got %v", err) } diff --git a/hupload/internal/storage/s3.go b/hupload/internal/storage/s3.go index 4fd3971..b434f6f 100644 --- a/hupload/internal/storage/s3.go +++ b/hupload/internal/storage/s3.go @@ -102,12 +102,12 @@ func (b *S3Backend) Migrate() error { } // CreateShare creates a new share -func (b *S3Backend) CreateShare(name, owner string, options Options) (*Share, error) { +func (b *S3Backend) CreateShare(ctx context.Context, name, owner string, options Options) (*Share, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } - _, err := b.GetShare(name) + _, err := b.GetShare(ctx, name) if err == nil { return nil, ErrShareAlreadyExists } @@ -130,7 +130,7 @@ func (b *S3Backend) CreateShare(name, owner string, options Options) (*Share, er return nil, err } - _, err = b.Client.PutObject(context.Background(), &s3.PutObjectInput{ + _, err = b.Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &b.Options.Bucket, Key: &path, Body: j, @@ -149,12 +149,12 @@ func (b *S3Backend) CreateShare(name, owner string, options Options) (*Share, er } // UpdateShare updates an existing share -func (b *S3Backend) UpdateShare(name string, options *Options) (*Options, error) { +func (b *S3Backend) UpdateShare(ctx context.Context, name string, options *Options) (*Options, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } - share, err := b.GetShare(name) + share, err := b.GetShare(ctx, name) if err != nil { return nil, err } @@ -168,7 +168,7 @@ func (b *S3Backend) UpdateShare(name string, options *Options) (*Options, error) return nil, err } - _, err = b.Client.PutObject(context.Background(), &s3.PutObjectInput{ + _, err = b.Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &b.Options.Bucket, Key: &path, Body: j, @@ -182,7 +182,7 @@ func (b *S3Backend) UpdateShare(name string, options *Options) (*Options, error) } // CreateItem creates a new item in a share -func (b *S3Backend) CreateItem(name, item string, size int64, r io.Reader) (*Item, error) { +func (b *S3Backend) CreateItem(ctx context.Context, name, item string, size int64, r io.Reader) (*Item, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } @@ -190,7 +190,7 @@ func (b *S3Backend) CreateItem(name, item string, size int64, r io.Reader) (*Ite return nil, ErrInvalidItemName } - share, err := b.GetShare(name) + share, err := b.GetShare(ctx, name) if err != nil { return nil, err } @@ -237,7 +237,7 @@ func (b *S3Backend) CreateItem(name, item string, size int64, r io.Reader) (*Ite } path := path.Join(name, item) - _, err = b.Client.PutObject(context.Background(), &s3.PutObjectInput{ + _, err = b.Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &b.Options.Bucket, Key: &path, Body: src, @@ -247,12 +247,12 @@ func (b *S3Backend) CreateItem(name, item string, size int64, r io.Reader) (*Ite return nil, err } - err = b.updateMetadata(name) + err = b.updateMetadata(ctx, name) if err != nil { return nil, err } - result, err := b.GetItem(name, item) + result, err := b.GetItem(ctx, name, item) if err != nil { return nil, err } @@ -261,7 +261,7 @@ func (b *S3Backend) CreateItem(name, item string, size int64, r io.Reader) (*Ite } // CreateItem creates a new item in a share -func (b *S3Backend) DeleteItem(share, item string) error { +func (b *S3Backend) DeleteItem(ctx context.Context, share, item string) error { if !IsShareNameSafe(share) { return ErrInvalidShareName } @@ -271,12 +271,12 @@ func (b *S3Backend) DeleteItem(share, item string) error { path := path.Join(share, item) - _, err := b.GetItem(share, item) + _, err := b.GetItem(ctx, share, item) if err != nil { return err } - _, err = b.Client.DeleteObject(context.Background(), &s3.DeleteObjectInput{ + _, err = b.Client.DeleteObject(ctx, &s3.DeleteObjectInput{ Bucket: &b.Options.Bucket, Key: &path, }) @@ -289,7 +289,7 @@ func (b *S3Backend) DeleteItem(share, item string) error { return err } - err = b.updateMetadata(share) + err = b.updateMetadata(ctx, share) if err != nil { return err } @@ -298,12 +298,12 @@ func (b *S3Backend) DeleteItem(share, item string) error { } // GetShare returns the share identified by share -func (b *S3Backend) GetShare(name string) (*Share, error) { +func (b *S3Backend) GetShare(ctx context.Context, name string) (*Share, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } path := path.Join("shares", name, ".metadata") - output, err := b.Client.GetObject(context.Background(), &s3.GetObjectInput{ + output, err := b.Client.GetObject(ctx, &s3.GetObjectInput{ Bucket: &b.Options.Bucket, Key: &path, }) @@ -325,9 +325,9 @@ func (b *S3Backend) GetShare(name string) (*Share, error) { } // ListShares returns the list of shares available -func (b *S3Backend) ListShares() ([]Share, error) { +func (b *S3Backend) ListShares(ctx context.Context) ([]Share, error) { prefix := "shares/" - output, err := b.Client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{ + output, err := b.Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ Bucket: &b.Options.Bucket, Prefix: &prefix, }) @@ -337,7 +337,7 @@ func (b *S3Backend) ListShares() ([]Share, error) { result := []Share{} for _, item := range output.Contents { - gOutput, err := b.Client.GetObject(context.Background(), &s3.GetObjectInput{ + gOutput, err := b.Client.GetObject(ctx, &s3.GetObjectInput{ Bucket: &b.Options.Bucket, Key: item.Key, }) @@ -360,11 +360,11 @@ func (b *S3Backend) ListShares() ([]Share, error) { } // ListShare returns the list of items in a share -func (b *S3Backend) ListShare(name string) ([]Item, error) { +func (b *S3Backend) ListShare(ctx context.Context, name string) ([]Item, error) { if !IsShareNameSafe(name) { return nil, ErrInvalidShareName } - output, err := b.Client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{ + output, err := b.Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ Bucket: &b.Options.Bucket, Prefix: &name, }) @@ -386,7 +386,7 @@ func (b *S3Backend) ListShare(name string) ([]Item, error) { // types.ObjectAttributesObjectSize, // }, } - gOutput, err := b.Client.HeadObject(context.Background(), &inputs) + gOutput, err := b.Client.HeadObject(ctx, &inputs) if err != nil { return nil, err } @@ -409,22 +409,22 @@ func (b *S3Backend) ListShare(name string) ([]Item, error) { } // ListShare returns the list of items in a share -func (b *S3Backend) DeleteShare(name string) error { +func (b *S3Backend) DeleteShare(ctx context.Context, name string) error { if !IsShareNameSafe(name) { return ErrInvalidShareName } - _, err := b.GetShare(name) + _, err := b.GetShare(ctx, name) if err != nil { return err } - content, err := b.ListShare(name) + content, err := b.ListShare(ctx, name) if err != nil { return err } for _, item := range content { - err = b.DeleteItem(name, path.Base(item.Path)) + err = b.DeleteItem(ctx, name, path.Base(item.Path)) if err != nil { return err } @@ -432,7 +432,7 @@ func (b *S3Backend) DeleteShare(name string) error { path := path.Join("shares", name, ".metadata") - _, err = b.Client.DeleteObject(context.Background(), &s3.DeleteObjectInput{ + _, err = b.Client.DeleteObject(ctx, &s3.DeleteObjectInput{ Bucket: &b.Options.Bucket, Key: &path, }) @@ -445,7 +445,7 @@ func (b *S3Backend) DeleteShare(name string) error { } // GetItem returns the item identified by share and item -func (b *S3Backend) GetItem(share, item string) (*Item, error) { +func (b *S3Backend) GetItem(ctx context.Context, share, item string) (*Item, error) { if !IsShareNameSafe(share) { return nil, ErrInvalidShareName } @@ -455,7 +455,7 @@ func (b *S3Backend) GetItem(share, item string) (*Item, error) { path := path.Join(share, item) - aOutput, err := b.Client.GetObjectAttributes(context.Background(), &s3.GetObjectAttributesInput{ + aOutput, err := b.Client.GetObjectAttributes(ctx, &s3.GetObjectAttributesInput{ Bucket: &b.Options.Bucket, Key: &path, ObjectAttributes: []types.ObjectAttributes{ @@ -483,7 +483,7 @@ func (b *S3Backend) GetItem(share, item string) (*Item, error) { } // GetItem returns the item identified by share and item -func (b *S3Backend) GetItemData(share, item string) (io.ReadCloser, error) { +func (b *S3Backend) GetItemData(ctx context.Context, share, item string) (io.ReadCloser, error) { if !IsShareNameSafe(share) { return nil, ErrInvalidShareName } @@ -491,14 +491,14 @@ func (b *S3Backend) GetItemData(share, item string) (io.ReadCloser, error) { return nil, ErrInvalidItemName } - _, err := b.GetItem(share, item) + _, err := b.GetItem(ctx, share, item) if err != nil { return nil, err } path := path.Join(share, item) - aOutput, err := b.Client.GetObject(context.Background(), &s3.GetObjectInput{ + aOutput, err := b.Client.GetObject(ctx, &s3.GetObjectInput{ Bucket: &b.Options.Bucket, Key: &path, }) @@ -510,12 +510,12 @@ func (b *S3Backend) GetItemData(share, item string) (io.ReadCloser, error) { return aOutput.Body, err } -func (b *S3Backend) updateMetadata(s string) error { +func (b *S3Backend) updateMetadata(ctx context.Context, s string) error { if !IsShareNameSafe(s) { return ErrInvalidShareName } - c, err := b.ListShare(s) + c, err := b.ListShare(ctx, s) if err != nil { return err } @@ -527,7 +527,7 @@ func (b *S3Backend) updateMetadata(s string) error { capacity += i.ItemInfo.Size } - share, err := b.GetShare(s) + share, err := b.GetShare(ctx, s) if err != nil { return err } @@ -542,7 +542,7 @@ func (b *S3Backend) updateMetadata(s string) error { path := path.Join("shares", s, ".metadata") - _, err = b.Client.PutObject(context.Background(), &s3.PutObjectInput{ + _, err = b.Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &b.Options.Bucket, Key: &path, Body: j, diff --git a/hupload/internal/storage/s3_test.go b/hupload/internal/storage/s3_test.go index 0bf78e6..ef464b3 100644 --- a/hupload/internal/storage/s3_test.go +++ b/hupload/internal/storage/s3_test.go @@ -3,6 +3,7 @@ package storage_test import ( "bufio" "bytes" + "context" "os" "reflect" "testing" @@ -35,11 +36,11 @@ func TestS3CreateShare(t *testing.T) { f := createS3Backend(t) t.Cleanup(func() { - _ = f.DeleteShare("Test") + _ = f.DeleteShare(context.Background(), "Test") }) // Test create share - _, err := f.CreateShare("Test", "admin", storage.DefaultOptions()) + _, err := f.CreateShare(context.Background(), "Test", "admin", storage.DefaultOptions()) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -49,11 +50,11 @@ func TestS3UpdateShare(t *testing.T) { f := createS3Backend(t) t.Cleanup(func() { - _ = f.DeleteShare("Test") + _ = f.DeleteShare(context.Background(), "Test") }) // Test create share - _, err := f.CreateShare("Test", "admin", storage.DefaultOptions()) + _, err := f.CreateShare(context.Background(), "Test", "admin", storage.DefaultOptions()) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -65,7 +66,7 @@ func TestS3UpdateShare(t *testing.T) { Message: "message", Description: "description", } - options, err := f.UpdateShare("Test", newOptions) + options, err := f.UpdateShare(context.Background(), "Test", newOptions) if err != nil { t.Errorf("Expected no error, got %v", err) @@ -81,10 +82,10 @@ func TestCreateS3Item(t *testing.T) { f := createS3Backend(t) t.Cleanup(func() { - _ = f.DeleteShare("Test") + _ = f.DeleteShare(context.Background(), "Test") }) - _, err := f.CreateShare("Test", "admin", storage.DefaultOptions()) + _, err := f.CreateShare(context.Background(), "Test", "admin", storage.DefaultOptions()) if err != nil { t.Errorf("Expected no error, got %v", err) return @@ -94,7 +95,7 @@ func TestCreateS3Item(t *testing.T) { b := bufio.NewReader(bytes.NewBuffer([]byte("test"))) // Test create item - _, err = f.CreateItem("Test", "test.txt", int64(len(content)), b) + _, err = f.CreateItem(context.Background(), "Test", "test.txt", int64(len(content)), b) if err != nil { t.Errorf("Expected no error, got %v", err) } @@ -104,7 +105,7 @@ func TestS3GetShare(t *testing.T) { f := createS3Backend(t) t.Cleanup(func() { - _ = f.DeleteShare("Test") + _ = f.DeleteShare(context.Background(), "Test") }) options := storage.Options{ @@ -113,14 +114,14 @@ func TestS3GetShare(t *testing.T) { Message: "message", Description: "description", } - _, err := f.CreateShare("Test", "admin", options) + _, err := f.CreateShare(context.Background(), "Test", "admin", options) if err != nil { t.Errorf("Expected no error, got %v", err) return } // Test get share - got, err := f.GetShare("Test") + got, err := f.GetShare(context.Background(), "Test") if err != nil { t.Errorf("Expected no error, got %v", err) return @@ -143,27 +144,28 @@ func TestS3ListShares(t *testing.T) { f := createS3Backend(t) t.Cleanup(func() { - _ = f.DeleteShare("Test1") - _ = f.DeleteShare("Test2") + _ = f.DeleteShare(context.Background(), "Test1") + _ = f.DeleteShare(context.Background(), "Test2") }) var ( err error ) - _, err = f.CreateShare("Test1", "admin", storage.DefaultOptions()) + _, err = f.CreateShare(context.Background(), "Test1", "admin", storage.DefaultOptions()) if err != nil { t.Errorf("Expected no error, got %v", err) return } - _, err = f.CreateShare("Test2", "admin", storage.DefaultOptions()) + time.Sleep(1 * time.Second) + _, err = f.CreateShare(context.Background(), "Test2", "admin", storage.DefaultOptions()) if err != nil { t.Errorf("Expected no error, got %v", err) return } // Test list shares - got, err := f.ListShares() + got, err := f.ListShares(context.Background()) if err != nil { t.Errorf("Expected no error, got %v", err) return diff --git a/hupload/internal/storage/storage.go b/hupload/internal/storage/storage.go index dd95ae3..177c790 100644 --- a/hupload/internal/storage/storage.go +++ b/hupload/internal/storage/storage.go @@ -1,6 +1,7 @@ package storage import ( + "context" "io" "time" ) @@ -87,32 +88,32 @@ type Storage interface { Migrate() error // CreateShare creates a new share - CreateShare(name, owner string, options Options) (*Share, error) + CreateShare(ctx context.Context, name, owner string, options Options) (*Share, error) // UpdateShare updates an existing share - UpdateShare(name string, options *Options) (*Options, error) + UpdateShare(ctx context.Context, name string, options *Options) (*Options, error) // CreateItem creates a new item in a share - CreateItem(share, item string, size int64, reader io.Reader) (*Item, error) + CreateItem(ctx context.Context, share, item string, size int64, reader io.Reader) (*Item, error) // CreateItem creates a new item in a share - DeleteItem(share, item string) error + DeleteItem(ctx context.Context, share, item string) error // GetShare returns the share identified by share - GetShare(string) (*Share, error) + GetShare(ctx context.Context, share string) (*Share, error) // ListShares returns the list of shares available - ListShares() ([]Share, error) + ListShares(ctx context.Context) ([]Share, error) // ListShare returns the list of items in a share - ListShare(string) ([]Item, error) + ListShare(ctx context.Context, share string) ([]Item, error) // ListShare returns the list of items in a share - DeleteShare(string) error + DeleteShare(ctx context.Context, share string) error // GetItem returns the item identified by share and item - GetItem(string, string) (*Item, error) + GetItem(ctx context.Context, share, item string) (*Item, error) // GetItem returns the item identified by share and item - GetItemData(string, string) (io.ReadCloser, error) + GetItemData(ctx context.Context, share string, item string) (io.ReadCloser, error) }