Skip to content

Commit

Permalink
Merge f7e6324 into 6317035
Browse files Browse the repository at this point in the history
  • Loading branch information
coderall committed May 17, 2019
2 parents 6317035 + f7e6324 commit 1a52b06
Show file tree
Hide file tree
Showing 11 changed files with 1,985 additions and 93 deletions.
3 changes: 2 additions & 1 deletion oss2/__init__.py
Expand Up @@ -23,9 +23,10 @@
from .utils import http_date, http_to_unixtime, iso8601_to_unixtime, date_to_iso8601, iso8601_to_date


from .models import BUCKET_ACL_PRIVATE, BUCKET_ACL_PUBLIC_READ, BUCKET_ACL_PUBLIC_READ_WRITE
from .models import BUCKET_ACL_PRIVATE, BUCKET_ACL_PUBLIC_READ, BUCKET_ACL_PUBLIC_READ_WRITE, SERVER_SIDE_ENCRYPTION_AES256, SERVER_SIDE_ENCRYPTION_KMS
from .models import OBJECT_ACL_DEFAULT, OBJECT_ACL_PRIVATE, OBJECT_ACL_PUBLIC_READ, OBJECT_ACL_PUBLIC_READ_WRITE
from .models import BUCKET_STORAGE_CLASS_STANDARD, BUCKET_STORAGE_CLASS_IA, BUCKET_STORAGE_CLASS_ARCHIVE
from .models import BUCKET_VERSIONING_ENABLE, BUCKET_VERSIONING_SUSPEND

from .crypto import LocalRsaProvider, AliKMSProvider
import logging
Expand Down
346 changes: 303 additions & 43 deletions oss2/api.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion oss2/auth.py
Expand Up @@ -72,7 +72,8 @@ class Auth(AuthBase):
'response-expires', 'response-content-disposition', 'cors', 'lifecycle',
'restore', 'qos', 'referer', 'stat', 'bucketInfo', 'append', 'position', 'security-token',
'live', 'comp', 'status', 'vod', 'startTime', 'endTime', 'x-oss-process',
'symlink', 'callback', 'callback-var', 'tagging']
'symlink', 'callback', 'callback-var', 'tagging', 'encryption', 'versions',
'versioning', 'versionId']
)

def _sign_request(self, req, bucket_name, key):
Expand Down
8 changes: 8 additions & 0 deletions oss2/exceptions.py
Expand Up @@ -230,6 +230,14 @@ class AccessDenied(ServerError):
status = 403
code = 'AccessDenied'

class NoSuchServerSideEncryptionRule(NotFound):
status = 404
code = 'NoSuchServerSideEncryptionRule'

class InvalidEncryptionAlgorithmError(ServerError):
status = 400
code = 'InvalidEncryptionAlgorithmError'

class SelectOperationFailed(ServerError):
code = 'SelectOperationFailed'
def __init__(self, status, code, message):
Expand Down
137 changes: 127 additions & 10 deletions oss2/models.py
Expand Up @@ -59,6 +59,10 @@ def __init__(self, resp):
#: 请求ID,用于跟踪一个OSS请求。提交工单时,最后能够提供请求ID
self.request_id = resp.request_id

self.versionid = _hget(self.headers, 'x-oss-version-id')

self.delete_marker = _hget(self.headers, 'x-oss-delete-marker', bool)

class HeadObjectResult(RequestResult):
def __init__(self, resp):
super(HeadObjectResult, self).__init__(resp)
Expand Down Expand Up @@ -202,6 +206,27 @@ def __init__(self, resp):
#: 下次追加写的偏移
self.next_position = _hget(resp.headers, OSS_NEXT_APPEND_POSITION, int)

class BatchDeleteObjectVersion(object):
def __init__(self, key=None, versionid=None):
self.key = key or ''
self.versionid = versionid or ''

class BatchDeleteObjectVersionList(object):
def __init__(self, object_version_list=None):
self.object_version_list = object_version_list or []

def append(self, object_version):
self.object_version_list.append(object_version)

def len(self):
return len(self.object_version_list)

class BatchDeleteObjectVersionResult(object):
def __init__(self, key, versionid=None, delete_marker=None, delete_marker_versionid=None):
self.key = key
self.versionid = versionid or ''
self.delete_marker = delete_marker or False
self.delete_marker_versionid = delete_marker_versionid or ''

class BatchDeleteObjectsResult(RequestResult):
def __init__(self, resp):
Expand All @@ -210,6 +235,9 @@ def __init__(self, resp):
#: 已经删除的文件名列表
self.deleted_keys = []

#:已经删除的带版本信息的文件信息列表
self.delete_versions = []


class InitMultipartUploadResult(RequestResult):
def __init__(self, resp):
Expand Down Expand Up @@ -429,7 +457,8 @@ def __init__(self, display_name, owner_id):

class BucketInfo(object):
def __init__(self, name=None, owner=None, location=None, storage_class=None, intranet_endpoint=None,
extranet_endpoint=None, creation_date=None, acl=None):
extranet_endpoint=None, creation_date=None, acl=None, bucket_encryption_rule=None,
versioning_status=None):
self.name = name
self.owner = owner
self.location = location
Expand All @@ -439,6 +468,9 @@ def __init__(self, name=None, owner=None, location=None, storage_class=None, int
self.creation_date = creation_date
self.acl = acl

self.bucket_encryption_rule = bucket_encryption_rule
self.versioning_status = versioning_status


class GetBucketStatResult(RequestResult, BucketStat):
def __init__(self, resp):
Expand Down Expand Up @@ -555,7 +587,7 @@ class LifecycleRule(object):
:param storage_transitions: 存储类型转换规则
:type storage_transitions: :class:`StorageTransition`
:param tagging: object tagging 规则
:type tagging: :class:`ObjectTagging`
:type tagging: :class:`Tagging`
"""

ENABLED = 'Enabled'
Expand Down Expand Up @@ -887,11 +919,11 @@ def __init__(self, resp):
_MAX_OBJECT_TAGGING_KEY_LENGTH=128
_MAX_OBJECT_TAGGING_VALUE_LENGTH=256

class ObjectTagging(object):
class Tagging(object):

def __init__(self, tagging_rules=None):

self.tag_set = tagging_rules or ObjectTaggingRule()
self.tag_set = tagging_rules or TaggingRule()

def __str__(self):

Expand All @@ -905,21 +937,21 @@ def __str__(self):

return tag_str

class ObjectTaggingRule(object):
class TaggingRule(object):

def __init__(self):
self.tagging_rule = dict()

def add(self, key, value):

if key is None or key == '':
raise ClientError("ObjectTagging key should not be empty")
raise ClientError("Tagging key should not be empty")

if len(key) > _MAX_OBJECT_TAGGING_KEY_LENGTH:
raise ClientError("ObjectTagging key is too long")
raise ClientError("Tagging key is too long")

if len(value) > _MAX_OBJECT_TAGGING_VALUE_LENGTH:
raise ClientError("ObjectTagging value is too long")
raise ClientError("Tagging value is too long")

self.tagging_rule[key] = value

Expand All @@ -945,8 +977,93 @@ def to_query_string(self):

return query_string

class GetObjectTaggingResult(RequestResult, ObjectTagging):
class GetTaggingResult(RequestResult, Tagging):

def __init__(self, resp):
RequestResult.__init__(self, resp)
Tagging.__init__(self)

SERVER_SIDE_ENCRYPTION_AES256 = 'AES256'
SERVER_SIDE_ENCRYPTION_KMS = 'KMS'

class ServerSideEncryptionRule(object):

def __init__(self, ssealgorithm=None, kmsmasterkeyid=None):

self.ssealgorithm = ssealgorithm
self.kmsmasterkeyid = kmsmasterkeyid

class GetServerSideEncryptionResult(RequestResult, ServerSideEncryptionRule):

def __init__(self, resp):
RequestResult.__init__(self, resp)
ObjectTagging.__init__(self)
ServerSideEncryptionRule.__init__(self)

class ListObjectVersionsResult(RequestResult):
def __init__(self, resp):
super(ListObjectVersionsResult, self).__init__(resp)

#: True表示还有更多的文件可以罗列;False表示已经列举完毕。
self.is_truncated = False

#: 本次使用的分页标记符
self.key_marker = ''

#: 下一次罗列的分页标记符,即,可以作为 :func:`list_object_versions <oss2.Bucket.list_object_versions>` 的 `key_marker` 参数。
self.next_key_marker = ''

#: 本次使用的versionid分页标记符
self.versionid_marker = ''

#: 下一次罗列的versionid分页标记符,即,可以作为 :func:`list_object_versions <oss2.Bucket.list_object_versions>` 的 `versionid_marker` 参数。
self.next_versionid_marker = ''

self.name = ''

self.owner = ''

self.prefix = ''

self.max_keys = ''

self.delimiter = ''

#: 本次罗列得到的delete marker列表。其中元素的类型为 :class:`DeleteMarkerInfo` 。
self.delete_marker = []

#: 本次罗列得到的文件version列表。其中元素的类型为 :class:`ObjectVersionInfo` 。
self.versions = []

self.common_prefix = []

class DeleteMarkerInfo(object):
def __init__(self):
self.key = ''
self.versionid = ''
self.is_latest = False
self.last_modified = ''
self.owner = Owner('', '')

class ObjectVersionInfo(object):
def __init__(self):
self.key = ''
self.versionid = ''
self.is_latest = False
self.last_modified = ''
self.owner = Owner('', '')
self.type = ''
self.storage_class = ''
self.size = ''
self.etag = ''

BUCKET_VERSIONING_ENABLE = 'Enabled'
BUCKET_VERSIONING_SUSPEND = 'Suspended'

class BucketVersioningConfig(object):
def __init__(self, status=None):
self.status = status

class GetBucketVersioningResult(RequestResult, BucketVersioningConfig):
def __init__(self, resp):
RequestResult.__init__(self,resp)
BucketVersioningConfig.__init__(self)
20 changes: 13 additions & 7 deletions oss2/resumable.py
Expand Up @@ -89,7 +89,8 @@ def resumable_download(bucket, key, filename,
part_size=None,
progress_callback=None,
num_threads=None,
store=None):
store=None,
params=None):
"""断点下载。
实现的方法是:
Expand Down Expand Up @@ -120,6 +121,8 @@ def resumable_download(bucket, key, filename,
:param store: 用来保存断点信息的持久存储,可以指定断点信息所在的目录。
:type store: `ResumableDownloadStore`
:param dict params: 指定下载参数,可以传入versionId下载指定版本文件
:raises: 如果OSS文件不存在,则抛出 :class:`NotFound <oss2.exceptions.NotFound>` ;也有可能抛出其他因下载文件而产生的异常。
"""

Expand All @@ -129,20 +132,21 @@ def resumable_download(bucket, key, filename,
multiget_threshold = defaults.get(multiget_threshold, defaults.multiget_threshold)

if isinstance(bucket, Bucket):
result = bucket.head_object(key)
result = bucket.head_object(key, params=params)
logger.debug("The size of object to download is: {0}, multiget_threshold: {1}".format(result.content_length,
multiget_threshold))
if result.content_length >= multiget_threshold:
downloader = _ResumableDownloader(bucket, key, filename, _ObjectInfo.make(result),
part_size=part_size,
progress_callback=progress_callback,
num_threads=num_threads,
store=store)
store=store,
params=params)
downloader.download(result.server_crc)
else:
bucket.get_object_to_file(key, filename, progress_callback=progress_callback)
bucket.get_object_to_file(key, filename, progress_callback=progress_callback, params=params)
else:
bucket.get_object_to_file(key, filename, progress_callback=progress_callback)
bucket.get_object_to_file(key, filename, progress_callback=progress_callback, params=params)


_MAX_MULTIGET_PART_COUNT = 100
Expand Down Expand Up @@ -248,7 +252,8 @@ def __init__(self, bucket, key, filename, objectInfo,
part_size=None,
store=None,
progress_callback=None,
num_threads=None):
num_threads=None,
params=None):
super(_ResumableDownloader, self).__init__(bucket, key, filename, objectInfo.size,
store or ResumableDownloadStore(),
progress_callback=progress_callback)
Expand All @@ -261,6 +266,7 @@ def __init__(self, bucket, key, filename, objectInfo,
self.__num_threads = defaults.get(num_threads, defaults.multiget_num_threads)
self.__finished_parts = None
self.__finished_size = None
self.__params = params

# protect record
self.__lock = threading.Lock()
Expand Down Expand Up @@ -311,7 +317,7 @@ def __download_part(self, part):

headers = {IF_MATCH : self.objectInfo.etag,
IF_UNMODIFIED_SINCE : utils.http_date(self.objectInfo.mtime)}
result = self.bucket.get_object(self.key, byte_range=(part.start, part.end - 1), headers=headers)
result = self.bucket.get_object(self.key, byte_range=(part.start, part.end - 1), headers=headers, params=self.__params)
utils.copyfileobj_and_verify(result, f, part.end - part.start, request_id=result.request_id)

part.part_crc = result.client_crc
Expand Down

0 comments on commit 1a52b06

Please sign in to comment.