You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/qiniu/go-sdk/v7/storage/base64_upload.go

172 lines
5.1 KiB

2 years ago
package storage
import (
"bytes"
"context"
"encoding/base64"
"fmt"
2 years ago
"github.com/qiniu/go-sdk/v7/internal/hostprovider"
2 years ago
"hash/crc32"
"io"
"net/http"
"strconv"
"strings"
2 years ago
"time"
2 years ago
"github.com/qiniu/go-sdk/v7/client"
)
// Base64Uploader 表示一个Base64上传对象
type Base64Uploader struct {
client *client.Client
cfg *Config
}
// NewBase64Uploader 用来构建一个Base64上传的对象
func NewBase64Uploader(cfg *Config) *Base64Uploader {
if cfg == nil {
cfg = &Config{}
}
return &Base64Uploader{
client: &client.DefaultClient,
cfg: cfg,
}
}
// NewBase64UploaderEx 用来构建一个Base64上传的对象
func NewBase64UploaderEx(cfg *Config, clt *client.Client) *Base64Uploader {
if cfg == nil {
cfg = &Config{}
}
if clt == nil {
clt = &client.DefaultClient
}
return &Base64Uploader{
client: clt,
cfg: cfg,
}
}
// Base64PutExtra 为Base64上传的额外可选项
type Base64PutExtra struct {
// 可选,用户自定义参数,必须以 "x:" 开头。若不以x:开头,则忽略。
Params map[string]string
// 可选,当为 "" 时候,服务端自动判断。
MimeType string
2 years ago
TryTimes int // 可选。尝试次数
// 主备域名冻结时间默认600s当一个域名请求失败单个域名会被重试 TryTimes 次),会被冻结一段时间,使用备用域名进行重试,在冻结时间内,域名不能被使用,当一个操作中所有域名竣备冻结操作不在进行重试,返回最后一次操作的错误。
HostFreezeDuration time.Duration
}
func (r *Base64PutExtra) init() {
if r.TryTimes == 0 {
r.TryTimes = settings.TryTimes
}
if r.HostFreezeDuration <= 0 {
r.HostFreezeDuration = 10 * 60 * time.Second
}
2 years ago
}
// Put 用来以Base64方式上传一个文件
//
// ctx 是请求的上下文。
// ret 是上传成功后返回的数据。如果 uptoken 中没有设置 callbackUrl 或 returnBody那么返回的数据结构是 PutRet 结构。
// uptoken 是由业务服务器颁发的上传凭证。
// key 是要上传的文件访问路径。比如:"foo/bar.jpg"。注意我们建议 key 不要以 '/' 开头。另外key 为空字符串是合法的。
// base64Data 是要上传的Base64数据一般为图片数据的Base64编码字符串
// extra 是上传的一些可选项可以指定为nil。详细见 Base64PutExtra 结构的描述。
func (p *Base64Uploader) Put(
ctx context.Context, ret interface{}, uptoken, key string, base64Data []byte, extra *Base64PutExtra) (err error) {
return p.put(ctx, ret, uptoken, key, true, base64Data, extra)
}
// PutWithoutKey 用来以Base64方式上传一个文件保存的文件名以文件的内容hash作为文件名
func (p *Base64Uploader) PutWithoutKey(
ctx context.Context, ret interface{}, uptoken string, base64Data []byte, extra *Base64PutExtra) (err error) {
return p.put(ctx, ret, uptoken, "", false, base64Data, extra)
}
func (p *Base64Uploader) put(
ctx context.Context, ret interface{}, uptoken, key string, hasKey bool, base64Data []byte, extra *Base64PutExtra) (err error) {
//set default extra
if extra == nil {
extra = &Base64PutExtra{}
}
2 years ago
extra.init()
2 years ago
//calc crc32
h := crc32.NewIEEE()
rawReader := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(base64Data))
fsize, decodeErr := io.Copy(h, rawReader)
if decodeErr != nil {
err = fmt.Errorf("invalid base64 data, %s", decodeErr.Error())
return
}
fCrc32 := h.Sum32()
postPath := bytes.NewBufferString("/putb64")
//add fsize
postPath.WriteString("/")
postPath.WriteString(strconv.Itoa(int(fsize)))
//add key
if hasKey {
postPath.WriteString("/key/")
postPath.WriteString(base64.URLEncoding.EncodeToString([]byte(key)))
}
//add mimeType
if extra.MimeType != "" {
postPath.WriteString("/mimeType/")
postPath.WriteString(base64.URLEncoding.EncodeToString([]byte(extra.MimeType)))
}
//add crc32
postPath.WriteString("/crc32/")
postPath.WriteString(fmt.Sprintf("%d", fCrc32))
//add extra params
if len(extra.Params) > 0 {
for k, v := range extra.Params {
if strings.HasPrefix(k, "x:") && v != "" {
postPath.WriteString("/")
postPath.WriteString(k)
postPath.WriteString("/")
postPath.WriteString(base64.URLEncoding.EncodeToString([]byte(v)))
}
}
}
2 years ago
//get up host
ak, bucket, gErr := getAkBucketFromUploadToken(uptoken)
if gErr != nil {
err = gErr
return
}
var upHostProvider hostprovider.HostProvider
12 months ago
upHostProvider, err = p.upHostProvider(ak, bucket, extra)
2 years ago
if err != nil {
return
}
2 years ago
2 years ago
return doUploadAction(upHostProvider, extra.TryTimes, extra.HostFreezeDuration, func(host string) error {
postURL := fmt.Sprintf("%s%s", host, postPath.String())
headers := http.Header{}
headers.Add("Content-Type", "application/octet-stream")
headers.Add("Authorization", "UpToken "+uptoken)
return p.client.CallWith(ctx, ret, "POST", postURL, headers, bytes.NewReader(base64Data), len(base64Data))
})
2 years ago
}
12 months ago
func (p *Base64Uploader) upHostProvider(ak, bucket string, extra *Base64PutExtra) (hostProvider hostprovider.HostProvider, err error) {
return getUpHostProvider(p.cfg, extra.TryTimes, extra.HostFreezeDuration, ak, bucket)
2 years ago
}