Browse Source

上传和下载接口支持鉴权

feature_gxh
Sydonian 8 months ago
parent
commit
510fe885e4
3 changed files with 174 additions and 29 deletions
  1. +57
    -22
      sdks/storage/cdsapi/object.go
  2. +4
    -5
      sdks/storage/cdsapi/package.go
  3. +113
    -2
      sdks/storage/cdsapi/utils.go

+ 57
- 22
sdks/storage/cdsapi/object.go View File

@@ -1,6 +1,7 @@
package cdsapi

import (
"context"
"fmt"
"io"
"mime"
@@ -9,6 +10,8 @@ import (
"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"
@@ -115,16 +118,15 @@ func (c *ObjectService) Upload(req ObjectUpload) (*ObjectUploadResp, error) {
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.Map(req.Files, func(src *UploadingObject) (*http2.IterMultiPartFile, error) {
resp, err := PostMultiPart(c.cfg, url,
map[string]string{"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
}
@@ -151,25 +153,42 @@ func (c *ObjectService) Upload(req ObjectUpload) (*ObjectUploadResp, error) {
const ObjectDownloadPath = "/object/download"

type ObjectDownload struct {
UserID cdssdk.UserID `form:"userID" json:"userID" binding:"required"`
ObjectID cdssdk.ObjectID `form:"objectID" json:"objectID" binding:"required"`
Offset int64 `form:"offset" json:"offset,omitempty"`
Length *int64 `form:"length" json:"length,omitempty"`
UserID cdssdk.UserID `form:"userID" url:"userID" binding:"required"`
ObjectID cdssdk.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) {
url, err := url.JoinPath(c.cfg.URL, ObjectDownloadPath)
httpReq, err := req.MakeParam().MakeRequest(c.cfg.URL)
if err != nil {
return nil, err
}

resp, err := http2.GetJSON(url, http2.RequestParam{
Query: req,
})
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
}
@@ -199,22 +218,38 @@ func (c *ObjectService) Download(req ObjectDownload) (*DownloadingObject, error)
const ObjectDownloadByPathPath = "/object/downloadByPath"

type ObjectDownloadByPath struct {
UserID cdssdk.UserID `form:"userID" json:"userID" binding:"required"`
PackageID cdssdk.PackageID `form:"packageID" json:"packageID" binding:"required"`
Path string `form:"path" json:"path" binding:"required"`
Offset int64 `form:"offset" json:"offset,omitempty"`
Length *int64 `form:"length" json:"length,omitempty"`
UserID cdssdk.UserID `form:"userID" url:"userID" binding:"required"`
PackageID cdssdk.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) {
url, err := url.JoinPath(c.cfg.URL, ObjectDownloadByPathPath)
httpReq, err := req.MakeParam().MakeRequest(c.cfg.URL)
if err != nil {
return nil, err
}

resp, err := http2.GetJSON(url, http2.RequestParam{
Query: req,
})
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
}


+ 4
- 5
sdks/storage/cdsapi/package.go View File

@@ -121,16 +121,15 @@ func (c *PackageService) CreateLoad(req PackageCreateLoad) (*PackageCreateLoadRe
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.Map(req.Files, func(src *UploadingObject) (*http2.IterMultiPartFile, error) {
resp, err := PostMultiPart(c.cfg, url,
map[string]string{"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
}


+ 113
- 2
sdks/storage/cdsapi/utils.go View File

@@ -2,15 +2,21 @@ package cdsapi

import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"mime/multipart"
"net/http"
ul "net/url"
"path/filepath"
"strings"
"time"

v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/google/go-querystring/query"
"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/math2"
@@ -60,7 +66,7 @@ func JSONAPI[Resp sdks.APIResponse, Req sdks.APIRequest](cfg *Config, cli *http.
}

signer := v4.NewSigner()
err = signer.SignHTTP(context.Background(), cred, httpReq, "", AuthService, AuthRegion, time.Now())
err = signer.SignHTTP(context.Background(), cred, httpReq, calcSha256(param.Body), AuthService, AuthRegion, time.Now())
if err != nil {
return re, err
}
@@ -91,7 +97,7 @@ func JSONAPINoData[Resp sdks.APIResponse, Req sdks.APIRequest](cfg *Config, cli
}

signer := v4.NewSigner()
err = signer.SignHTTP(context.Background(), cred, httpReq, "", AuthService, AuthRegion, time.Now())
err = signer.SignHTTP(context.Background(), cred, httpReq, calcSha256(param.Body), AuthService, AuthRegion, time.Now())
if err != nil {
return err
}
@@ -104,3 +110,108 @@ func JSONAPINoData[Resp sdks.APIResponse, Req sdks.APIRequest](cfg *Config, cli

return sdks.ParseCodeDataJSONResponse(resp, any(nil))
}

func calcSha256(body sdks.RequestBody) string {
hasher := sha256.New()
switch body := body.(type) {
case *sdks.StringBody:
return hex.EncodeToString(hasher.Sum([]byte(body.Value)))

case *sdks.BytesBody:
return hex.EncodeToString(hasher.Sum(body.Value))

default:
return ""
}
}

func PostMultiPart(cfg *Config, url string, info any, files http2.MultiPartFileIterator) (*http.Response, error) {
req, err := http.NewRequest(http.MethodPost, url, nil)
if err != nil {
return nil, err
}

pr, pw := io.Pipe()
muWriter := multipart.NewWriter(pw)

req.Header.Set("Content-Type", fmt.Sprintf("%s;boundary=%s", http2.ContentTypeMultiPart, muWriter.Boundary()))

writeResult := make(chan error, 1)
go func() {
writeResult <- func() error {
defer pw.Close()
defer muWriter.Close()

if info != nil {
mp, err := query.Values(info)
if err != nil {
return fmt.Errorf("formValues object to map failed, err: %w", err)
}

for k, v := range mp {
err := muWriter.WriteField(k, v[0])
if err != nil {
return fmt.Errorf("write form field failed, err: %w", err)
}
}
}

for {
file, err := files.MoveNext()
if err == iterator.ErrNoMoreItem {
break
}
if err != nil {
return fmt.Errorf("opening file: %w", err)
}

err = sendFileOnePart(muWriter, file.FieldName, file.FileName, file.File)
file.File.Close()
if err != nil {
return err
}
}

return nil
}()
}()

req.Body = pr

if cfg.AccessKey != "" && cfg.SecretKey != "" {
prod := credentials.NewStaticCredentialsProvider(cfg.AccessKey, cfg.SecretKey, "")
cred, err := prod.Retrieve(context.TODO())
if err != nil {
return nil, err
}

signer := v4.NewSigner()
err = signer.SignHTTP(context.Background(), cred, req, "", AuthService, AuthRegion, time.Now())
if err != nil {
return nil, err
}
}

cli := http.Client{}
resp, err := cli.Do(req)
if err != nil {
return nil, err
}

writeErr := <-writeResult
if writeErr != nil {
return nil, writeErr
}

return resp, nil
}

func sendFileOnePart(muWriter *multipart.Writer, fieldName, fileName string, file io.ReadCloser) error {
w, err := muWriter.CreateFormFile(fieldName, ul.PathEscape(fileName))
if err != nil {
return fmt.Errorf("create form file failed, err: %w", err)
}

_, err = io.Copy(w, file)
return err
}

Loading…
Cancel
Save