|
- package api
-
- import (
- "context"
- "fmt"
- "io"
- "mime"
- "net/http"
- "net/url"
- "strings"
- "time"
-
- v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
- "github.com/aws/aws-sdk-go-v2/credentials"
- "gitlink.org.cn/cloudream/common/consts/errorcode"
- "gitlink.org.cn/cloudream/common/pkgs/iterator"
- "gitlink.org.cn/cloudream/common/sdks"
- "gitlink.org.cn/cloudream/common/utils/http2"
- "gitlink.org.cn/cloudream/common/utils/serder"
- "gitlink.org.cn/cloudream/storage2/client/types"
- )
-
- type ObjectService struct {
- *Client
- }
-
- func (c *Client) Object() *ObjectService {
- return &ObjectService{
- Client: c,
- }
- }
-
- const ObjectListPathByPath = "/object/listByPath"
-
- type ObjectListByPath struct {
- PackageID types.PackageID `form:"packageID" binding:"required" url:"packageID" json:"packageID"`
- Path string `form:"path" url:"path" json:"path"` // 允许为空字符串
- IsPrefix bool `form:"isPrefix" url:"isPrefix" json:"isPrefix"`
- NoRecursive bool `form:"noRecursive" url:"noRecursive" json:"noRecursive"` // 仅当isPrefix为true时有效,表示仅查询直接属于Prefix下的对象,对于更深的对象,返回它们的公共前缀
- MaxKeys int `form:"maxKeys" url:"maxKeys" json:"maxKeys"`
- ContinuationToken string `form:"continuationToken" url:"continuationToken" json:"continuationToken"` // 用于分页,如果为空字符串,表示从头开始
- }
-
- func (r *ObjectListByPath) MakeParam() *sdks.RequestParam {
- return sdks.MakeQueryParam(http.MethodGet, ObjectListPathByPath, r)
- }
-
- type ObjectListByPathResp struct {
- CommonPrefixes []string `json:"commonPrefixes"` // 仅在IsPrefix为true且NoRecursive为true时有效,包含更深层对象的shared prefix
- Objects []types.Object `json:"objects"` // 如果IsPrefix为true且NoRecursive为false,则返回所有匹配的对象,否则只返回直接属于Prefix下的对象
- IsTruncated bool `json:"isTruncated"` // 是否还有更多对象
- NextContinuationToken string `json:"nextContinuationToken"` // 用于分页,如果IsTruncated为true,则下次请求的ContinuationToken为该值
- }
-
- func (r *ObjectListByPathResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) ListByPath(req ObjectListByPath) (*ObjectListByPathResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectListByPathResp{})
- }
-
- const ObjectListByIDsPath = "/object/listByIDs"
-
- type ObjectListByIDs struct {
- ObjectIDs []types.ObjectID `form:"objectIDs" binding:"required" url:"objectIDs"`
- }
-
- func (r *ObjectListByIDs) MakeParam() *sdks.RequestParam {
- return sdks.MakeQueryParam(http.MethodGet, ObjectListByIDsPath, r)
- }
-
- type ObjectListByIDsResp struct {
- Objects []*types.Object `json:"object"` // 与ObjectIDs一一对应,如果某个ID不存在,则对应位置为nil
- }
-
- func (r *ObjectListByIDsResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) ListByIDs(req ObjectListByIDs) (*ObjectListByIDsResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectListByIDsResp{})
- }
-
- const ObjectUploadPath = "/object/upload"
-
- type ObjectUpload struct {
- ObjectUploadInfo
- Files UploadObjectIterator `json:"-"`
- }
-
- type ObjectUploadInfo struct {
- PackageID types.PackageID `json:"packageID" binding:"required"`
- Affinity types.UserSpaceID `json:"affinity"`
- LoadTo []types.UserSpaceID `json:"loadTo"`
- LoadToPath []string `json:"loadToPath"`
- }
-
- type UploadingObject struct {
- Path string
- File io.ReadCloser
- }
-
- type UploadObjectIterator = iterator.Iterator[*UploadingObject]
-
- type ObjectUploadResp struct {
- Uploadeds []types.Object `json:"uploadeds"`
- }
-
- func (c *ObjectService) Upload(req ObjectUpload) (*ObjectUploadResp, error) {
- type uploadInfo struct {
- Info string `url:"info"`
- }
-
- url, err := url.JoinPath(c.cfg.URL, ObjectUploadPath)
- if err != nil {
- return nil, err
- }
-
- infoJSON, err := serder.ObjectToJSON(req)
- if err != nil {
- return nil, fmt.Errorf("upload info to json: %w", err)
- }
-
- resp, err := PostMultiPart(c.cfg, url,
- uploadInfo{Info: string(infoJSON)},
- iterator.Map(req.Files, func(src *UploadingObject) (*http2.IterMultiPartFile, error) {
- return &http2.IterMultiPartFile{
- FieldName: "files",
- FileName: src.Path,
- File: src.File,
- }, nil
- }))
- if err != nil {
- return nil, err
- }
-
- contType := resp.Header.Get("Content-Type")
- if strings.Contains(contType, http2.ContentTypeJSON) {
- var err error
- var codeResp response[ObjectUploadResp]
- if codeResp, err = serder.JSONToObjectStreamEx[response[ObjectUploadResp]](resp.Body); err != nil {
- return nil, fmt.Errorf("parsing response: %w", err)
- }
-
- if codeResp.Code == errorcode.OK {
- return &codeResp.Data, nil
- }
-
- return nil, codeResp.ToError()
- }
-
- return nil, fmt.Errorf("unknow response content type: %s", contType)
-
- }
-
- const ObjectDownloadPath = "/object/download"
-
- type ObjectDownload struct {
- ObjectID types.ObjectID `form:"objectID" url:"objectID" binding:"required"`
- Offset int64 `form:"offset" url:"offset,omitempty"`
- Length *int64 `form:"length" url:"length,omitempty"`
- }
-
- func (r *ObjectDownload) MakeParam() *sdks.RequestParam {
- return sdks.MakeQueryParam(http.MethodGet, ObjectDownloadPath, r)
- }
-
- type DownloadingObject struct {
- Path string
- File io.ReadCloser
- }
-
- func (c *ObjectService) Download(req ObjectDownload) (*DownloadingObject, error) {
- httpReq, err := req.MakeParam().MakeRequest(c.cfg.URL)
- if err != nil {
- return nil, err
- }
-
- if c.cfg.AccessKey != "" && c.cfg.SecretKey != "" {
- prod := credentials.NewStaticCredentialsProvider(c.cfg.AccessKey, c.cfg.SecretKey, "")
- cred, err := prod.Retrieve(context.TODO())
- if err != nil {
- return nil, err
- }
-
- signer := v4.NewSigner()
- err = signer.SignHTTP(context.Background(), cred, httpReq, "", AuthService, AuthRegion, time.Now())
- if err != nil {
- return nil, err
- }
- }
-
- resp, err := http.DefaultClient.Do(httpReq)
- if err != nil {
- return nil, err
- }
-
- contType := resp.Header.Get("Content-Type")
-
- if strings.Contains(contType, http2.ContentTypeJSON) {
- var codeResp response[any]
- if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil {
- return nil, fmt.Errorf("parsing response: %w", err)
- }
-
- return nil, codeResp.ToError()
- }
-
- _, params, err := mime.ParseMediaType(resp.Header.Get("Content-Disposition"))
- if err != nil {
- return nil, fmt.Errorf("parsing content disposition: %w", err)
- }
-
- return &DownloadingObject{
- Path: params["filename"],
- File: resp.Body,
- }, nil
- }
-
- const ObjectDownloadByPathPath = "/object/downloadByPath"
-
- type ObjectDownloadByPath struct {
- PackageID types.PackageID `form:"packageID" url:"packageID" binding:"required"`
- Path string `form:"path" url:"path" binding:"required"`
- Offset int64 `form:"offset" url:"offset,omitempty"`
- Length *int64 `form:"length" url:"length,omitempty"`
- }
-
- func (r *ObjectDownloadByPath) MakeParam() *sdks.RequestParam {
- return sdks.MakeQueryParam(http.MethodGet, ObjectDownloadByPathPath, r)
- }
-
- func (c *ObjectService) DownloadByPath(req ObjectDownloadByPath) (*DownloadingObject, error) {
- httpReq, err := req.MakeParam().MakeRequest(c.cfg.URL)
- if err != nil {
- return nil, err
- }
-
- if c.cfg.AccessKey != "" && c.cfg.SecretKey != "" {
- prod := credentials.NewStaticCredentialsProvider(c.cfg.AccessKey, c.cfg.SecretKey, "")
- cred, err := prod.Retrieve(context.TODO())
- if err != nil {
- return nil, err
- }
-
- signer := v4.NewSigner()
- err = signer.SignHTTP(context.Background(), cred, httpReq, "", AuthService, AuthRegion, time.Now())
- if err != nil {
- return nil, err
- }
- }
-
- resp, err := http.DefaultClient.Do(httpReq)
- if err != nil {
- return nil, err
- }
-
- contType := resp.Header.Get("Content-Type")
-
- if strings.Contains(contType, http2.ContentTypeJSON) {
- var codeResp response[any]
- if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil {
- return nil, fmt.Errorf("parsing response: %w", err)
- }
-
- return nil, codeResp.ToError()
- }
-
- _, params, err := mime.ParseMediaType(resp.Header.Get("Content-Disposition"))
- if err != nil {
- return nil, fmt.Errorf("parsing content disposition: %w", err)
- }
-
- return &DownloadingObject{
- Path: params["filename"],
- File: resp.Body,
- }, nil
- }
-
- const ObjectUpdateInfoPath = "/object/updateInfo"
-
- type UpdatingObject struct {
- ObjectID types.ObjectID `json:"objectID" binding:"required"`
- UpdateTime time.Time `json:"updateTime" binding:"required"`
- }
-
- func (u *UpdatingObject) ApplyTo(obj *types.Object) {
- obj.UpdateTime = u.UpdateTime
- }
-
- type ObjectUpdateInfo struct {
- Updatings []UpdatingObject `json:"updatings" binding:"required"`
- }
-
- func (r *ObjectUpdateInfo) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectUpdateInfoPath, r)
- }
-
- type ObjectUpdateInfoResp struct {
- Successes []types.ObjectID `json:"successes"`
- }
-
- func (r *ObjectUpdateInfoResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) UpdateInfo(req ObjectUpdateInfo) (*ObjectUpdateInfoResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectUpdateInfoResp{})
- }
-
- const ObjectUpdateInfoByPathPath = "/object/updateInfoByPath"
-
- type ObjectUpdateInfoByPath struct {
- PackageID types.PackageID `json:"packageID" binding:"required"`
- Path string `json:"path" binding:"required"`
- UpdateTime time.Time `json:"updateTime" binding:"required"`
- }
-
- func (r *ObjectUpdateInfoByPath) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectUpdateInfoByPathPath, r)
- }
-
- type ObjectUpdateInfoByPathResp struct{}
-
- func (r *ObjectUpdateInfoByPathResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) UpdateInfoByPath(req ObjectUpdateInfoByPath) (*ObjectUpdateInfoByPathResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectUpdateInfoByPathResp{})
- }
-
- const ObjectMovePath = "/object/move"
-
- type MovingObject struct {
- ObjectID types.ObjectID `json:"objectID" binding:"required"`
- PackageID types.PackageID `json:"packageID" binding:"required"`
- Path string `json:"path" binding:"required"`
- }
-
- func (m *MovingObject) ApplyTo(obj *types.Object) {
- obj.PackageID = m.PackageID
- obj.Path = m.Path
- }
-
- type ObjectMove struct {
- Movings []MovingObject `json:"movings" binding:"required"`
- }
-
- func (r *ObjectMove) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectMovePath, r)
- }
-
- type ObjectMoveResp struct {
- Successes []types.ObjectID `json:"successes"`
- }
-
- func (r *ObjectMoveResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) Move(req ObjectMove) (*ObjectMoveResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectMoveResp{})
- }
-
- const ObjectDeletePath = "/object/delete"
-
- type ObjectDelete struct {
- ObjectIDs []types.ObjectID `json:"objectIDs" binding:"required"`
- }
-
- func (r *ObjectDelete) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectDeletePath, r)
- }
-
- type ObjectDeleteResp struct{}
-
- func (r *ObjectDeleteResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) Delete(req ObjectDelete) error {
- return JSONAPINoData(c.cfg, http.DefaultClient, &req)
- }
-
- const ObjectDeleteByPathPath = "/object/deleteByPath"
-
- type ObjectDeleteByPath struct {
- PackageID types.PackageID `json:"packageID" binding:"required"`
- Path string `json:"path" binding:"required"`
- }
-
- func (r *ObjectDeleteByPath) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectDeleteByPathPath, r)
- }
-
- type ObjectDeleteByPathResp struct{}
-
- func (r *ObjectDeleteByPathResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) DeleteByPath(req ObjectDeleteByPath) error {
- return JSONAPINoData(c.cfg, http.DefaultClient, &req)
- }
-
- const ObjectClonePath = "/object/clone"
-
- type ObjectClone struct {
- Clonings []CloningObject `json:"clonings" binding:"required"`
- }
-
- func (r *ObjectClone) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectClonePath, r)
- }
-
- type CloningObject struct {
- ObjectID types.ObjectID `json:"objectID" binding:"required"`
- NewPath string `json:"newPath" binding:"required"`
- NewPackageID types.PackageID `json:"newPackageID" binding:"required"`
- }
-
- type ObjectCloneResp struct {
- Objects []*types.Object `json:"objects"`
- }
-
- func (r *ObjectCloneResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) Clone(req ObjectClone) (*ObjectCloneResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectCloneResp{})
- }
-
- const ObjectGetPackageObjectsPath = "/object/getPackageObjects"
-
- type ObjectGetPackageObjects struct {
- PackageID types.PackageID `form:"packageID" url:"packageID" binding:"required"`
- }
-
- func (r *ObjectGetPackageObjects) MakeParam() *sdks.RequestParam {
- return sdks.MakeQueryParam(http.MethodGet, ObjectGetPackageObjectsPath, r)
- }
-
- type ObjectGetPackageObjectsResp struct {
- Objects []types.Object `json:"objects"`
- }
-
- func (r *ObjectGetPackageObjectsResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) GetPackageObjects(req ObjectGetPackageObjects) (*ObjectGetPackageObjectsResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectGetPackageObjectsResp{})
- }
-
- const ObjectNewMultipartUploadPath = "/v1/object/newMultipartUpload"
-
- type ObjectNewMultipartUpload struct {
- PackageID types.PackageID `json:"packageID" binding:"required"`
- Path string `json:"path" binding:"required"`
- }
-
- func (r *ObjectNewMultipartUpload) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectNewMultipartUploadPath, r)
- }
-
- type ObjectNewMultipartUploadResp struct {
- Object types.Object `json:"object"`
- }
-
- func (r *ObjectNewMultipartUploadResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) NewMultipartUpload(req ObjectNewMultipartUpload) (*ObjectNewMultipartUploadResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectNewMultipartUploadResp{})
- }
-
- const ObjectUploadPartPath = "/v1/object/uploadPart"
-
- type ObjectUploadPart struct {
- ObjectUploadPartInfo
- File io.ReadCloser `json:"-"`
- }
-
- type ObjectUploadPartInfo struct {
- ObjectID types.ObjectID `json:"objectID" binding:"required"`
- Index int `json:"index"`
- }
-
- type ObjectUploadPartResp struct{}
-
- func (c *ObjectService) UploadPart(req ObjectUploadPart) (*ObjectUploadPartResp, error) {
- url, err := url.JoinPath(c.cfg.URL, ObjectUploadPartPath)
- if err != nil {
- return nil, err
- }
-
- infoJSON, err := serder.ObjectToJSON(req)
- if err != nil {
- return nil, fmt.Errorf("upload info to json: %w", err)
- }
-
- resp, err := http2.PostMultiPart(url, http2.MultiPartRequestParam{
- Form: map[string]string{"info": string(infoJSON)},
- Files: iterator.Array(&http2.IterMultiPartFile{
- FieldName: "file",
- File: req.File,
- }),
- })
- if err != nil {
- return nil, err
- }
-
- contType := resp.Header.Get("Content-Type")
- if strings.Contains(contType, http2.ContentTypeJSON) {
- var err error
- var codeResp response[ObjectUploadPartResp]
- if codeResp, err = serder.JSONToObjectStreamEx[response[ObjectUploadPartResp]](resp.Body); err != nil {
- return nil, fmt.Errorf("parsing response: %w", err)
- }
-
- if codeResp.Code == errorcode.OK {
- return &codeResp.Data, nil
- }
-
- return nil, codeResp.ToError()
- }
-
- return nil, fmt.Errorf("unknow response content type: %s", contType)
- }
-
- const ObjectCompleteMultipartUploadPath = "/v1/object/completeMultipartUpload"
-
- type ObjectCompleteMultipartUpload struct {
- ObjectID types.ObjectID `json:"objectID" binding:"required"`
- Indexes []int `json:"indexes" binding:"required"`
- }
-
- func (r *ObjectCompleteMultipartUpload) MakeParam() *sdks.RequestParam {
- return sdks.MakeJSONParam(http.MethodPost, ObjectCompleteMultipartUploadPath, r)
- }
-
- type ObjectCompleteMultipartUploadResp struct {
- Object types.Object `json:"object"`
- }
-
- func (r *ObjectCompleteMultipartUploadResp) ParseResponse(resp *http.Response) error {
- return sdks.ParseCodeDataJSONResponse(resp, r)
- }
-
- func (c *ObjectService) CompleteMultipartUpload(req ObjectCompleteMultipartUpload) (*ObjectCompleteMultipartUploadResp, error) {
- return JSONAPI(c.cfg, http.DefaultClient, &req, &ObjectCompleteMultipartUploadResp{})
- }
|