From d2d944ede315dce81f9a80070cc9142bc28026fd Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Thu, 28 Mar 2024 09:35:56 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9B=B4=E6=96=B0Object?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E3=80=81=E8=8E=B7=E5=8F=96Package?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=AD=89=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sdks/storage/bucket.go | 35 ++++++++++++++ sdks/storage/object.go | 86 +++++++++++++++++++++++++++++++-- sdks/storage/package.go | 103 ++++++++++++++++++++++++++-------------- 3 files changed, 184 insertions(+), 40 deletions(-) diff --git a/sdks/storage/bucket.go b/sdks/storage/bucket.go index a4183a2..4420267 100644 --- a/sdks/storage/bucket.go +++ b/sdks/storage/bucket.go @@ -84,3 +84,38 @@ func (c *BucketService) Delete(req BucketDeleteReq) (*BucketDeleteResp, error) { return nil, codeResp.ToError() } + +const BucketListUserBucketsPath = "/bucket/listUserBuckets" + +type BucketListUserBucketsReq struct { + UserID UserID `form:"userID" json:"userID" binding:"required"` +} + +type BucketListUserBucketsResp struct { + Buckets []Bucket `json:"buckets"` +} + +func (c *BucketService) ListUserBuckets(req BucketListUserBucketsReq) (*BucketListUserBucketsResp, error) { + url, err := url.JoinPath(c.baseURL, BucketListUserBucketsPath) + if err != nil { + return nil, err + } + + resp, err := myhttp.GetForm(url, myhttp.RequestParam{ + Query: req, + }) + if err != nil { + return nil, err + } + + codeResp, err := myhttp.ParseJSONResponse[response[BucketListUserBucketsResp]](resp) + if err != nil { + return nil, err + } + + if codeResp.Code == errorcode.OK { + return &codeResp.Data, nil + } + + return nil, codeResp.ToError() +} diff --git a/sdks/storage/object.go b/sdks/storage/object.go index abbefd4..7421133 100644 --- a/sdks/storage/object.go +++ b/sdks/storage/object.go @@ -5,6 +5,7 @@ import ( "io" "net/url" "strings" + "time" "gitlink.org.cn/cloudream/common/consts/errorcode" "gitlink.org.cn/cloudream/common/pkgs/iterator" @@ -90,8 +91,8 @@ func (c *ObjectService) Upload(req ObjectUploadReq) (*ObjectUploadResp, error) { const ObjectDownloadPath = "/object/download" type ObjectDownloadReq struct { - UserID int64 `json:"userID"` - ObjectID int64 `json:"objectID"` + UserID UserID `form:"userID" json:"userID" binding:"required"` + ObjectID ObjectID `form:"objectID" json:"objectID" binding:"required"` } func (c *ObjectService) Download(req ObjectDownloadReq) (io.ReadCloser, error) { @@ -125,11 +126,88 @@ func (c *ObjectService) Download(req ObjectDownloadReq) (io.ReadCloser, error) { return nil, fmt.Errorf("unknow response content type: %s", contType) } +const ObjectUpdateInfoPath = "/object/updateInfo" + +type UpdatingObject struct { + ObjectID ObjectID `json:"objectID" binding:"required"` + UpdateTime time.Time `json:"updateTime" binding:"required"` +} + +func (u *UpdatingObject) ApplyTo(obj *Object) { + obj.UpdateTime = u.UpdateTime +} + +type ObjectUpdateInfoReq struct { + UserID UserID `json:"userID" binding:"required"` + Updatings []UpdatingObject `json:"updatings" binding:"required"` +} + +type ObjectUpdateInfoResp struct{} + +func (c *ObjectService) Update(req ObjectUpdateInfoReq) (*ObjectUpdateInfoResp, error) { + url, err := url.JoinPath(c.baseURL, ObjectUpdateInfoPath) + if err != nil { + return nil, err + } + + resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ + Body: req, + }) + if err != nil { + return nil, err + } + + jsonResp, err := myhttp.ParseJSONResponse[response[ObjectUpdateInfoResp]](resp) + if err != nil { + return nil, err + } + + if jsonResp.Code == errorcode.OK { + return &jsonResp.Data, nil + } + + return nil, jsonResp.ToError() +} + +const ObjectDeletePath = "/object/delete" + +type ObjectDeleteReq struct { + UserID UserID `json:"userID" binding:"required"` + ObjectIDs []ObjectID `json:"objectIDs" binding:"required"` +} + +type ObjectDeleteResp struct{} + +func (c *ObjectService) Delete(req ObjectDeleteReq) (*ObjectDeleteResp, error) { + url, err := url.JoinPath(c.baseURL, ObjectDeletePath) + if err != nil { + return nil, err + } + + resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ + Body: req, + }) + if err != nil { + return nil, err + } + + jsonResp, err := myhttp.ParseJSONResponse[response[ObjectDeleteResp]](resp) + if err != nil { + return nil, err + } + + if jsonResp.Code == errorcode.OK { + return &jsonResp.Data, nil + } + + return nil, jsonResp.ToError() +} + const ObjectGetPackageObjectsPath = "/object/getPackageObjects" type ObjectGetPackageObjectsReq struct { - UserID UserID `json:"userID"` - PackageID PackageID `json:"packageID"` + UserID UserID `form:"userID" json:"userID" binding:"required"` + PackageID PackageID `form:"packageID" json:"packageID" binding:"required"` } type ObjectGetPackageObjectsResp struct { Objects []Object `json:"objects"` diff --git a/sdks/storage/package.go b/sdks/storage/package.go index 26a8931..988030c 100644 --- a/sdks/storage/package.go +++ b/sdks/storage/package.go @@ -21,8 +21,8 @@ func (c *Client) Package() *PackageService { const PackageGetPath = "/package/get" type PackageGetReq struct { - UserID UserID `json:"userID"` - PackageID PackageID `json:"packageID"` + UserID UserID `form:"userID" json:"userID" binding:"required"` + PackageID PackageID `form:"packageID" json:"packageID" binding:"required"` } type PackageGetResp struct { Package @@ -90,13 +90,15 @@ func (s *PackageService) Create(req PackageCreateReq) (*PackageCreateResp, error return nil, codeResp.ToError() } +const PackageDeletePath = "/package/delete" + type PackageDeleteReq struct { - UserID UserID `json:"userID"` - PackageID PackageID `json:"packageID"` + UserID UserID `json:"userID" binding:"required"` + PackageID PackageID `json:"packageID" binding:"required"` } func (c *PackageService) Delete(req PackageDeleteReq) error { - url, err := url.JoinPath(c.baseURL, "/package/delete") + url, err := url.JoinPath(c.baseURL, PackageDeletePath) if err != nil { return err } @@ -126,9 +128,47 @@ func (c *PackageService) Delete(req PackageDeleteReq) error { return fmt.Errorf("unknow response content type: %s", contType) } +const PackageListBucketPackagesPath = "/package/listBucketPackages" + +type PackageListBucketPackagesReq struct { + UserID UserID `form:"userID" json:"userID" binding:"required"` + BucketID BucketID `form:"bucketID" json:"bucketID" binding:"required"` +} + +type PackageListBucketPackagesResp struct { + Packages []Package `json:"packages"` +} + +func (c *PackageService) ListBucketPackages(req PackageListBucketPackagesReq) (*PackageListBucketPackagesResp, error) { + url, err := url.JoinPath(c.baseURL, PackageListBucketPackagesPath) + if err != nil { + return nil, err + } + + resp, err := myhttp.GetForm(url, myhttp.RequestParam{ + Query: req, + }) + if err != nil { + return nil, err + } + + codeResp, err := myhttp.ParseJSONResponse[response[PackageListBucketPackagesResp]](resp) + if err != nil { + return nil, err + } + + if codeResp.Code == errorcode.OK { + return &codeResp.Data, nil + } + + return nil, codeResp.ToError() +} + +const PackageGetCachedNodesPath = "/package/getCachedNodes" + type PackageGetCachedNodesReq struct { - PackageID PackageID `json:"packageID"` - UserID UserID `json:"userID"` + PackageID PackageID `form:"packageID" json:"packageID" binding:"required"` + UserID UserID `form:"userID" json:"userID" binding:"required"` } type PackageGetCachedNodesResp struct { @@ -136,7 +176,7 @@ type PackageGetCachedNodesResp struct { } func (c *PackageService) GetCachedNodes(req PackageGetCachedNodesReq) (*PackageGetCachedNodesResp, error) { - url, err := url.JoinPath(c.baseURL, "/package/getCachedNodes") + url, err := url.JoinPath(c.baseURL, PackageGetCachedNodesPath) if err != nil { return nil, err } @@ -146,27 +186,24 @@ func (c *PackageService) GetCachedNodes(req PackageGetCachedNodesReq) (*PackageG if err != nil { return nil, err } - contType := resp.Header.Get("Content-Type") - if strings.Contains(contType, myhttp.ContentTypeJSON) { - var codeResp response[PackageGetCachedNodesResp] - if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { - return nil, fmt.Errorf("parsing response: %w", err) - } - - if codeResp.Code == errorcode.OK { - return &codeResp.Data, nil - } + codeResp, err := myhttp.ParseJSONResponse[response[PackageGetCachedNodesResp]](resp) + if err != nil { + return nil, err + } - return nil, codeResp.ToError() + if codeResp.Code == errorcode.OK { + return &codeResp.Data, nil } - return nil, fmt.Errorf("unknow response content type: %s", contType) + return nil, codeResp.ToError() } +const PackageGetLoadedNodesPath = "/package/getLoadedNodes" + type PackageGetLoadedNodesReq struct { - PackageID PackageID `json:"packageID"` - UserID UserID `json:"userID"` + PackageID PackageID `form:"packageID" json:"packageID" binding:"required"` + UserID UserID `form:"userID" json:"userID" binding:"required"` } type PackageGetLoadedNodesResp struct { @@ -174,7 +211,7 @@ type PackageGetLoadedNodesResp struct { } func (c *PackageService) GetLoadedNodes(req PackageGetLoadedNodesReq) (*PackageGetLoadedNodesResp, error) { - url, err := url.JoinPath(c.baseURL, "/package/getLoadedNodes") + url, err := url.JoinPath(c.baseURL, PackageGetLoadedNodesPath) if err != nil { return nil, err } @@ -185,20 +222,14 @@ func (c *PackageService) GetLoadedNodes(req PackageGetLoadedNodesReq) (*PackageG return nil, err } - contType := resp.Header.Get("Content-Type") - if strings.Contains(contType, myhttp.ContentTypeJSON) { - - var codeResp response[PackageGetLoadedNodesResp] - if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { - return nil, fmt.Errorf("parsing response: %w", err) - } - - if codeResp.Code == errorcode.OK { - return &codeResp.Data, nil - } + codeResp, err := myhttp.ParseJSONResponse[response[PackageGetLoadedNodesResp]](resp) + if err != nil { + return nil, err + } - return nil, codeResp.ToError() + if codeResp.Code == errorcode.OK { + return &codeResp.Data, nil } - return nil, fmt.Errorf("unknow response content type: %s", contType) + return nil, codeResp.ToError() } From 064ae123b85b1a091f67af8b01256302c4931fbf Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Thu, 28 Mar 2024 16:44:53 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=B8=8B=E8=BD=BDObject?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkgs/iterator/empty.go | 15 ++++++ sdks/storage/object.go | 34 ++++++++++--- sdks/storage/storage_test.go | 16 +++--- utils/http/http.go | 96 ++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 pkgs/iterator/empty.go diff --git a/pkgs/iterator/empty.go b/pkgs/iterator/empty.go new file mode 100644 index 0000000..0fea9cc --- /dev/null +++ b/pkgs/iterator/empty.go @@ -0,0 +1,15 @@ +package iterator + +type emptyIterator[T any] struct{} + +func (i *emptyIterator[T]) MoveNext() (T, error) { + var ret T + return ret, ErrNoMoreItem +} +func (i *emptyIterator[T]) Close() { + +} + +func Empty[T any]() Iterator[T] { + return &emptyIterator[T]{} +} diff --git a/sdks/storage/object.go b/sdks/storage/object.go index 7421133..cb5e49e 100644 --- a/sdks/storage/object.go +++ b/sdks/storage/object.go @@ -36,12 +36,12 @@ type ObjectUploadInfo struct { NodeAffinity *NodeID `json:"nodeAffinity"` } -type IterObjectUpload struct { +type UploadingObject struct { Path string File io.ReadCloser } -type UploadObjectIterator = iterator.Iterator[*IterObjectUpload] +type UploadObjectIterator = iterator.Iterator[*UploadingObject] type ObjectUploadResp struct{} @@ -58,7 +58,7 @@ func (c *ObjectService) Upload(req ObjectUploadReq) (*ObjectUploadResp, error) { resp, err := myhttp.PostMultiPart(url, myhttp.MultiPartRequestParam{ Form: map[string]string{"info": string(infoJSON)}, - Files: iterator.Map(req.Files, func(src *IterObjectUpload) (*myhttp.IterMultiPartFile, error) { + Files: iterator.Map(req.Files, func(src *UploadingObject) (*myhttp.IterMultiPartFile, error) { return &myhttp.IterMultiPartFile{ FieldName: "files", FileName: src.Path, @@ -94,8 +94,12 @@ type ObjectDownloadReq struct { UserID UserID `form:"userID" json:"userID" binding:"required"` ObjectID ObjectID `form:"objectID" json:"objectID" binding:"required"` } +type DownloadingObject struct { + Path string + File io.ReadCloser +} -func (c *ObjectService) Download(req ObjectDownloadReq) (io.ReadCloser, error) { +func (c *ObjectService) Download(req ObjectDownloadReq) (*DownloadingObject, error) { url, err := url.JoinPath(c.baseURL, ObjectDownloadPath) if err != nil { return nil, err @@ -119,11 +123,27 @@ func (c *ObjectService) Download(req ObjectDownloadReq) (io.ReadCloser, error) { return nil, codeResp.ToError() } - if strings.Contains(contType, myhttp.ContentTypeOctetStream) { - return resp.Body, nil + if !strings.Contains(contType, myhttp.ContentTypeMultiPart) { + return nil, fmt.Errorf("unknow response content type: %s", contType) } - return nil, fmt.Errorf("unknow response content type: %s", contType) + _, files, err := myhttp.ParseMultiPartResponse(resp) + if err != nil { + return nil, err + } + + file, err := files.MoveNext() + if err == iterator.ErrNoMoreItem { + return nil, fmt.Errorf("no file found in response") + } + if err != nil { + return nil, err + } + + return &DownloadingObject{ + Path: file.FileName, + File: file.File, + }, nil } const ObjectUpdateInfoPath = "/object/updateInfo" diff --git a/sdks/storage/storage_test.go b/sdks/storage/storage_test.go index 5521a47..0527fbe 100644 --- a/sdks/storage/storage_test.go +++ b/sdks/storage/storage_test.go @@ -36,11 +36,11 @@ func Test_PackageGet(t *testing.T) { PackageID: createResp.PackageID, }, Files: iterator.Array( - &IterObjectUpload{ + &UploadingObject{ Path: "test", File: io.NopCloser(bytes.NewBuffer(fileData)), }, - &IterObjectUpload{ + &UploadingObject{ Path: "test2", File: io.NopCloser(bytes.NewBuffer(fileData)), }, @@ -93,11 +93,11 @@ func Test_Object(t *testing.T) { NodeAffinity: &nodeAff, }, Files: iterator.Array( - &IterObjectUpload{ + &UploadingObject{ Path: "test", File: io.NopCloser(bytes.NewBuffer(fileData)), }, - &IterObjectUpload{ + &UploadingObject{ Path: "test2", File: io.NopCloser(bytes.NewBuffer(fileData)), }, @@ -149,11 +149,11 @@ func Test_Storage(t *testing.T) { PackageID: createResp.PackageID, }, Files: iterator.Array( - &IterObjectUpload{ + &UploadingObject{ Path: "test", File: io.NopCloser(bytes.NewBuffer(fileData)), }, - &IterObjectUpload{ + &UploadingObject{ Path: "test2", File: io.NopCloser(bytes.NewBuffer(fileData)), }, @@ -201,11 +201,11 @@ func Test_Cache(t *testing.T) { PackageID: createResp.PackageID, }, Files: iterator.Array( - &IterObjectUpload{ + &UploadingObject{ Path: "test.txt", File: io.NopCloser(bytes.NewBuffer(fileData)), }, - &IterObjectUpload{ + &UploadingObject{ Path: "test2.txt", File: io.NopCloser(bytes.NewBuffer(fileData)), }, diff --git a/utils/http/http.go b/utils/http/http.go index 463bd37..bab12e6 100644 --- a/utils/http/http.go +++ b/utils/http/http.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io" + "mime" "mime/multipart" "net/http" ul "net/url" @@ -131,6 +132,101 @@ func ParseJSONResponse[TBody any](resp *http.Response) (TBody, error) { return ret, fmt.Errorf("unknow response content type: %s, status: %d, body(prefix): %s", contType, resp.StatusCode, strCont[:math.Min(len(strCont), 200)]) } +type MultiPartFile struct { + FileName string + File io.ReadCloser +} + +type multiPartFileIterator struct { + mr *multipart.Reader + firstFile *multipart.Part +} + +func (m *multiPartFileIterator) MoveNext() (*MultiPartFile, error) { + if m.firstFile != nil { + f := m.firstFile + m.firstFile = nil + return &MultiPartFile{ + FileName: f.FileName(), + File: f, + }, nil + } + + for { + part, err := m.mr.NextPart() + if err == io.EOF { + return nil, iterator.ErrNoMoreItem + } + if err != nil { + return nil, err + } + + if part.FileName() != "" { + return &MultiPartFile{ + FileName: part.FileName(), + File: part, + }, nil + } + } +} + +func (m *multiPartFileIterator) Close() {} + +// 解析multipart/form-data响应,只支持form参数在头部的情况 +func ParseMultiPartResponse(resp *http.Response) (map[string]string, iterator.Iterator[*MultiPartFile], error) { + mtype, params, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return nil, nil, fmt.Errorf("parse content type: %w", err) + } + + if mtype != ContentTypeMultiPart { + return nil, nil, fmt.Errorf("unknow content type: %s", mtype) + } + + boundary := params["boundary"] + if boundary == "" { + return nil, nil, fmt.Errorf("no boundary in content type: %s", mtype) + } + + formValues := make(map[string]string) + rd := multipart.NewReader(resp.Body, boundary) + + var firstFile *multipart.Part + for { + part, err := rd.NextPart() + if err == io.EOF { + return formValues, iterator.Empty[*MultiPartFile](), nil + } + if err != nil { + return nil, nil, err + } + + formName := part.FormName() + fileName := part.FileName() + + if formName == "" { + continue + } + + if fileName != "" { + firstFile = part + break + } + + data, err := io.ReadAll(part) + if err != nil { + return nil, nil, err + } + + formValues[formName] = string(data) + } + + return formValues, &multiPartFileIterator{ + mr: rd, + firstFile: firstFile, + }, nil +} + type MultiPartRequestParam struct { Header any Query any From 3e9092341637f4e36d7d2605ecb0b93ff7920f4d Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Fri, 29 Mar 2024 10:40:32 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sdks/storage/bucket.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdks/storage/bucket.go b/sdks/storage/bucket.go index 4420267..19cb5de 100644 --- a/sdks/storage/bucket.go +++ b/sdks/storage/bucket.go @@ -18,8 +18,8 @@ func (c *Client) Bucket() *BucketService { const BucketCreatePath = "/bucket/create" type BucketCreateReq struct { - UserID UserID `json:"userID" binding:"required"` - BucketName string `json:"bucketName" binding:"required"` + UserID UserID `json:"userID" binding:"required"` + Name string `json:"name" binding:"required"` } type BucketCreateResp struct { From eef5bc46c0edc3400be1076832396ecc19624235 Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Fri, 29 Mar 2024 16:20:04 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sdks/storage/object.go | 51 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/sdks/storage/object.go b/sdks/storage/object.go index cb5e49e..e30af8e 100644 --- a/sdks/storage/object.go +++ b/sdks/storage/object.go @@ -162,7 +162,9 @@ type ObjectUpdateInfoReq struct { Updatings []UpdatingObject `json:"updatings" binding:"required"` } -type ObjectUpdateInfoResp struct{} +type ObjectUpdateInfoResp struct { + Successes []ObjectID `json:"successes"` +} func (c *ObjectService) Update(req ObjectUpdateInfoReq) (*ObjectUpdateInfoResp, error) { url, err := url.JoinPath(c.baseURL, ObjectUpdateInfoPath) @@ -189,6 +191,53 @@ func (c *ObjectService) Update(req ObjectUpdateInfoReq) (*ObjectUpdateInfoResp, return nil, jsonResp.ToError() } +const ObjectMovePath = "/object/move" + +type MovingObject struct { + ObjectID ObjectID `json:"objectID" binding:"required"` + PackageID PackageID `json:"packageID" binding:"required"` + Path string `json:"path" binding:"required"` +} + +func (m *MovingObject) ApplyTo(obj *Object) { + obj.PackageID = m.PackageID + obj.Path = m.Path +} + +type ObjectMoveReq struct { + UserID UserID `json:"userID" binding:"required"` + Movings []MovingObject `json:"movings" binding:"required"` +} + +type ObjectMoveResp struct { + Successes []ObjectID `json:"successes"` +} + +func (c *ObjectService) Move(req ObjectMoveReq) (*ObjectMoveResp, error) { + url, err := url.JoinPath(c.baseURL, ObjectMovePath) + if err != nil { + return nil, err + } + + resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ + Body: req, + }) + if err != nil { + return nil, err + } + + jsonResp, err := myhttp.ParseJSONResponse[response[ObjectMoveResp]](resp) + if err != nil { + return nil, err + } + + if jsonResp.Code == errorcode.OK { + return &jsonResp.Data, nil + } + + return nil, jsonResp.ToError() +} + const ObjectDeletePath = "/object/delete" type ObjectDeleteReq struct { From d84c4ee82db6ecb49fc9118ae349e3d7e765ec4d Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Thu, 11 Apr 2024 09:29:39 +0800 Subject: [PATCH 5/5] =?UTF-8?q?cds=E6=94=AF=E6=8C=81rclone=E6=8C=82?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sdks/storage/bucket.go | 61 ++++++++++++++++++++++++++++-------- sdks/storage/cache.go | 2 +- sdks/storage/models.go | 2 +- sdks/storage/node.go | 2 +- sdks/storage/object.go | 57 +++++++++++++++++---------------- sdks/storage/package.go | 60 ++++++++++++++++++++++++++++------- sdks/storage/storage.go | 4 +-- sdks/storage/storage_test.go | 50 ++++++++++++++--------------- sdks/storage/utils.go | 33 ++++++++++++++++++- utils/http/http.go | 28 ++++++++++++----- utils/serder/serder.go | 12 +++++++ 11 files changed, 221 insertions(+), 90 deletions(-) diff --git a/sdks/storage/bucket.go b/sdks/storage/bucket.go index 19cb5de..15bfac8 100644 --- a/sdks/storage/bucket.go +++ b/sdks/storage/bucket.go @@ -15,18 +15,53 @@ func (c *Client) Bucket() *BucketService { return &BucketService{c} } +const BucketGetByNamePath = "/bucket/getByName" + +type BucketGetByName struct { + UserID UserID `json:"userID" form:"userID" binding:"required"` + Name string `json:"name" form:"name" binding:"required"` +} +type BucketGetByNameResp struct { + Bucket Bucket `json:"bucket"` +} + +func (c *BucketService) GetByName(req BucketGetByName) (*BucketGetByNameResp, error) { + url, err := url.JoinPath(c.baseURL, BucketGetByNamePath) + if err != nil { + return nil, err + } + + resp, err := myhttp.GetForm(url, myhttp.RequestParam{ + Query: req, + }) + if err != nil { + return nil, err + } + + codeResp, err := ParseJSONResponse[response[BucketGetByNameResp]](resp) + if err != nil { + return nil, err + } + + if codeResp.Code == errorcode.OK { + return &codeResp.Data, nil + } + + return nil, codeResp.ToError() +} + const BucketCreatePath = "/bucket/create" -type BucketCreateReq struct { +type BucketCreate struct { UserID UserID `json:"userID" binding:"required"` Name string `json:"name" binding:"required"` } type BucketCreateResp struct { - BucketID BucketID `json:"bucketID"` + Bucket Bucket `json:"bucket"` } -func (c *BucketService) Create(req BucketCreateReq) (*BucketCreateResp, error) { +func (c *BucketService) Create(req BucketCreate) (*BucketCreateResp, error) { url, err := url.JoinPath(c.baseURL, BucketCreatePath) if err != nil { return nil, err @@ -39,7 +74,7 @@ func (c *BucketService) Create(req BucketCreateReq) (*BucketCreateResp, error) { return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[BucketCreateResp]](resp) + codeResp, err := ParseJSONResponse[response[BucketCreateResp]](resp) if err != nil { return nil, err } @@ -53,36 +88,36 @@ func (c *BucketService) Create(req BucketCreateReq) (*BucketCreateResp, error) { const BucketDeletePath = "/bucket/delete" -type BucketDeleteReq struct { +type BucketDelete struct { UserID UserID `json:"userID" binding:"required"` BucketID BucketID `json:"bucketID" binding:"required"` } type BucketDeleteResp struct{} -func (c *BucketService) Delete(req BucketDeleteReq) (*BucketDeleteResp, error) { +func (c *BucketService) Delete(req BucketDelete) error { url, err := url.JoinPath(c.baseURL, BucketDeletePath) if err != nil { - return nil, err + return err } resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ Body: req, }) if err != nil { - return nil, err + return err } - codeResp, err := myhttp.ParseJSONResponse[response[BucketDeleteResp]](resp) + codeResp, err := ParseJSONResponse[response[BucketDeleteResp]](resp) if err != nil { - return nil, err + return err } if codeResp.Code == errorcode.OK { - return &codeResp.Data, nil + return nil } - return nil, codeResp.ToError() + return codeResp.ToError() } const BucketListUserBucketsPath = "/bucket/listUserBuckets" @@ -108,7 +143,7 @@ func (c *BucketService) ListUserBuckets(req BucketListUserBucketsReq) (*BucketLi return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[BucketListUserBucketsResp]](resp) + codeResp, err := ParseJSONResponse[response[BucketListUserBucketsResp]](resp) if err != nil { return nil, err } diff --git a/sdks/storage/cache.go b/sdks/storage/cache.go index e7574dd..74d02b7 100644 --- a/sdks/storage/cache.go +++ b/sdks/storage/cache.go @@ -29,7 +29,7 @@ func (c *Client) CacheMovePackage(req CacheMovePackageReq) (*CacheMovePackageRes return nil, err } - jsonResp, err := myhttp.ParseJSONResponse[response[CacheMovePackageResp]](resp) + jsonResp, err := ParseJSONResponse[response[CacheMovePackageResp]](resp) if err != nil { return nil, err } diff --git a/sdks/storage/models.go b/sdks/storage/models.go index 0ad6b81..74128f4 100644 --- a/sdks/storage/models.go +++ b/sdks/storage/models.go @@ -10,7 +10,7 @@ import ( ) const ( - ObjectPathSeperator = "/" + ObjectPathSeparator = "/" ) type NodeID int64 diff --git a/sdks/storage/node.go b/sdks/storage/node.go index 050e859..111135f 100644 --- a/sdks/storage/node.go +++ b/sdks/storage/node.go @@ -30,7 +30,7 @@ func (c *Client) NodeGetNodes(req NodeGetNodesReq) (*NodeGetNodesResp, error) { return nil, err } - jsonResp, err := myhttp.ParseJSONResponse[response[NodeGetNodesResp]](resp) + jsonResp, err := ParseJSONResponse[response[NodeGetNodesResp]](resp) if err != nil { return nil, err } diff --git a/sdks/storage/object.go b/sdks/storage/object.go index e30af8e..0af5f41 100644 --- a/sdks/storage/object.go +++ b/sdks/storage/object.go @@ -25,7 +25,7 @@ func (c *Client) Object() *ObjectService { const ObjectUploadPath = "/object/upload" -type ObjectUploadReq struct { +type ObjectUpload struct { ObjectUploadInfo Files UploadObjectIterator `json:"-"` } @@ -43,9 +43,15 @@ type UploadingObject struct { type UploadObjectIterator = iterator.Iterator[*UploadingObject] -type ObjectUploadResp struct{} +type ObjectUploadResp struct { + Uploadeds []UploadedObject `json:"uploadeds"` +} +type UploadedObject struct { + Object *Object `json:"object"` + Error string `json:"error"` +} -func (c *ObjectService) Upload(req ObjectUploadReq) (*ObjectUploadResp, error) { +func (c *ObjectService) Upload(req ObjectUpload) (*ObjectUploadResp, error) { url, err := url.JoinPath(c.baseURL, ObjectUploadPath) if err != nil { return nil, err @@ -72,8 +78,9 @@ func (c *ObjectService) Upload(req ObjectUploadReq) (*ObjectUploadResp, error) { contType := resp.Header.Get("Content-Type") if strings.Contains(contType, myhttp.ContentTypeJSON) { + var err error var codeResp response[ObjectUploadResp] - if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { + if codeResp, err = serder.JSONToObjectStreamEx[response[ObjectUploadResp]](resp.Body); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } @@ -90,7 +97,7 @@ func (c *ObjectService) Upload(req ObjectUploadReq) (*ObjectUploadResp, error) { const ObjectDownloadPath = "/object/download" -type ObjectDownloadReq struct { +type ObjectDownload struct { UserID UserID `form:"userID" json:"userID" binding:"required"` ObjectID ObjectID `form:"objectID" json:"objectID" binding:"required"` } @@ -99,7 +106,7 @@ type DownloadingObject struct { File io.ReadCloser } -func (c *ObjectService) Download(req ObjectDownloadReq) (*DownloadingObject, error) { +func (c *ObjectService) Download(req ObjectDownload) (*DownloadingObject, error) { url, err := url.JoinPath(c.baseURL, ObjectDownloadPath) if err != nil { return nil, err @@ -123,10 +130,6 @@ func (c *ObjectService) Download(req ObjectDownloadReq) (*DownloadingObject, err return nil, codeResp.ToError() } - if !strings.Contains(contType, myhttp.ContentTypeMultiPart) { - return nil, fmt.Errorf("unknow response content type: %s", contType) - } - _, files, err := myhttp.ParseMultiPartResponse(resp) if err != nil { return nil, err @@ -157,7 +160,7 @@ func (u *UpdatingObject) ApplyTo(obj *Object) { obj.UpdateTime = u.UpdateTime } -type ObjectUpdateInfoReq struct { +type ObjectUpdateInfo struct { UserID UserID `json:"userID" binding:"required"` Updatings []UpdatingObject `json:"updatings" binding:"required"` } @@ -166,7 +169,7 @@ type ObjectUpdateInfoResp struct { Successes []ObjectID `json:"successes"` } -func (c *ObjectService) Update(req ObjectUpdateInfoReq) (*ObjectUpdateInfoResp, error) { +func (c *ObjectService) UpdateInfo(req ObjectUpdateInfo) (*ObjectUpdateInfoResp, error) { url, err := url.JoinPath(c.baseURL, ObjectUpdateInfoPath) if err != nil { return nil, err @@ -179,7 +182,7 @@ func (c *ObjectService) Update(req ObjectUpdateInfoReq) (*ObjectUpdateInfoResp, return nil, err } - jsonResp, err := myhttp.ParseJSONResponse[response[ObjectUpdateInfoResp]](resp) + jsonResp, err := ParseJSONResponse[response[ObjectUpdateInfoResp]](resp) if err != nil { return nil, err } @@ -204,7 +207,7 @@ func (m *MovingObject) ApplyTo(obj *Object) { obj.Path = m.Path } -type ObjectMoveReq struct { +type ObjectMove struct { UserID UserID `json:"userID" binding:"required"` Movings []MovingObject `json:"movings" binding:"required"` } @@ -213,7 +216,7 @@ type ObjectMoveResp struct { Successes []ObjectID `json:"successes"` } -func (c *ObjectService) Move(req ObjectMoveReq) (*ObjectMoveResp, error) { +func (c *ObjectService) Move(req ObjectMove) (*ObjectMoveResp, error) { url, err := url.JoinPath(c.baseURL, ObjectMovePath) if err != nil { return nil, err @@ -226,7 +229,7 @@ func (c *ObjectService) Move(req ObjectMoveReq) (*ObjectMoveResp, error) { return nil, err } - jsonResp, err := myhttp.ParseJSONResponse[response[ObjectMoveResp]](resp) + jsonResp, err := ParseJSONResponse[response[ObjectMoveResp]](resp) if err != nil { return nil, err } @@ -240,41 +243,41 @@ func (c *ObjectService) Move(req ObjectMoveReq) (*ObjectMoveResp, error) { const ObjectDeletePath = "/object/delete" -type ObjectDeleteReq struct { +type ObjectDelete struct { UserID UserID `json:"userID" binding:"required"` ObjectIDs []ObjectID `json:"objectIDs" binding:"required"` } type ObjectDeleteResp struct{} -func (c *ObjectService) Delete(req ObjectDeleteReq) (*ObjectDeleteResp, error) { +func (c *ObjectService) Delete(req ObjectDelete) error { url, err := url.JoinPath(c.baseURL, ObjectDeletePath) if err != nil { - return nil, err + return err } resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ Body: req, }) if err != nil { - return nil, err + return err } - jsonResp, err := myhttp.ParseJSONResponse[response[ObjectDeleteResp]](resp) + jsonResp, err := ParseJSONResponse[response[ObjectDeleteResp]](resp) if err != nil { - return nil, err + return err } if jsonResp.Code == errorcode.OK { - return &jsonResp.Data, nil + return nil } - return nil, jsonResp.ToError() + return jsonResp.ToError() } const ObjectGetPackageObjectsPath = "/object/getPackageObjects" -type ObjectGetPackageObjectsReq struct { +type ObjectGetPackageObjects struct { UserID UserID `form:"userID" json:"userID" binding:"required"` PackageID PackageID `form:"packageID" json:"packageID" binding:"required"` } @@ -282,7 +285,7 @@ type ObjectGetPackageObjectsResp struct { Objects []Object `json:"objects"` } -func (c *ObjectService) GetPackageObjects(req ObjectGetPackageObjectsReq) (*ObjectGetPackageObjectsResp, error) { +func (c *ObjectService) GetPackageObjects(req ObjectGetPackageObjects) (*ObjectGetPackageObjectsResp, error) { url, err := url.JoinPath(c.baseURL, ObjectGetPackageObjectsPath) if err != nil { return nil, err @@ -295,7 +298,7 @@ func (c *ObjectService) GetPackageObjects(req ObjectGetPackageObjectsReq) (*Obje return nil, err } - jsonResp, err := myhttp.ParseJSONResponse[response[ObjectGetPackageObjectsResp]](resp) + jsonResp, err := ParseJSONResponse[response[ObjectGetPackageObjectsResp]](resp) if err != nil { return nil, err } diff --git a/sdks/storage/package.go b/sdks/storage/package.go index 988030c..6655e48 100644 --- a/sdks/storage/package.go +++ b/sdks/storage/package.go @@ -41,7 +41,43 @@ func (c *PackageService) Get(req PackageGetReq) (*PackageGetResp, error) { return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[PackageGetResp]](resp) + codeResp, err := ParseJSONResponse[response[PackageGetResp]](resp) + if err != nil { + return nil, err + } + + if codeResp.Code == errorcode.OK { + return &codeResp.Data, nil + } + + return nil, codeResp.ToError() +} + +const PackageGetByNamePath = "/package/getByName" + +type PackageGetByName struct { + UserID UserID `form:"userID" json:"userID" binding:"required"` + BucketName string `form:"bucketName" json:"bucketName" binding:"required"` + PackageName string `form:"packageName" json:"packageName" binding:"required"` +} +type PackageGetByNameResp struct { + Package Package `json:"package"` +} + +func (c *PackageService) GetByName(req PackageGetByName) (*PackageGetByNameResp, error) { + url, err := url.JoinPath(c.baseURL, PackageGetByNamePath) + if err != nil { + return nil, err + } + + resp, err := myhttp.GetForm(url, myhttp.RequestParam{ + Query: req, + }) + if err != nil { + return nil, err + } + + codeResp, err := ParseJSONResponse[response[PackageGetByNameResp]](resp) if err != nil { return nil, err } @@ -55,17 +91,17 @@ func (c *PackageService) Get(req PackageGetReq) (*PackageGetResp, error) { const PackageCreatePath = "/package/create" -type PackageCreateReq struct { +type PackageCreate struct { UserID UserID `json:"userID"` BucketID BucketID `json:"bucketID"` Name string `json:"name"` } type PackageCreateResp struct { - PackageID PackageID `json:"packageID,string"` + Package Package `json:"package"` } -func (s *PackageService) Create(req PackageCreateReq) (*PackageCreateResp, error) { +func (s *PackageService) Create(req PackageCreate) (*PackageCreateResp, error) { url, err := url.JoinPath(s.baseURL, PackageCreatePath) if err != nil { return nil, err @@ -78,7 +114,7 @@ func (s *PackageService) Create(req PackageCreateReq) (*PackageCreateResp, error return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[PackageCreateResp]](resp) + codeResp, err := ParseJSONResponse[response[PackageCreateResp]](resp) if err != nil { return nil, err } @@ -92,12 +128,12 @@ func (s *PackageService) Create(req PackageCreateReq) (*PackageCreateResp, error const PackageDeletePath = "/package/delete" -type PackageDeleteReq struct { +type PackageDelete struct { UserID UserID `json:"userID" binding:"required"` PackageID PackageID `json:"packageID" binding:"required"` } -func (c *PackageService) Delete(req PackageDeleteReq) error { +func (c *PackageService) Delete(req PackageDelete) error { url, err := url.JoinPath(c.baseURL, PackageDeletePath) if err != nil { return err @@ -130,7 +166,7 @@ func (c *PackageService) Delete(req PackageDeleteReq) error { const PackageListBucketPackagesPath = "/package/listBucketPackages" -type PackageListBucketPackagesReq struct { +type PackageListBucketPackages struct { UserID UserID `form:"userID" json:"userID" binding:"required"` BucketID BucketID `form:"bucketID" json:"bucketID" binding:"required"` } @@ -139,7 +175,7 @@ type PackageListBucketPackagesResp struct { Packages []Package `json:"packages"` } -func (c *PackageService) ListBucketPackages(req PackageListBucketPackagesReq) (*PackageListBucketPackagesResp, error) { +func (c *PackageService) ListBucketPackages(req PackageListBucketPackages) (*PackageListBucketPackagesResp, error) { url, err := url.JoinPath(c.baseURL, PackageListBucketPackagesPath) if err != nil { return nil, err @@ -152,7 +188,7 @@ func (c *PackageService) ListBucketPackages(req PackageListBucketPackagesReq) (* return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[PackageListBucketPackagesResp]](resp) + codeResp, err := ParseJSONResponse[response[PackageListBucketPackagesResp]](resp) if err != nil { return nil, err } @@ -187,7 +223,7 @@ func (c *PackageService) GetCachedNodes(req PackageGetCachedNodesReq) (*PackageG return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[PackageGetCachedNodesResp]](resp) + codeResp, err := ParseJSONResponse[response[PackageGetCachedNodesResp]](resp) if err != nil { return nil, err } @@ -222,7 +258,7 @@ func (c *PackageService) GetLoadedNodes(req PackageGetLoadedNodesReq) (*PackageG return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[PackageGetLoadedNodesResp]](resp) + codeResp, err := ParseJSONResponse[response[PackageGetLoadedNodesResp]](resp) if err != nil { return nil, err } diff --git a/sdks/storage/storage.go b/sdks/storage/storage.go index 827d06e..92f63ef 100644 --- a/sdks/storage/storage.go +++ b/sdks/storage/storage.go @@ -32,7 +32,7 @@ func (c *Client) StorageLoadPackage(req StorageLoadPackageReq) (*StorageLoadPack return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[StorageLoadPackageResp]](resp) + codeResp, err := ParseJSONResponse[response[StorageLoadPackageResp]](resp) if err != nil { return nil, err } @@ -109,7 +109,7 @@ func (c *Client) StorageGetInfo(req StorageGetInfoReq) (*StorageGetInfoResp, err return nil, err } - codeResp, err := myhttp.ParseJSONResponse[response[StorageGetInfoResp]](resp) + codeResp, err := ParseJSONResponse[response[StorageGetInfoResp]](resp) if err != nil { return nil, err } diff --git a/sdks/storage/storage_test.go b/sdks/storage/storage_test.go index 0527fbe..a5a7d6c 100644 --- a/sdks/storage/storage_test.go +++ b/sdks/storage/storage_test.go @@ -23,21 +23,21 @@ func Test_PackageGet(t *testing.T) { } pkgName := uuid.NewString() - createResp, err := cli.Package().Create(PackageCreateReq{ + createResp, err := cli.Package().Create(PackageCreate{ UserID: 1, BucketID: 1, Name: pkgName, }) So(err, ShouldBeNil) - _, err = cli.Object().Upload(ObjectUploadReq{ + _, err = cli.Object().Upload(ObjectUpload{ ObjectUploadInfo: ObjectUploadInfo{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }, Files: iterator.Array( &UploadingObject{ - Path: "test", + Path: "abc/test", File: io.NopCloser(bytes.NewBuffer(fileData)), }, &UploadingObject{ @@ -50,16 +50,16 @@ func Test_PackageGet(t *testing.T) { getResp, err := cli.Package().Get(PackageGetReq{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }) So(err, ShouldBeNil) - So(getResp.PackageID, ShouldEqual, createResp.PackageID) + So(getResp.PackageID, ShouldEqual, createResp.Package.PackageID) So(getResp.Package.Name, ShouldEqual, pkgName) - err = cli.Package().Delete(PackageDeleteReq{ + err = cli.Package().Delete(PackageDelete{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }) So(err, ShouldBeNil) }) @@ -79,17 +79,17 @@ func Test_Object(t *testing.T) { nodeAff := NodeID(2) pkgName := uuid.NewString() - createResp, err := cli.Package().Create(PackageCreateReq{ + createResp, err := cli.Package().Create(PackageCreate{ UserID: 1, BucketID: 1, Name: pkgName, }) So(err, ShouldBeNil) - _, err = cli.Object().Upload(ObjectUploadReq{ + _, err = cli.Object().Upload(ObjectUpload{ ObjectUploadInfo: ObjectUploadInfo{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, NodeAffinity: &nodeAff, }, Files: iterator.Array( @@ -116,9 +116,9 @@ func Test_Object(t *testing.T) { // So(downFileData, ShouldResemble, fileData) // downFs.Close() - err = cli.Package().Delete(PackageDeleteReq{ + err = cli.Package().Delete(PackageDelete{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }) So(err, ShouldBeNil) }) @@ -136,17 +136,17 @@ func Test_Storage(t *testing.T) { } pkgName := uuid.NewString() - createResp, err := cli.Package().Create(PackageCreateReq{ + createResp, err := cli.Package().Create(PackageCreate{ UserID: 1, BucketID: 1, Name: pkgName, }) So(err, ShouldBeNil) - _, err = cli.Object().Upload(ObjectUploadReq{ + _, err = cli.Object().Upload(ObjectUpload{ ObjectUploadInfo: ObjectUploadInfo{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }, Files: iterator.Array( &UploadingObject{ @@ -163,14 +163,14 @@ func Test_Storage(t *testing.T) { _, err = cli.StorageLoadPackage(StorageLoadPackageReq{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, StorageID: 1, }) So(err, ShouldBeNil) - err = cli.Package().Delete(PackageDeleteReq{ + err = cli.Package().Delete(PackageDelete{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }) So(err, ShouldBeNil) }) @@ -188,17 +188,17 @@ func Test_Cache(t *testing.T) { } pkgName := uuid.NewString() - createResp, err := cli.Package().Create(PackageCreateReq{ + createResp, err := cli.Package().Create(PackageCreate{ UserID: 1, BucketID: 1, Name: pkgName, }) So(err, ShouldBeNil) - _, err = cli.Object().Upload(ObjectUploadReq{ + _, err = cli.Object().Upload(ObjectUpload{ ObjectUploadInfo: ObjectUploadInfo{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }, Files: iterator.Array( &UploadingObject{ @@ -215,14 +215,14 @@ func Test_Cache(t *testing.T) { _, err = cli.CacheMovePackage(CacheMovePackageReq{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, NodeID: 1, }) So(err, ShouldBeNil) - err = cli.Package().Delete(PackageDeleteReq{ + err = cli.Package().Delete(PackageDelete{ UserID: 1, - PackageID: createResp.PackageID, + PackageID: createResp.Package.PackageID, }) So(err, ShouldBeNil) }) diff --git a/sdks/storage/utils.go b/sdks/storage/utils.go index 89cb5a2..fdbf25b 100644 --- a/sdks/storage/utils.go +++ b/sdks/storage/utils.go @@ -1,7 +1,38 @@ package cdssdk -import "path/filepath" +import ( + "fmt" + "io" + "net/http" + "path/filepath" + "strings" + + myhttp "gitlink.org.cn/cloudream/common/utils/http" + "gitlink.org.cn/cloudream/common/utils/math" + "gitlink.org.cn/cloudream/common/utils/serder" +) func MakeIPFSFilePath(fileHash string) string { return filepath.Join("ipfs", fileHash) } + +func ParseJSONResponse[TBody any](resp *http.Response) (TBody, error) { + var ret TBody + contType := resp.Header.Get("Content-Type") + if strings.Contains(contType, myhttp.ContentTypeJSON) { + var err error + if ret, err = serder.JSONToObjectStreamEx[TBody](resp.Body); err != nil { + return ret, fmt.Errorf("parsing response: %w", err) + } + + return ret, nil + } + + cont, err := io.ReadAll(resp.Body) + if err != nil { + return ret, fmt.Errorf("unknow response content type: %s, status: %d", contType, resp.StatusCode) + } + strCont := string(cont) + + return ret, fmt.Errorf("unknow response content type: %s, status: %d, body(prefix): %s", contType, resp.StatusCode, strCont[:math.Min(len(strCont), 200)]) +} diff --git a/utils/http/http.go b/utils/http/http.go index bab12e6..94f5241 100644 --- a/utils/http/http.go +++ b/utils/http/http.go @@ -133,8 +133,9 @@ func ParseJSONResponse[TBody any](resp *http.Response) (TBody, error) { } type MultiPartFile struct { - FileName string - File io.ReadCloser + FieldName string + FileName string + File io.ReadCloser } type multiPartFileIterator struct { @@ -146,9 +147,16 @@ func (m *multiPartFileIterator) MoveNext() (*MultiPartFile, error) { if m.firstFile != nil { f := m.firstFile m.firstFile = nil + + fileName, err := ul.PathUnescape(f.FileName()) + if err != nil { + return nil, fmt.Errorf("unescape file name: %w", err) + } + return &MultiPartFile{ - FileName: f.FileName(), - File: f, + FieldName: f.FormName(), + FileName: fileName, + File: f, }, nil } @@ -161,10 +169,16 @@ func (m *multiPartFileIterator) MoveNext() (*MultiPartFile, error) { return nil, err } + fileName, err := ul.PathUnescape(part.FileName()) + if err != nil { + return nil, fmt.Errorf("unescape file name: %w", err) + } + if part.FileName() != "" { return &MultiPartFile{ - FileName: part.FileName(), - File: part, + FieldName: part.FormName(), + FileName: fileName, + File: part, }, nil } } @@ -292,7 +306,7 @@ func PostMultiPart(url string, param MultiPartRequestParam) (*http.Response, err err = func() error { defer file.File.Close() - w, err := muWriter.CreateFormFile(file.FieldName, file.FileName) + w, err := muWriter.CreateFormFile(file.FieldName, ul.PathEscape(file.FileName)) if err != nil { return fmt.Errorf("create form file failed, err: %w", err) } diff --git a/utils/serder/serder.go b/utils/serder/serder.go index 911e8ae..e8ded8c 100644 --- a/utils/serder/serder.go +++ b/utils/serder/serder.go @@ -53,6 +53,18 @@ func JSONToObjectEx[T any](data []byte) (T, error) { return ret, nil } +// 将JSON字符串转为对象。支持TypeUnion。 +func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) { + var ret T + dec := defaultAPI.NewDecoder(stream) + err := dec.Decode(&ret) + if err != nil { + return ret, err + } + + return ret, nil +} + // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。 func ObjectToJSON(obj any) ([]byte, error) { return json.Marshal(obj)