github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/internal/pcsfunctions/pcsupload/upload.go (about)

     1  package pcsupload
     2  
     3  import (
     4  	"context"
     5  	"github.com/fzfile/BaiduPCS-Go/baidupcs"
     6  	"github.com/fzfile/BaiduPCS-Go/baidupcs/pcserror"
     7  	"github.com/fzfile/BaiduPCS-Go/internal/pcsconfig"
     8  	"github.com/fzfile/BaiduPCS-Go/requester"
     9  	"github.com/fzfile/BaiduPCS-Go/requester/multipartreader"
    10  	"github.com/fzfile/BaiduPCS-Go/requester/rio"
    11  	"github.com/fzfile/BaiduPCS-Go/requester/uploader"
    12  	"io"
    13  	"net/http"
    14  )
    15  
    16  type (
    17  	PCSUpload struct {
    18  		pcs        *baidupcs.BaiduPCS
    19  		targetPath string
    20  	}
    21  
    22  	EmptyReaderLen64 struct {
    23  	}
    24  )
    25  
    26  func (e EmptyReaderLen64) Read(p []byte) (n int, err error) {
    27  	return 0, io.EOF
    28  }
    29  
    30  func (e EmptyReaderLen64) Len() int64 {
    31  	return 0
    32  }
    33  
    34  func NewPCSUpload(pcs *baidupcs.BaiduPCS, targetPath string) uploader.MultiUpload {
    35  	return &PCSUpload{
    36  		pcs:        pcs,
    37  		targetPath: targetPath,
    38  	}
    39  }
    40  
    41  func (pu *PCSUpload) lazyInit() {
    42  	if pu.pcs == nil {
    43  		pu.pcs = &baidupcs.BaiduPCS{}
    44  	}
    45  }
    46  
    47  // Precreate do nothing
    48  func (pu *PCSUpload) Precreate() (err error) {
    49  	return nil
    50  }
    51  
    52  func (pu *PCSUpload) TmpFile(ctx context.Context, partseq int, partOffset int64, r rio.ReaderLen64) (checksum string, uperr error) {
    53  	pu.lazyInit()
    54  
    55  	var respErr *uploader.MultiError
    56  	checksum, pcsError := pu.pcs.UploadTmpFile(func(uploadURL string, jar http.CookieJar) (resp *http.Response, err error) {
    57  		client := pcsconfig.Config.PCSHTTPClient()
    58  		client.SetCookiejar(jar)
    59  		client.SetTimeout(0)
    60  
    61  		mr := multipartreader.NewMultipartReader()
    62  		mr.AddFormFile("uploadedfile", "", r)
    63  		mr.CloseMultipart()
    64  
    65  		doneChan := make(chan struct{}, 1)
    66  		go func() {
    67  			resp, err = client.Req(http.MethodPost, uploadURL, mr, nil)
    68  			doneChan <- struct{}{}
    69  
    70  			if resp != nil {
    71  				// 不可恢复的错误
    72  				switch resp.StatusCode {
    73  				case 400, 401, 403, 413:
    74  					respErr = &uploader.MultiError{
    75  						Terminated: true,
    76  					}
    77  				}
    78  			}
    79  		}()
    80  		select {
    81  		case <-ctx.Done(): // 取消
    82  			// 返回, 让那边关闭连接
    83  			return resp, ctx.Err()
    84  		case <-doneChan:
    85  			// return
    86  		}
    87  		return
    88  	})
    89  
    90  	if respErr != nil {
    91  		respErr.Err = pcsError
    92  		return checksum, respErr
    93  	}
    94  
    95  	return checksum, pcsError
    96  }
    97  
    98  func (pu *PCSUpload) CreateSuperFile(checksumList ...string) (err error) {
    99  	pu.lazyInit()
   100  
   101  	// 先在网盘目标位置, 上传一个空文件
   102  	// 防止出现file does not exist
   103  	pcsError := pu.pcs.Upload(pu.targetPath, func(uploadURL string, jar http.CookieJar) (resp *http.Response, err error) {
   104  		mr := multipartreader.NewMultipartReader()
   105  		mr.AddFormFile("file", "file", &EmptyReaderLen64{})
   106  		mr.CloseMultipart()
   107  
   108  		c := requester.NewHTTPClient()
   109  		c.SetCookiejar(jar)
   110  		return c.Req(http.MethodPost, uploadURL, mr, nil)
   111  	})
   112  	if pcsError != nil {
   113  		// 修改操作
   114  		pcsError.(*pcserror.PCSErrInfo).Operation = baidupcs.OperationUploadCreateSuperFile
   115  		return pcsError
   116  	}
   117  
   118  	return pu.pcs.UploadCreateSuperFile(false, pu.targetPath, checksumList...)
   119  }