1313from .cos_threadpool import SimpleThreadPool
1414logger = logging .getLogger (__name__ )
1515
16+
1617class ResumableDownLoader (object ):
1718 def __init__ (self , cos_client , bucket , key , dest_filename , object_info , part_size = 20 , max_thread = 5 , enable_crc = False , ** kwargs ):
1819 self .__cos_client = cos_client
@@ -24,26 +25,25 @@ def __init__(self, cos_client, bucket, key, dest_filename, object_info, part_siz
2425 self .__enable_crc = enable_crc
2526 self .__headers = kwargs
2627
27- self .__max_part_count = 100 # 取决于服务端是否对并发有限制
28- self .__min_part_size = 1024 * 1024 # 1M
28+ self .__max_part_count = 100 # 取决于服务端是否对并发有限制
29+ self .__min_part_size = 1024 * 1024 # 1M
2930 self .__part_size = self .__determine_part_size_internal (int (object_info ['Content-Length' ]), part_size )
3031 self .__finished_parts = []
3132 self .__lock = threading .Lock ()
32- self .__record = None # 记录当前的上下文
33+ self .__record = None # 记录当前的上下文
3334 self .__dump_record_dir = os .path .join (os .path .expanduser ('~' ), '.cos_download_tmp_file' )
34-
35+
3536 record_filename = self .__get_record_filename (bucket , key , self .__dest_file_path )
36- self .__record_filepath = os .path .join (self .__dump_record_dir , record_filename )
37+ self .__record_filepath = os .path .join (self .__dump_record_dir , record_filename )
3738 self .__tmp_file = None
3839
3940 if not os .path .exists (self .__dump_record_dir ):
4041 os .makedirs (self .__dump_record_dir )
41-
4242 logger .debug ('resumale downloader init finish, bucket: {0}, key: {1}' .format (bucket , key ))
4343
4444 def start (self ):
4545 logger .debug ('start resumable downloade, bucket: {0}, key: {1}' .format (self .__bucket , self .__key ))
46- self .__load_record () # 从record文件中恢复读取上下文
46+ self .__load_record () # 从record文件中恢复读取上下文
4747
4848 assert self .__tmp_file
4949 open (self .__tmp_file , 'a' ).close ()
@@ -78,10 +78,10 @@ def __get_record_filename(self, bucket, key, dest_file_path):
7878 return '{0}_{1}.{2}' .format (bucket , key_md5 , dest_file_path_md5 )
7979
8080 def __determine_part_size_internal (self , file_size , part_size ):
81- real_part_size = part_size * 1024 * 1024 # MB
81+ real_part_size = part_size * 1024 * 1024 # MB
8282 if real_part_size < self .__min_part_size :
8383 real_part_size = self .__min_part_size
84-
84+
8585 while real_part_size * self .__max_part_count < file_size :
8686 real_part_size = real_part_size * 2
8787 logger .debug ('finish to determine part size, file_size: {0}, part_size: {1}' .format (file_size , real_part_size ))
@@ -123,33 +123,29 @@ def __download_part(self, part, headers):
123123 result ["Body" ].pget_stream_to_file (f , part .start , part .length )
124124
125125 self .__finish_part (part )
126-
126+
127127 def __finish_part (self , part ):
128128 logger .debug ('download part finished,bucket: {0}, key: {1}, part_id: {2}' .
129129 format (self .__bucket , self .__key , part .part_id ))
130130 with self .__lock :
131131 self .__finished_parts .append (part )
132- self .__record ['parts' ].append ({'part_id' : part .part_id ,
133- 'start' : part .start ,
134- 'length' : part .length })
132+ self .__record ['parts' ].append ({'part_id' : part .part_id , 'start' : part .start , 'length' : part .length })
135133 self .__dump_record (self .__record )
136134
137- def __dump_record (self , record ):
135+ def __dump_record (self , record ):
138136 with open (self .__record_filepath , 'w' ) as f :
139137 json .dump (record , f )
140- logger .debug ('dump record to {0}, bucket: {1}, key: {2}' .
141- format (self .__record_filepath , self .__bucket , self .__key ))
138+ logger .debug ('dump record to {0}, bucket: {1}, key: {2}' .format (self .__record_filepath , self .__bucket , self .__key ))
142139
143140 def __load_record (self ):
144141 record = None
145142
146143 if os .path .exists (self .__record_filepath ):
147144 with open (self .__record_filepath , 'r' ) as f :
148145 record = json .load (f )
149-
150146 ret = self .__check_record (record )
151147 # record记录是否跟head object的一致,不一致则删除
152- if ret == False :
148+ if not ret :
153149 self .__del_record ()
154150 record = None
155151 else :
@@ -166,9 +162,9 @@ def __load_record(self):
166162
167163 if not record :
168164 self .__tmp_file = "{file_name}_{uuid}" .format (file_name = self .__dest_file_path , uuid = uuid .uuid4 ().hex )
169- record = {'bucket' : self .__bucket , 'key' : self .__key , 'tmp_filename' :self .__tmp_file ,
170- 'mtime' :self .__object_info ['Last-Modified' ], 'etag' :self .__object_info ['ETag' ],
171- 'file_size' :self .__object_info ['Content-Length' ], 'part_size' : self .__part_size , 'parts' :[]}
165+ record = {'bucket' : self .__bucket , 'key' : self .__key , 'tmp_filename' : self .__tmp_file ,
166+ 'mtime' : self .__object_info ['Last-Modified' ], 'etag' : self .__object_info ['ETag' ],
167+ 'file_size' : self .__object_info ['Content-Length' ], 'part_size' : self .__part_size , 'parts' : []}
172168 self .__record = record
173169 self .__dump_record (record )
174170
@@ -184,12 +180,13 @@ def __del_record(self):
184180 def __check_crc (self ):
185181 logger .debug ('start to check crc' )
186182 c64 = crcmod .mkCrcFun (0x142F0E1EBA9EA3693L , initCrc = 0L , xorOut = 0xffffffffffffffffL , rev = True )
187- with open (self .__dest_file_path ,'rb' ) as f :
183+ with open (self .__dest_file_path , 'rb' ) as f :
188184 local_crc64 = str (c64 (f .read ()))
189185 object_crc64 = self .__object_info ['x-cos-hash-crc64ecma' ]
190186 if local_crc64 is not None and object_crc64 is not None and local_crc64 != object_crc64 :
191187 raise CosClientError ('crc of client: {0} is mismatch with cos: {1}' .format (local_crc64 , object_crc64 ))
192188
189+
193190class PartInfo (object ):
194191 def __init__ (self , part_id , start , length ):
195192 self .part_id = part_id
0 commit comments