JCS-pub/client/sdk/api/v1/object.go

534 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package api
import (
"fmt"
"io"
"mime"
"net/http"
"net/url"
"strings"
"time"
"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"
jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
)
type ObjectService struct {
*Client
}
func (c *Client) Object() *ObjectService {
return &ObjectService{
Client: c,
}
}
const ObjectListPathByPath = "/object/listByPath"
type ObjectListByPath struct {
PackageID jcstypes.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 []jcstypes.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, c.httpCli, &req, &ObjectListByPathResp{})
}
const ObjectListByIDsPath = "/object/listByIDs"
type ObjectListByIDs struct {
ObjectIDs []jcstypes.ObjectID `form:"objectIDs" binding:"required" url:"objectIDs"`
}
func (r *ObjectListByIDs) MakeParam() *sdks.RequestParam {
return sdks.MakeQueryParam(http.MethodGet, ObjectListByIDsPath, r)
}
type ObjectListByIDsResp struct {
Objects []*jcstypes.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, c.httpCli, &req, &ObjectListByIDsResp{})
}
const ObjectUploadPath = "/object/upload"
type ObjectUpload struct {
Info ObjectUploadInfo
Files UploadObjectIterator `json:"-"`
}
type ObjectUploadInfo struct {
PackageID jcstypes.PackageID `json:"packageID" binding:"required"`
Affinity jcstypes.UserSpaceID `json:"affinity"`
CopyTo []jcstypes.UserSpaceID `json:"copyTo"`
CopyToPath []string `json:"copyToPath"`
}
type UploadingObject struct {
Path string
File io.ReadCloser
}
type UploadObjectIterator = iterator.Iterator[*UploadingObject]
type ObjectUploadResp struct {
Uploadeds []jcstypes.Object `json:"uploadeds"`
}
func (c *ObjectService) Upload(req ObjectUpload) (*ObjectUploadResp, error) {
type uploadInfo struct {
Info string `url:"info"`
}
url, err := url.JoinPath(c.cfg.EndPoint, "v1", ObjectUploadPath)
if err != nil {
return nil, err
}
infoJSON, err := serder.ObjectToJSON(req.Info)
if err != nil {
return nil, fmt.Errorf("upload info to json: %w", err)
}
resp, err := PostMultiPart(&c.cfg, c.httpCli, 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 jcstypes.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) {
u, err := url.JoinPath(c.cfg.EndPoint, "v1")
if err != nil {
return nil, err
}
httpReq, err := req.MakeParam().MakeRequest(u)
if err != nil {
return nil, err
}
resp, err := c.httpCli.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 jcstypes.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) {
u, err := url.JoinPath(c.cfg.EndPoint, "v1")
if err != nil {
return nil, err
}
httpReq, err := req.MakeParam().MakeRequest(u)
if err != nil {
return nil, err
}
resp, err := c.httpCli.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 jcstypes.ObjectID `json:"objectID" binding:"required"`
UpdateTime time.Time `json:"updateTime" binding:"required"`
}
func (u *UpdatingObject) ApplyTo(obj *jcstypes.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 []jcstypes.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, c.httpCli, &req, &ObjectUpdateInfoResp{})
}
const ObjectUpdateInfoByPathPath = "/object/updateInfoByPath"
type ObjectUpdateInfoByPath struct {
PackageID jcstypes.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, c.httpCli, &req, &ObjectUpdateInfoByPathResp{})
}
const ObjectMovePath = "/object/move"
type MovingObject struct {
ObjectID jcstypes.ObjectID `json:"objectID" binding:"required"`
PackageID jcstypes.PackageID `json:"packageID" binding:"required"`
Path string `json:"path" binding:"required"`
}
func (m *MovingObject) ApplyTo(obj *jcstypes.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 []jcstypes.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, c.httpCli, &req, &ObjectMoveResp{})
}
const ObjectDeletePath = "/object/delete"
type ObjectDelete struct {
ObjectIDs []jcstypes.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, c.httpCli, &req)
}
const ObjectDeleteByPathPath = "/object/deleteByPath"
type ObjectDeleteByPath struct {
PackageID jcstypes.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, c.httpCli, &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 jcstypes.ObjectID `json:"objectID" binding:"required"`
NewPath string `json:"newPath" binding:"required"`
NewPackageID jcstypes.PackageID `json:"newPackageID" binding:"required"`
}
type ObjectCloneResp struct {
Objects []*jcstypes.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, c.httpCli, &req, &ObjectCloneResp{})
}
const ObjectGetPackageObjectsPath = "/object/getPackageObjects"
type ObjectGetPackageObjects struct {
PackageID jcstypes.PackageID `form:"packageID" url:"packageID" binding:"required"`
}
func (r *ObjectGetPackageObjects) MakeParam() *sdks.RequestParam {
return sdks.MakeQueryParam(http.MethodGet, ObjectGetPackageObjectsPath, r)
}
type ObjectGetPackageObjectsResp struct {
Objects []jcstypes.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, c.httpCli, &req, &ObjectGetPackageObjectsResp{})
}
const ObjectNewMultipartUploadPath = "/object/newMultipartUpload"
type ObjectNewMultipartUpload struct {
PackageID jcstypes.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 jcstypes.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, c.httpCli, &req, &ObjectNewMultipartUploadResp{})
}
const ObjectUploadPartPath = "/object/uploadPart"
type ObjectUploadPart struct {
ObjectUploadPartInfo
File io.ReadCloser `json:"-"`
}
type ObjectUploadPartInfo struct {
ObjectID jcstypes.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.EndPoint, 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 = "/object/completeMultipartUpload"
type ObjectCompleteMultipartUpload struct {
ObjectID jcstypes.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 jcstypes.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, c.httpCli, &req, &ObjectCompleteMultipartUploadResp{})
}