mirror of
https://github.com/eiblog/eiblog.git
synced 2026-03-01 00:34:58 +08:00
update vendor
This commit is contained in:
282
vendor/github.com/qiniu/api.v7/kodocli/upload.go
generated
vendored
Normal file
282
vendor/github.com/qiniu/api.v7/kodocli/upload.go
generated
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
package kodocli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
. "context"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
const (
|
||||
DontCheckCrc = 0
|
||||
CalcAndCheckCrc = 1
|
||||
CheckCrc = 2
|
||||
)
|
||||
|
||||
// 上传的额外可选项
|
||||
//
|
||||
type PutExtra struct {
|
||||
// 可选,用户自定义参数,必须以 "x:" 开头。若不以x:开头,则忽略。
|
||||
Params map[string]string
|
||||
|
||||
// 可选,当为 "" 时候,服务端自动判断。
|
||||
MimeType string
|
||||
|
||||
Crc32 uint32
|
||||
|
||||
// CheckCrc == 0 (DontCheckCrc): 表示不进行 crc32 校验
|
||||
// CheckCrc == 1 (CalcAndCheckCrc): 对于 Put 等同于 CheckCrc = 2;对于 PutFile 会自动计算 crc32 值
|
||||
// CheckCrc == 2 (CheckCrc): 表示进行 crc32 校验,且 crc32 值就是上面的 Crc32 变量
|
||||
CheckCrc uint32
|
||||
|
||||
// 上传事件:进度通知。这个事件的回调函数应该尽可能快地结束。
|
||||
OnProgress func(fsize, uploaded int64)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// 如果 uptoken 没有指定 ReturnBody,那么返回值是标准的 PutRet 结构
|
||||
//
|
||||
type PutRet struct {
|
||||
Hash string `json:"hash"`
|
||||
PersistentId string `json:"persistentId"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// 上传一个文件。
|
||||
// 和 Put 不同的只是一个通过提供文件路径来访问文件内容,一个通过 io.Reader 来访问。
|
||||
//
|
||||
// ctx 是请求的上下文。
|
||||
// ret 是上传成功后返回的数据。如果 uptoken 中没有设置 CallbackUrl 或 ReturnBody,那么返回的数据结构是 PutRet 结构。
|
||||
// uptoken 是由业务服务器颁发的上传凭证。
|
||||
// key 是要上传的文件访问路径。比如:"foo/bar.jpg"。注意我们建议 key 不要以 '/' 开头。另外,key 为空字符串是合法的。
|
||||
// localFile 是要上传的文件的本地路径。
|
||||
// extra 是上传的一些可选项。详细见 PutExtra 结构的描述。
|
||||
//
|
||||
func (p Uploader) PutFile(
|
||||
ctx Context, ret interface{}, uptoken, key, localFile string, extra *PutExtra) (err error) {
|
||||
|
||||
return p.putFile(ctx, ret, uptoken, key, true, localFile, extra)
|
||||
}
|
||||
|
||||
// 上传一个文件。文件的访问路径(key)自动生成。
|
||||
// 如果 uptoken 中设置了 SaveKey,那么按 SaveKey 要求的规则生成 key,否则自动以文件的 hash 做 key。
|
||||
// 和 RputWithoutKey 不同的只是一个通过提供文件路径来访问文件内容,一个通过 io.Reader 来访问。
|
||||
//
|
||||
// ctx 是请求的上下文。
|
||||
// ret 是上传成功后返回的数据。如果 uptoken 中没有设置 CallbackUrl 或 ReturnBody,那么返回的数据结构是 PutRet 结构。
|
||||
// uptoken 是由业务服务器颁发的上传凭证。
|
||||
// localFile 是要上传的文件的本地路径。
|
||||
// extra 是上传的一些可选项。详细见 PutExtra 结构的描述。
|
||||
//
|
||||
func (p Uploader) PutFileWithoutKey(
|
||||
ctx Context, ret interface{}, uptoken, localFile string, extra *PutExtra) (err error) {
|
||||
|
||||
return p.putFile(ctx, ret, uptoken, "", false, localFile, extra)
|
||||
}
|
||||
|
||||
func (p Uploader) putFile(
|
||||
ctx Context, ret interface{}, uptoken string,
|
||||
key string, hasKey bool, localFile string, extra *PutExtra) (err error) {
|
||||
|
||||
f, err := os.Open(localFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fsize := fi.Size()
|
||||
|
||||
if extra != nil && extra.CheckCrc == 1 {
|
||||
extra.Crc32, err = getFileCrc32(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return p.put(ctx, ret, uptoken, key, hasKey, f, fsize, extra, filepath.Base(localFile))
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// 上传一个文件。
|
||||
//
|
||||
// ctx 是请求的上下文。
|
||||
// ret 是上传成功后返回的数据。如果 uptoken 中没有设置 CallbackUrl 或 ReturnBody,那么返回的数据结构是 PutRet 结构。
|
||||
// uptoken 是由业务服务器颁发的上传凭证。
|
||||
// key 是要上传的文件访问路径。比如:"foo/bar.jpg"。注意我们建议 key 不要以 '/' 开头。另外,key 为空字符串是合法的。
|
||||
// data 是文件内容的访问接口(io.Reader)。
|
||||
// fsize 是要上传的文件大小。
|
||||
// extra 是上传的一些可选项。详细见 PutExtra 结构的描述。
|
||||
//
|
||||
func (p Uploader) Put(
|
||||
ctx Context, ret interface{}, uptoken, key string, data io.Reader, size int64, extra *PutExtra) error {
|
||||
|
||||
return p.put(ctx, ret, uptoken, key, true, data, size, extra, path.Base(key))
|
||||
}
|
||||
|
||||
// 上传一个文件。文件的访问路径(key)自动生成。
|
||||
// 如果 uptoken 中设置了 SaveKey,那么按 SaveKey 要求的规则生成 key,否则自动以文件的 hash 做 key。
|
||||
//
|
||||
// ctx 是请求的上下文。
|
||||
// ret 是上传成功后返回的数据。如果 uptoken 中没有设置 CallbackUrl 或 ReturnBody,那么返回的数据结构是 PutRet 结构。
|
||||
// uptoken 是由业务服务器颁发的上传凭证。
|
||||
// data 是文件内容的访问接口(io.Reader)。
|
||||
// fsize 是要上传的文件大小。
|
||||
// extra 是上传的一些可选项。详细见 PutExtra 结构的描述。
|
||||
//
|
||||
func (p Uploader) PutWithoutKey(
|
||||
ctx Context, ret interface{}, uptoken string, data io.Reader, size int64, extra *PutExtra) error {
|
||||
|
||||
return p.put(ctx, ret, uptoken, "", false, data, size, extra, "filename")
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
var defaultPutExtra PutExtra
|
||||
|
||||
func (p Uploader) put(
|
||||
ctx Context, ret interface{}, uptoken string,
|
||||
key string, hasKey bool, data io.Reader, size int64, extra *PutExtra, fileName string) error {
|
||||
|
||||
uphosts, err := p.getUpHostFromToken(uptoken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var b bytes.Buffer
|
||||
writer := multipart.NewWriter(&b)
|
||||
|
||||
if extra == nil {
|
||||
extra = &defaultPutExtra
|
||||
}
|
||||
|
||||
if extra.OnProgress != nil {
|
||||
data = &readerWithProgress{reader: data, fsize: size, onProgress: extra.OnProgress}
|
||||
}
|
||||
|
||||
err = writeMultipart(writer, uptoken, key, hasKey, extra, fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lastLine := fmt.Sprintf("\r\n--%s--\r\n", writer.Boundary())
|
||||
r := strings.NewReader(lastLine)
|
||||
|
||||
bodyLen := int64(-1)
|
||||
if size >= 0 {
|
||||
bodyLen = int64(b.Len()) + size + int64(len(lastLine))
|
||||
}
|
||||
mr := io.MultiReader(&b, data, r)
|
||||
|
||||
contentType := writer.FormDataContentType()
|
||||
err = p.Conn.CallWith64(ctx, ret, "POST", uphosts[0], contentType, mr, bodyLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if extra.OnProgress != nil {
|
||||
extra.OnProgress(size, size)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
type readerWithProgress struct {
|
||||
reader io.Reader
|
||||
uploaded int64
|
||||
fsize int64
|
||||
onProgress func(fsize, uploaded int64)
|
||||
}
|
||||
|
||||
func (p *readerWithProgress) Read(b []byte) (n int, err error) {
|
||||
|
||||
if p.uploaded > 0 {
|
||||
p.onProgress(p.fsize, p.uploaded)
|
||||
}
|
||||
|
||||
n, err = p.reader.Read(b)
|
||||
p.uploaded += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
func writeMultipart(
|
||||
writer *multipart.Writer, uptoken, key string, hasKey bool, extra *PutExtra, fileName string) (err error) {
|
||||
|
||||
//token
|
||||
if err = writer.WriteField("token", uptoken); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//key
|
||||
if hasKey {
|
||||
if err = writer.WriteField("key", key); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//extra.Params
|
||||
if extra.Params != nil {
|
||||
for k, v := range extra.Params {
|
||||
if strings.HasPrefix(k, "x:") {
|
||||
err = writer.WriteField(k, v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//extra.CheckCrc
|
||||
if extra.CheckCrc != 0 {
|
||||
err = writer.WriteField("crc32", strconv.FormatInt(int64(extra.Crc32), 10))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//file
|
||||
head := make(textproto.MIMEHeader)
|
||||
head.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, escapeQuotes(fileName)))
|
||||
if extra.MimeType != "" {
|
||||
head.Set("Content-Type", extra.MimeType)
|
||||
}
|
||||
|
||||
_, err = writer.CreatePart(head)
|
||||
return err
|
||||
}
|
||||
|
||||
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
func escapeQuotes(s string) string {
|
||||
return quoteEscaper.Replace(s)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
func getFileCrc32(f *os.File) (uint32, error) {
|
||||
|
||||
h := crc32.NewIEEE()
|
||||
_, err := io.Copy(h, f)
|
||||
f.Seek(0, 0)
|
||||
|
||||
return h.Sum32(), err
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
Reference in New Issue
Block a user