Skip to content

Commit 937d3d1

Browse files
authored
Merge pull request #36 from Yulegu-bj/master
新增"获取已上传成功的分片列表"
2 parents a12c13c + 76c743e commit 937d3d1

File tree

4 files changed

+121
-22
lines changed

4 files changed

+121
-22
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# !/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
4+
from ufile import multipartuploadufile, filemanager
5+
6+
public_key = '' # 账户公钥
7+
private_key = '' # 账户私钥
8+
9+
bucket = '' # 空间名称
10+
upload_id = '' # 上传分片ID
11+
max_parts = None # 最大分片数目
12+
part_number_marker = None # 起始分片编号
13+
14+
# 设置上传host后缀,外网可用后缀形如 .cn-bj.ufileos.com(cn-bj为北京地区,其他地区具体后缀可见控制台:对象存储-单地域空间管理-存储空间域名)
15+
# 默认值为'.cn-bj.ufileos.com',如果上传文件的bucket所在地域不在北京,请务必设置此项
16+
upload_suffix = '.cn-bj.ufileos.com'
17+
18+
multi_part_upload_ufile_handler = multipartuploadufile.MultipartUploadUFile(public_key, private_key, upload_suffix)
19+
20+
ret, resp = multi_part_upload_ufile_handler.get_multi_upload_part(bucket, upload_id, max_parts, part_number_marker,
21+
upload_suffix=upload_suffix)
22+
assert resp.status_code == 200, print(
23+
"status: %d error: %s" % (resp.status_code, resp.error if resp.error else resp.content))
24+
25+
print("list parts success")
26+
print(resp.content)

ufile/httprequest.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,22 @@ def _bucket_request(url, param, header):
327327
return __return_wraper(response)
328328

329329

330+
def _get_multi_upload_part(url, header):
331+
"""
332+
UCloud UFile 获取分片上传列表信息请求
333+
334+
:param url: String类型,获取分片上传列表信息请求的url
335+
:param header: dict类型,键值对类型分别为string类型,HTTP请求头信息
336+
:return: ret: 如果http状态码不为[200, 204, 206]之一则返回None,否则如果服务器返回json信息则返回dict类型,键值对类型分别为string, unicode string类型,否则返回空的dict
337+
:return: ResponseInfo: 响应的具体信息,UCloud UFile 服务器返回信息或者网络链接异常
338+
"""
339+
try:
340+
response = requests.get(url, headers=header)
341+
except RequestException as e:
342+
return None, ResponseInfo(None, e)
343+
return __return_wraper(response)
344+
345+
330346
class ResponseInfo(object):
331347
"""
332348
UCloud UFile 服务器返回信息,解析UCloud UFile服务器返回信息以及网络连接问题

ufile/multipartuploadufile.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
from . import config
1010
from .baseufile import BaseUFile
1111
from .compact import s
12-
from .httprequest import ResponseInfo, _initialsharding, _finishsharding, _shardingupload
12+
from .httprequest import ResponseInfo, _initialsharding, _finishsharding, _shardingupload, _get_multi_upload_part
1313
from .logger import logger
1414
from .util import _check_dict, initialsharding_url, finishsharding_url, shardingupload_url, _file_iter, \
15-
mimetype_from_file, mimetype_from_buffer, deprecated
15+
mimetype_from_file, mimetype_from_buffer, deprecated, ufile_listparts_url
1616

1717

1818
class MultipartUploadUFile(BaseUFile):
@@ -115,8 +115,9 @@ def uploadstream(self, bucket, key, stream, maxthread=4, retrycount=3, retryinte
115115
break
116116
self.etaglist.append("")
117117
thread1 = threading.Thread(target=self.__partthread, args=(
118-
sem, self.__bucket, self.__key, self.uploadid, partnumber, self.__header, data, retrycount, retryinterval,
119-
self.etaglist, self.__upload_suffix))
118+
sem, self.__bucket, self.__key, self.uploadid, partnumber, self.__header, data, retrycount,
119+
retryinterval,
120+
self.etaglist, self.__upload_suffix))
120121
self.__threaddict[partnumber] = thread1
121122
thread1.start()
122123
partnumber += 1
@@ -397,6 +398,8 @@ def init_multipart_upload(self, bucket, key, header=None, upload_suffix=None):
397398
self.__bucket = bucket
398399
self.__key = key
399400
self.__header = header if header else dict()
401+
if 'User-Agent' not in self.__header:
402+
self.__header['User-Agent'] = config.get_default('user_agent')
400403
self.__upload_suffix = upload_suffix if upload_suffix else config.get_default('upload_suffix')
401404
ret, resp = self.__initialsharding()
402405
if resp.ok:
@@ -431,7 +434,8 @@ def upload_part_copy(self, source_bucket, source_key, mime_type, offset, size, p
431434
self.__header.update({"X-Ufile-Copy-Source": "/%s/%s" % (source_bucket, source_key)})
432435
self.__header.update({"Content-Type": self.__mimetype})
433436
self.__header.update({"X-Ufile-Copy-Source-Range": "bytes=%d-%d" % (offset, size - 1)})
434-
437+
if 'User-Agent' not in self.__header:
438+
self.__header['User-Agent'] = config.get_default('user_agent')
435439
authorization = self.authorization('put', self.__bucket, self.__key, self.__header)
436440
self.__header.update({"Authorization": authorization})
437441

@@ -441,3 +445,25 @@ def upload_part_copy(self, source_bucket, source_key, mime_type, offset, size, p
441445
if resp.ok:
442446
self.etaglist.append(resp.etag)
443447
return ret, resp
448+
449+
def get_multi_upload_part(self, bucket, upload_id, max_parts=None, part_number_marker=None, header=None, upload_suffix=None):
450+
"""
451+
获取未完成分片上传的对象的已上传成功的分片列表。
452+
453+
:param bucket: string类型,空间名称
454+
:param upload_id: string类型,初始化分片上传时返回的uploadid
455+
:param max_parts: int类型,返回的最大条目数,默认为1000
456+
:param part_number_marker: int类型,返回的起始条目,默认为0
457+
:param header: dict类型,HTTP请求头部
458+
:param upload_suffix: string类型, 如果传入此参数, 则会忽略 config 中配置的 upload_suffix 字段
459+
:return: (dict, ResponseInfo) tuple类型,dict为返回的json信息,ResponseInfo为请求的返回信息
460+
"""
461+
self.__header = header if header else dict()
462+
if 'User-Agent' not in self.__header:
463+
self.__header['User-Agent'] = config.get_default('user_agent')
464+
if upload_suffix is not None:
465+
self.__upload_suffix = upload_suffix
466+
authorization = self.authorization('get', bucket, "", self.__header, action='muploadpart')
467+
self.__header.update({"Authorization": authorization})
468+
url = ufile_listparts_url(bucket, self.__upload_suffix, upload_id, max_parts, part_number_marker)
469+
return _get_multi_upload_part(url, self.__header)

ufile/util.py

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
# -*- coding: utf-8 -*-
22

3-
from .compact import *
4-
from . import config
5-
63
import base64
74
import hashlib
5+
import mimetypes
86
import os
97
import struct
10-
11-
import mimetypes
12-
from os import path
138
import warnings
14-
from .config import BLOCKSIZE
9+
from os import path
10+
11+
from . import config
12+
from .compact import *
13+
from .config import BLOCKSIZE
1514

1615
_EXTRA_TYPES_MAP = {
1716
".js": "application/javascript",
@@ -428,7 +427,10 @@ def shardingupload_url(bucket, key, uploadid, part_number, upload_suffix=None):
428427
:param part_number: integer类型, 分片上传的编号,从0开始
429428
:return: string类型, 结束分片上传UFile的url
430429
"""
431-
return 'http://{0}{1}/{2}?uploadId={3}&partNumber={4}'.format(bucket, upload_suffix or config.get_default('upload_suffix'), key, uploadid, s(str(part_number)))
430+
return 'http://{0}{1}/{2}?uploadId={3}&partNumber={4}'.format(bucket,
431+
upload_suffix or config.get_default('upload_suffix'),
432+
key, uploadid, s(str(part_number)))
433+
432434

433435
def ufile_getfilelist_url(bucket, upload_suffix=None):
434436
"""
@@ -439,6 +441,7 @@ def ufile_getfilelist_url(bucket, upload_suffix=None):
439441
"""
440442
return 'http://{0}{1}/?list'.format(bucket, upload_suffix or config.get_default('upload_suffix'))
441443

444+
442445
def mimetype_from_file(file):
443446
"""
444447
获取文件的mimetype
@@ -454,6 +457,7 @@ def mimetype_from_file(file):
454457

455458
return 'application/unknowntype'
456459

460+
457461
def mimetype_from_buffer(stream):
458462
"""
459463
获取流对象的mimetype
@@ -463,6 +467,7 @@ def mimetype_from_buffer(stream):
463467
"""
464468
return 'application/octet-stream'
465469

470+
466471
def ufile_restore_url(bucket, key, upload_suffix=None):
467472
"""
468473
解冻冷存文件的url
@@ -473,6 +478,7 @@ def ufile_restore_url(bucket, key, upload_suffix=None):
473478
"""
474479
return 'http://{0}{1}/{2}?restore'.format(bucket, upload_suffix or config.get_default('upload_suffix'), key)
475480

481+
476482
def ufile_classswitch_url(bucket, key, upload_suffix=None):
477483
"""
478484
文件存储类型转换的url
@@ -483,6 +489,7 @@ def ufile_classswitch_url(bucket, key, upload_suffix=None):
483489
"""
484490
return 'http://{0}{1}/{2}'.format(bucket, upload_suffix or config.get_default('upload_suffix'), key)
485491

492+
486493
def ufile_copy_url(bucket, key, upload_suffix=None):
487494
"""
488495
拷贝文件的url
@@ -493,6 +500,7 @@ def ufile_copy_url(bucket, key, upload_suffix=None):
493500
"""
494501
return 'http://{0}{1}/{2}'.format(bucket, upload_suffix or config.get_default('upload_suffix'), key)
495502

503+
496504
def ufile_rename_url(bucket, key, upload_suffix=None):
497505
"""
498506
重命名文件的url
@@ -504,6 +512,7 @@ def ufile_rename_url(bucket, key, upload_suffix=None):
504512
"""
505513
return 'http://{0}{1}/{2}'.format(bucket, upload_suffix or config.get_default('upload_suffix'), key)
506514

515+
507516
def ufile_listobjects_url(bucket, upload_suffix=None):
508517
"""
509518
获取目录文件列表的url
@@ -513,13 +522,35 @@ def ufile_listobjects_url(bucket, upload_suffix=None):
513522
"""
514523
return 'http://{0}{1}/?listobjects'.format(bucket, upload_suffix or config.get_default('upload_suffix'))
515524

525+
526+
def ufile_listparts_url(bucket, upload_suffix, upload_id, max_parts=None, part_number_marker=None):
527+
"""
528+
获取未完成分片上传的对象的已上传成功的分片列表。
529+
530+
:param bucket: string类型, 空间名称
531+
:param upload_suffix: string类型, 域名后缀
532+
:param upload_id: string类型, 初始化分片上传获得的uploadid字符串
533+
:param max_parts: integer类型, 规定在US3响应中的最大Part数目。
534+
:param part_number_marker: integer类型, 指定List的起始位置,只有Part Number数目大于该参数的Part会被列出
535+
"""
536+
url = 'http://{0}{1}/?muploadpart&uploadId={2}'.format(bucket, upload_suffix or config.get_default('upload_suffix'),
537+
upload_id)
538+
if max_parts is not None:
539+
url += '&max-parts={}'.format(max_parts)
540+
if part_number_marker is not None:
541+
url += '&part-number-marker={}'.format(part_number_marker)
542+
return url
543+
544+
516545
def deprecated(message):
517-
def deprecated_decorator(func):
518-
def deprecated_func(*args, **kwargs):
519-
warnings.warn("Call to deprecated function {} . -- {}".format(func.__name__, message),
520-
category=DeprecationWarning,
521-
stacklevel=2)
522-
warnings.simplefilter('default', DeprecationWarning)
523-
return func(*args, **kwargs)
524-
return deprecated_func
525-
return deprecated_decorator
546+
def deprecated_decorator(func):
547+
def deprecated_func(*args, **kwargs):
548+
warnings.warn("Call to deprecated function {} . -- {}".format(func.__name__, message),
549+
category=DeprecationWarning,
550+
stacklevel=2)
551+
warnings.simplefilter('default', DeprecationWarning)
552+
return func(*args, **kwargs)
553+
554+
return deprecated_func
555+
556+
return deprecated_decorator

0 commit comments

Comments
 (0)