| @@ -1,9 +1,13 @@ | |||||
| module gitlink.org.cn/cloudream/common | module gitlink.org.cn/cloudream/common | ||||
| go 1.20 | |||||
| go 1.22 | |||||
| toolchain go1.23.2 | |||||
| require ( | require ( | ||||
| github.com/antonfisher/nested-logrus-formatter v1.3.1 | github.com/antonfisher/nested-logrus-formatter v1.3.1 | ||||
| github.com/aws/aws-sdk-go-v2 v1.36.3 | |||||
| github.com/aws/aws-sdk-go-v2/credentials v1.17.62 | |||||
| github.com/google/uuid v1.3.0 | github.com/google/uuid v1.3.0 | ||||
| github.com/hashicorp/go-multierror v1.1.1 | github.com/hashicorp/go-multierror v1.1.1 | ||||
| github.com/imdario/mergo v0.3.15 | github.com/imdario/mergo v0.3.15 | ||||
| @@ -21,14 +25,16 @@ require ( | |||||
| golang.org/x/exp v0.0.0-20230519143937-03e91628a987 | golang.org/x/exp v0.0.0-20230519143937-03e91628a987 | ||||
| ) | ) | ||||
| require github.com/aws/smithy-go v1.22.2 // indirect | |||||
| require ( | require ( | ||||
| github.com/benbjohnson/clock v1.3.0 // indirect | github.com/benbjohnson/clock v1.3.0 // indirect | ||||
| github.com/coreos/go-semver v0.3.0 // indirect | github.com/coreos/go-semver v0.3.0 // indirect | ||||
| github.com/coreos/go-systemd/v22 v22.5.0 // indirect | github.com/coreos/go-systemd/v22 v22.5.0 // indirect | ||||
| github.com/gogo/protobuf v1.3.2 // indirect | github.com/gogo/protobuf v1.3.2 // indirect | ||||
| github.com/golang/protobuf v1.5.3 // indirect | github.com/golang/protobuf v1.5.3 // indirect | ||||
| github.com/google/go-querystring v1.1.0 | |||||
| github.com/gopherjs/gopherjs v1.17.2 // indirect | github.com/gopherjs/gopherjs v1.17.2 // indirect | ||||
| github.com/gorilla/websocket v1.5.3 // indirect | |||||
| github.com/hashicorp/errwrap v1.1.0 // indirect | github.com/hashicorp/errwrap v1.1.0 // indirect | ||||
| github.com/jtolds/gls v4.20.0+incompatible // indirect | github.com/jtolds/gls v4.20.0+incompatible // indirect | ||||
| github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect | ||||
| @@ -1,5 +1,11 @@ | |||||
| github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= | github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= | ||||
| github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= | github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= | ||||
| github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= | |||||
| github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= | |||||
| github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU= | |||||
| github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8= | |||||
| github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= | |||||
| github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= | |||||
| github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= | github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= | ||||
| github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | ||||
| github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= | github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= | ||||
| @@ -15,15 +21,17 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 | |||||
| github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | ||||
| github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= | ||||
| github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | ||||
| github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||||
| github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | |||||
| github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= | |||||
| github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= | |||||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | ||||
| github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= | github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= | ||||
| github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= | github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= | ||||
| github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= | |||||
| github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | |||||
| github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | ||||
| github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= | ||||
| github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | ||||
| @@ -51,6 +59,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY | |||||
| github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= | github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= | ||||
| github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= | github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= | ||||
| github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= | github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= | ||||
| github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= | |||||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| @@ -75,6 +84,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO | |||||
| github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= | ||||
| github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||||
| github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= | github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= | ||||
| github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= | |||||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||
| @@ -150,6 +160,7 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw | |||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||||
| gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | |||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| @@ -0,0 +1,143 @@ | |||||
| package cdsapi | |||||
| import ( | |||||
| "context" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "net/url" | |||||
| "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" | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | |||||
| ) | |||||
| const ( | |||||
| AuthService = "jcs" | |||||
| AuthRegion = "any" | |||||
| ) | |||||
| type PresignedService struct { | |||||
| *Client | |||||
| accessKey string | |||||
| secretKey string | |||||
| } | |||||
| func (c *Client) Presigned(accessKey string, secretKey string) *PresignedService { | |||||
| return &PresignedService{ | |||||
| Client: c, | |||||
| accessKey: accessKey, | |||||
| secretKey: secretKey, | |||||
| } | |||||
| } | |||||
| const PresignedObjectDownloadByPathPath = "/v1/presigned/object/downloadByPath" | |||||
| type PresignedObjectDownloadByPath struct { | |||||
| 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 (c *PresignedService) ObjectDownload(req PresignedObjectDownloadByPath, expireIn int) (string, error) { | |||||
| return c.presign(req, PresignedObjectDownloadByPathPath, http.MethodGet, expireIn) | |||||
| } | |||||
| const PresignedObjectUploadPath = "/v1/presigned/object/upload" | |||||
| type PresignedObjectUpload struct { | |||||
| UserID cdssdk.UserID `form:"userID" binding:"required" url:"userID"` | |||||
| PackageID cdssdk.PackageID `form:"packageID" binding:"required" url:"packageID"` | |||||
| Path string `form:"path" binding:"required" url:"path"` | |||||
| Affinity cdssdk.StorageID `form:"affinity" url:"affinity,omitempty"` | |||||
| LoadTo []cdssdk.StorageID `form:"loadTo" url:"loadTo,omitempty"` | |||||
| LoadToPath []string `form:"loadToPath" url:"loadToPath,omitempty"` | |||||
| } | |||||
| type PresignedObjectUploadResp struct { | |||||
| Object cdssdk.Object `json:"object"` | |||||
| } | |||||
| func (c *PresignedService) ObjectUpload(req PresignedObjectUpload, expireIn int) (string, error) { | |||||
| return c.presign(req, PresignedObjectUploadPath, http.MethodPost, expireIn) | |||||
| } | |||||
| const PresignedObjectNewMultipartUploadPath = "/v1/presigned/object/newMultipartUpload" | |||||
| type PresignedObjectNewMultipartUpload struct { | |||||
| UserID cdssdk.UserID `form:"userID" binding:"required" url:"userID"` | |||||
| PackageID cdssdk.PackageID `form:"packageID" binding:"required" url:"packageID"` | |||||
| Path string `form:"path" binding:"required" url:"path"` | |||||
| } | |||||
| type PresignedObjectNewMultipartUploadResp struct { | |||||
| Object cdssdk.Object `json:"object"` | |||||
| } | |||||
| func (c *PresignedService) ObjectNewMultipartUpload(req PresignedObjectNewMultipartUpload, expireIn int) (string, error) { | |||||
| return c.presign(req, PresignedObjectNewMultipartUploadPath, http.MethodPost, expireIn) | |||||
| } | |||||
| const PresignedObjectUploadPartPath = "/v1/presigned/object/uploadPart" | |||||
| type PresignedObjectUploadPart struct { | |||||
| UserID cdssdk.UserID `form:"userID" binding:"required" url:"userID"` | |||||
| ObjectID cdssdk.ObjectID `form:"objectID" binding:"required" url:"objectID"` | |||||
| Index int `form:"index" binding:"required" url:"index"` | |||||
| } | |||||
| type PresignedUploadPartResp struct{} | |||||
| func (c *PresignedService) ObjectUploadPart(req PresignedObjectUploadPart, expireIn int) (string, error) { | |||||
| return c.presign(req, PresignedObjectUploadPartPath, http.MethodPost, expireIn) | |||||
| } | |||||
| const PresignedObjectCompleteMultipartUploadPath = "/v1/presigned/object/completeMultipartUpload" | |||||
| type PresignedObjectCompleteMultipartUpload struct { | |||||
| UserID cdssdk.UserID `form:"userID" binding:"required" url:"userID"` | |||||
| ObjectID cdssdk.ObjectID `form:"objectID" binding:"required" url:"objectID"` | |||||
| Indexes []int `form:"indexes" binding:"required" url:"indexes"` | |||||
| } | |||||
| type PresignedObjectCompleteMultipartUploadResp struct { | |||||
| Object cdssdk.Object `json:"object"` | |||||
| } | |||||
| func (c *PresignedService) ObjectCompleteMultipartUpload(req PresignedObjectCompleteMultipartUpload, expireIn int) (string, error) { | |||||
| return c.presign(req, PresignedObjectCompleteMultipartUploadPath, http.MethodPost, expireIn) | |||||
| } | |||||
| func (c *PresignedService) presign(req any, path string, method string, expireIn int) (string, error) { | |||||
| u, err := url.Parse(c.baseURL) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| u = u.JoinPath(path) | |||||
| us, err := query.Values(req) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| us.Add("X-Expires", fmt.Sprintf("%v", expireIn)) | |||||
| u.RawQuery = us.Encode() | |||||
| prod := credentials.NewStaticCredentialsProvider(c.accessKey, c.secretKey, "") | |||||
| cred, err := prod.Retrieve(context.TODO()) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| r, err := http.NewRequest(method, u.String(), nil) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| signer := v4.NewSigner() | |||||
| signedURL, _, err := signer.PresignHTTP(context.Background(), cred, r, "", AuthService, AuthRegion, time.Now()) | |||||
| return signedURL, err | |||||
| } | |||||
| @@ -0,0 +1,125 @@ | |||||
| package cdsapi | |||||
| import ( | |||||
| "testing" | |||||
| . "github.com/smartystreets/goconvey/convey" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/types" | |||||
| ) | |||||
| func Test_Presigned(t *testing.T) { | |||||
| cli := NewClient(&Config{ | |||||
| URL: "http://localhost:7890", | |||||
| }) | |||||
| Convey("下载文件", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectDownload(PresignedObjectDownloadByPath{ | |||||
| UserID: 1, | |||||
| PackageID: 3, | |||||
| Path: "example.java", | |||||
| Offset: 1, | |||||
| Length: types.Ref(int64(100)), | |||||
| }, 100) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| Convey("上传文件", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectUpload(PresignedObjectUpload{ | |||||
| UserID: 1, | |||||
| PackageID: 3, | |||||
| Path: "example.java", | |||||
| }, 100) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| } | |||||
| func Test_PresignedObjectDownload(t *testing.T) { | |||||
| cli := NewClient(&Config{ | |||||
| URL: "http://localhost:7890", | |||||
| }) | |||||
| Convey("下载文件", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectDownload(PresignedObjectDownloadByPath{ | |||||
| UserID: 1, | |||||
| PackageID: 3, | |||||
| Path: "example.java", | |||||
| // Offset: 1, | |||||
| // Length: types.Ref(int64(100)), | |||||
| }, 100) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| } | |||||
| func Test_PresignedObjectUpload(t *testing.T) { | |||||
| cli := NewClient(&Config{ | |||||
| URL: "http://localhost:7890", | |||||
| }) | |||||
| Convey("上传文件", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectUpload(PresignedObjectUpload{ | |||||
| UserID: 1, | |||||
| PackageID: 3, | |||||
| Path: "example.java", | |||||
| }, 100) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| } | |||||
| func Test_PresignedNewMultipartUpload(t *testing.T) { | |||||
| cli := NewClient(&Config{ | |||||
| URL: "http://localhost:7890", | |||||
| }) | |||||
| Convey("启动分片上传", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectNewMultipartUpload(PresignedObjectNewMultipartUpload{ | |||||
| UserID: 1, | |||||
| PackageID: 3, | |||||
| Path: "example.java", | |||||
| }, 600) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| } | |||||
| func Test_PresignedObjectUploadPart(t *testing.T) { | |||||
| cli := NewClient(&Config{ | |||||
| URL: "http://localhost:7890", | |||||
| }) | |||||
| Convey("上传分片", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectUploadPart(PresignedObjectUploadPart{ | |||||
| UserID: 1, | |||||
| ObjectID: 7, | |||||
| Index: 3, | |||||
| }, 600) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| } | |||||
| func Test_PresignedCompleteMultipartUpload(t *testing.T) { | |||||
| cli := NewClient(&Config{ | |||||
| URL: "http://localhost:7890", | |||||
| }) | |||||
| Convey("合并分片", t, func() { | |||||
| pre := cli.Presigned("123456", "123456") | |||||
| url, err := pre.ObjectCompleteMultipartUpload(PresignedObjectCompleteMultipartUpload{ | |||||
| UserID: 1, | |||||
| ObjectID: 7, | |||||
| Indexes: []int{1, 2, 3}, | |||||
| }, 600) | |||||
| So(err, ShouldEqual, nil) | |||||
| t.Logf("url: %s", url) | |||||
| }) | |||||
| } | |||||
| @@ -6,6 +6,7 @@ import ( | |||||
| "fmt" | "fmt" | ||||
| "io" | "io" | ||||
| "reflect" | "reflect" | ||||
| "strings" | |||||
| jsoniter "github.com/json-iterator/go" | jsoniter "github.com/json-iterator/go" | ||||
| "github.com/mitchellh/mapstructure" | "github.com/mitchellh/mapstructure" | ||||
| @@ -189,3 +190,79 @@ func ObjectToMap(obj any) (map[string]any, error) { | |||||
| } | } | ||||
| return mp, dec.Decode(obj) | return mp, dec.Decode(obj) | ||||
| } | } | ||||
| // 1. 尝试解开所有引用 | |||||
| // | |||||
| // 2. nil值将会是空字符串 | |||||
| func ObjectToMapString(obj any) (map[string]string, error) { | |||||
| if obj == nil { | |||||
| return make(map[string]string), nil | |||||
| } | |||||
| v := reflect.ValueOf(obj) | |||||
| for v.Kind() == reflect.Ptr { | |||||
| v = v.Elem() | |||||
| } | |||||
| if !v.IsValid() { | |||||
| return make(map[string]string), nil | |||||
| } | |||||
| if v.Kind() != reflect.Struct { | |||||
| return nil, fmt.Errorf("type %v is not a struct", v.Type()) | |||||
| } | |||||
| mp := make(map[string]string) | |||||
| objectToMapString(v, mp) | |||||
| return mp, nil | |||||
| } | |||||
| func objectToMapString(val reflect.Value, mp map[string]string) { | |||||
| typ := val.Type() | |||||
| for i := 0; i < val.NumField(); i++ { | |||||
| vf := val.Field(i) | |||||
| tf := typ.Field(i) | |||||
| if tf.Anonymous { | |||||
| objectToMapString(vf, mp) | |||||
| continue | |||||
| } | |||||
| fieldName := tf.Name | |||||
| omitEmpty := false | |||||
| jsonTag := tf.Tag.Get("json") | |||||
| if jsonTag != "" { | |||||
| tagParts := strings.Split(jsonTag, ",") | |||||
| fieldName = strings.TrimSpace(tagParts[0]) | |||||
| if len(tagParts) > 1 { | |||||
| for _, tagPart := range tagParts[1:] { | |||||
| tagPart = strings.TrimSpace(tagPart) | |||||
| if tagPart == "omitempty" { | |||||
| omitEmpty = true | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| for vf.Kind() == reflect.Ptr { | |||||
| vf = vf.Elem() | |||||
| } | |||||
| if !vf.IsValid() { | |||||
| if omitEmpty { | |||||
| continue | |||||
| } | |||||
| mp[fieldName] = "" | |||||
| continue | |||||
| } | |||||
| if vf.IsZero() && omitEmpty { | |||||
| continue | |||||
| } | |||||
| if vf.Kind() == reflect.Array { | |||||
| } | |||||
| mp[fieldName] = fmt.Sprintf("%v", vf) | |||||
| } | |||||
| } | |||||
| @@ -694,3 +694,108 @@ func Test_ObjectToJSONEx4(t *testing.T) { | |||||
| So(ret[0].(*StCallback).Value, ShouldEqual, "called") | So(ret[0].(*StCallback).Value, ShouldEqual, "called") | ||||
| }) | }) | ||||
| } | } | ||||
| type StStringer struct { | |||||
| } | |||||
| func (s StStringer) String() string { | |||||
| return "StStringer" | |||||
| } | |||||
| func Test_ObjectToMapString(t *testing.T) { | |||||
| Convey("结构体", t, func() { | |||||
| type StEmb struct { | |||||
| IntRef *int `json:"intRef,omitempty"` | |||||
| BoolRef **bool `json:"boolRef"` | |||||
| StrRef *string `json:"strRef"` | |||||
| } | |||||
| type St struct { | |||||
| StEmb | |||||
| Int int | |||||
| Bool bool | |||||
| Str string | |||||
| StStringer *StStringer | |||||
| } | |||||
| st := St{ | |||||
| StEmb: StEmb{ | |||||
| IntRef: types.Ref(123), | |||||
| BoolRef: types.Ref(types.Ref(true)), | |||||
| }, | |||||
| Int: 456, | |||||
| Bool: false, | |||||
| Str: "test", | |||||
| StStringer: &StStringer{}, | |||||
| } | |||||
| mp, err := ObjectToMapString(st) | |||||
| So(err, ShouldBeNil) | |||||
| So(mp["intRef"], ShouldEqual, "123") | |||||
| So(mp["boolRef"], ShouldEqual, "true") | |||||
| So(mp["strRef"], ShouldEqual, "") | |||||
| So(mp["Int"], ShouldEqual, "456") | |||||
| So(mp["Bool"], ShouldEqual, "false") | |||||
| So(mp["Str"], ShouldEqual, "test") | |||||
| So(mp["StStringer"], ShouldEqual, "StStringer") | |||||
| }) | |||||
| Convey("结构体引用", t, func() { | |||||
| type StEmb struct { | |||||
| IntRef *int `json:"intRef,omitempty"` | |||||
| BoolRef **bool `json:"boolRef"` | |||||
| StrRef *string `json:"strRef"` | |||||
| } | |||||
| type St struct { | |||||
| StEmb | |||||
| Int int | |||||
| Bool bool | |||||
| Str string | |||||
| StStringer *StStringer | |||||
| } | |||||
| st := St{ | |||||
| StEmb: StEmb{ | |||||
| IntRef: types.Ref(123), | |||||
| BoolRef: types.Ref(types.Ref(true)), | |||||
| }, | |||||
| Int: 456, | |||||
| Bool: false, | |||||
| Str: "test", | |||||
| StStringer: &StStringer{}, | |||||
| } | |||||
| mp, err := ObjectToMapString(&st) | |||||
| So(err, ShouldBeNil) | |||||
| So(mp["intRef"], ShouldEqual, "123") | |||||
| So(mp["boolRef"], ShouldEqual, "true") | |||||
| So(mp["strRef"], ShouldEqual, "") | |||||
| So(mp["Int"], ShouldEqual, "456") | |||||
| So(mp["Bool"], ShouldEqual, "false") | |||||
| So(mp["Str"], ShouldEqual, "test") | |||||
| So(mp["StStringer"], ShouldEqual, "StStringer") | |||||
| }) | |||||
| Convey("nil", t, func() { | |||||
| mp, err := ObjectToMapString(nil) | |||||
| So(err, ShouldBeNil) | |||||
| So(mp, ShouldResemble, map[string]string{}) | |||||
| }) | |||||
| Convey("nil指针", t, func() { | |||||
| type St struct{} | |||||
| var st *St | |||||
| mp, err := ObjectToMapString(st) | |||||
| So(err, ShouldBeNil) | |||||
| So(mp, ShouldResemble, map[string]string{}) | |||||
| }) | |||||
| Convey("非结构体", t, func() { | |||||
| mp, err := ObjectToMapString(123) | |||||
| So(err, ShouldNotBeNil) | |||||
| So(mp, ShouldBeNil) | |||||
| }) | |||||
| } | |||||