@@ -1991,3 +1991,192 @@ func (s *ObjectService) GetSymlink(ctx context.Context, name string, opt *Object
19911991 }
19921992 return resp .Header .Get ("x-cos-symlink-target" ), resp , err
19931993}
1994+
1995+ type ObjectPutFromURLOptions struct {
1996+ PartSize int
1997+ QueueSize int
1998+ InitOptions * InitiateMultipartUploadOptions
1999+ }
2000+
2001+ func (s * ObjectService ) PutFromURL (ctx context.Context , name string , downloadURL string , opt * ObjectPutFromURLOptions ) (* CompleteMultipartUploadResult , * Response , error ) {
2002+ if opt == nil {
2003+ opt = & ObjectPutFromURLOptions {}
2004+ }
2005+ // init
2006+ v , resp , err := s .InitiateMultipartUpload (ctx , name , opt .InitOptions )
2007+ if err != nil {
2008+ return nil , resp , err
2009+ }
2010+ uploadId := v .UploadID
2011+ var isErr bool
2012+ defer func () {
2013+ if isErr {
2014+ s .AbortMultipartUpload (ctx , name , uploadId , nil )
2015+ }
2016+ }()
2017+ // request from url
2018+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , downloadURL , nil )
2019+ if err != nil {
2020+ isErr = true
2021+ return nil , nil , err
2022+ }
2023+ rsp , err := http .DefaultClient .Do (req )
2024+ if err != nil || rsp == nil {
2025+ isErr = true
2026+ return nil , nil , err
2027+ }
2028+ defer rsp .Body .Close ()
2029+ if rsp .StatusCode > 299 {
2030+ isErr = true
2031+ return nil , & Response {rsp }, fmt .Errorf ("the status code of downloadURL response is failed: %d" , rsp .StatusCode )
2032+ }
2033+ factory := newPartFactory (opt .PartSize , opt .QueueSize )
2034+ partChannel , errChannel := factory .Produce (rsp .Body )
2035+ defer factory .Close ()
2036+
2037+ comOpt := & CompleteMultipartUploadOptions {}
2038+ var partNumber int
2039+ for {
2040+ select {
2041+ case part , ok := <- partChannel :
2042+ if ! ok {
2043+ partChannel = nil
2044+ break
2045+ }
2046+ partNumber ++
2047+ resp , err := s .UploadPart (ctx , name , uploadId , partNumber , part , nil )
2048+ if err != nil {
2049+ isErr = true
2050+ return nil , resp , err
2051+ }
2052+ comOpt .Parts = append (comOpt .Parts , Object {
2053+ PartNumber : partNumber ,
2054+ ETag : resp .Header .Get ("ETag" ),
2055+ })
2056+ case err , ok := <- errChannel :
2057+ if ! ok {
2058+ errChannel = nil
2059+ break
2060+ }
2061+ if err != nil {
2062+ isErr = true
2063+ return nil , nil , err
2064+ }
2065+ }
2066+ if partChannel == nil && errChannel == nil {
2067+ break
2068+ }
2069+ }
2070+ res , resp , err := s .CompleteMultipartUpload (ctx , name , uploadId , comOpt )
2071+ if err != nil {
2072+ isErr = true
2073+ }
2074+ return res , resp , err
2075+ }
2076+
2077+ type partFactory struct {
2078+ partSize int
2079+ queueSize int
2080+ current * bytes.Buffer
2081+ partChannel chan * bytes.Buffer
2082+ errChannel chan error
2083+ cancelChannel chan struct {}
2084+ }
2085+
2086+ const CHUNK_SIZE = 1024 * 1024
2087+
2088+ func newPartFactory (partSize int , queueSize int ) * partFactory {
2089+ if partSize <= 0 {
2090+ partSize = 8
2091+ }
2092+ if queueSize <= 0 {
2093+ queueSize = 10
2094+ }
2095+ return & partFactory {
2096+ partSize : partSize * 1024 * 1024 ,
2097+ queueSize : queueSize ,
2098+ current : bytes .NewBuffer (nil ),
2099+ }
2100+ }
2101+
2102+ func (pf * partFactory ) Produce (reader io.ReadCloser ) (<- chan * bytes.Buffer , <- chan error ) {
2103+ pf .cancelChannel = make (chan struct {}, 1 )
2104+ pf .partChannel = make (chan * bytes.Buffer , pf .queueSize )
2105+ pf .errChannel = make (chan error , 1 )
2106+
2107+ go pf .Run (reader )
2108+ return pf .partChannel , pf .errChannel
2109+ }
2110+
2111+ func (pf * partFactory ) Close () {
2112+ pf .cancelChannel <- struct {}{}
2113+ }
2114+
2115+ func (pf * partFactory ) Run (reader io.ReadCloser ) {
2116+ var total , parts int
2117+ defer func () {
2118+ close (pf .errChannel )
2119+ close (pf .partChannel )
2120+ }()
2121+ buf := make ([]byte , CHUNK_SIZE )
2122+ for {
2123+ select {
2124+ case <- pf .cancelChannel :
2125+ return
2126+ default :
2127+ n , err := reader .Read (buf )
2128+ total += n
2129+ if n > 0 {
2130+ part , e := pf .Write (buf [:n ])
2131+ if e != nil {
2132+ pf .errChannel <- e
2133+ return
2134+ }
2135+ if part != nil {
2136+ parts ++
2137+ select {
2138+ case pf .partChannel <- part :
2139+ case <- pf .cancelChannel :
2140+ return
2141+ }
2142+ }
2143+ }
2144+ if err != nil && err != io .EOF {
2145+ pf .errChannel <- err
2146+ return
2147+ }
2148+ if err == io .EOF || n == 0 {
2149+ if pf .current .Len () > 0 {
2150+ parts ++
2151+ select {
2152+ case pf .partChannel <- pf .current :
2153+ case <- pf .cancelChannel :
2154+ return
2155+ }
2156+ }
2157+ return
2158+ }
2159+ }
2160+ }
2161+ }
2162+
2163+ func (pf * partFactory ) Write (p []byte ) (* bytes.Buffer , error ) {
2164+ var res * bytes.Buffer
2165+ for nwrite := 0 ; nwrite < len (p ); {
2166+ if pf .current .Len () == pf .partSize {
2167+ res = pf .current
2168+ pf .current = bytes .NewBuffer (nil )
2169+ }
2170+ end := len (p )
2171+ // 大于缓存区大小
2172+ if pf .current .Len ()+ end - nwrite > pf .partSize {
2173+ end = nwrite + pf .partSize - pf .current .Len ()
2174+ }
2175+ nr , err := pf .current .Write (p [nwrite :end ])
2176+ if err != nil {
2177+ return res , err
2178+ }
2179+ nwrite += nr
2180+ }
2181+ return res , nil
2182+ }
0 commit comments