Skip to content

Commit c57b274

Browse files
authored
Merge pull request #204 from zhy1985555/master
支持新域名、静态连接池
2 parents 2a49bfb + cf5afbe commit c57b274

File tree

10 files changed

+103
-42
lines changed

10 files changed

+103
-42
lines changed

demo/ci_media.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def ci_create_media_transcode_watermark_jobs():
9090
'StartTime':'0',
9191
'EndTime':'1000.5',
9292
'Image': {
93-
'Url': 'http://'+bucket_name+".cos."+region+".myqcloud.com/1215shuiyin.jpg",
93+
'Url': 'http://'+bucket_name+".cos."+region+".tencentcos.cn/1215shuiyin.jpg",
9494
'Mode': 'Fixed',
9595
'Width': '128',
9696
'Height': '128',

demo/ci_watermark.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
bucket_name = 'examplebucket-1250000000'
2626
# 添加盲水印
27-
watermark_url = 'http://{bucket}.cos.{region}.myqcloud.com/watermark.png'.format(bucket=bucket_name, region=region)
27+
watermark_url = 'http://{bucket}.cos.{region}.tencentcos.cn/watermark.png'.format(bucket=bucket_name, region=region)
2828
watermark_url_base64 = bytes.decode(base64.b64encode(str.encode(watermark_url)))
2929
print(watermark_url_base64)
3030
response, data = client.ci_put_object_from_local_file(
@@ -39,10 +39,10 @@
3939
print(data['ProcessResults']['Object']['ETag'])
4040

4141
# 下载时添加盲水印
42-
# download_url = http://examplebucket-1250000000.cos.ap-shanghai.myqcloud.com/sample.jpeg?watermark/3/type/3/text/watermark_url_base64
42+
# download_url = http://examplebucket-1250000000.cos.ap-shanghai.tencentcos.cn/sample.jpeg?watermark/3/type/3/text/watermark_url_base64
4343

4444
# 提取盲水印
45-
sample_url = 'http://{bucket}.cos.{region}.myqcloud.com/sample.png'.format(bucket=bucket_name, region=region)
45+
sample_url = 'http://{bucket}.cos.{region}.tencentcos.cn/sample.png'.format(bucket=bucket_name, region=region)
4646
sample_url_base64 = bytes.decode(base64.b64encode(str.encode(sample_url)))
4747
response, data = client.ci_put_object_from_local_file(
4848
Bucket=bucket_name,

demo/demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def percentage(consumed_bytes, total_bytes):
3838
token = None # 如果使用永久密钥不需要填入token,如果使用临时密钥需要填入,临时密钥生成和使用指引参见https://cloud.tencent.com/document/product/436/14048
3939
domain = None # domain可以不填,此时使用COS区域域名访问存储桶。domain也可以填写用户自定义域名,或者桶的全球加速域名
4040
# 填写用户自定义域名,比如user-define.example.com,需要先开启桶的自定义域名,具体请参见https://cloud.tencent.com/document/product/436/36638
41-
# 填写桶的全球加速域名,比如examplebucket-1250000000.cos.accelerate.myqcloud.com,需要先开启桶的全球加速功能,请参见https://cloud.tencent.com/document/product/436/38864
41+
# 填写桶的全球加速域名,比如examplebucket-1250000000.cos.accelerate.tencentcos.cn,需要先开启桶的全球加速功能,请参见https://cloud.tencent.com/document/product/436/38864
4242

4343
config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token, Domain=domain) # 获取配置对象
4444
client = CosS3Client(config)

demo/fetch_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
response = client.put_async_fetch_task(
2626
Bucket=test_bucket,
2727
FetchTaskConfiguration={
28-
'Url': 'http://examplebucket-1250000000.cos.ap-beijing.myqcloud.com/exampleobject',
28+
'Url': 'http://examplebucket-1250000000.cos.ap-beijing.tencentcos.cn/exampleobject',
2929
'Key': 'exampleobject'
3030
}
3131
)

qcloud_cos/cos_client.py

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class CosConfig(object):
3939
def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token=None, Scheme=None, Timeout=None,
4040
Access_id=None, Access_key=None, Secret_id=None, Secret_key=None, Endpoint=None, IP=None, Port=None,
4141
Anonymous=None, UA=None, Proxies=None, Domain=None, ServiceDomain=None, PoolConnections=10,
42-
PoolMaxSize=10, AllowRedirects=False, SignHost=True, EndpointCi=None):
42+
PoolMaxSize=10, AllowRedirects=False, SignHost=True, EndpointCi=None, EnableOldDomain=True, EnableInternalDomain=True):
4343
"""初始化,保存用户的信息
4444
4545
:param Appid(string): 用户APPID.
@@ -66,6 +66,8 @@ def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token
6666
:param AllowRedirects(bool): 是否重定向
6767
:param SignHost(bool): 是否将host算入签名
6868
:param EndpointCi(string): ci的endpoint
69+
:param EnableOldDomain(bool): 是否使用旧的myqcloud.com域名访问COS
70+
:param EnableInternalDomain(bool): 是否使用内网域名访问COS
6971
"""
7072
self._appid = to_unicode(Appid)
7173
self._token = to_unicode(Token)
@@ -85,9 +87,11 @@ def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token
8587
self._allow_redirects = AllowRedirects
8688
self._sign_host = SignHost
8789
self._copy_part_threshold_size = SINGLE_UPLOAD_LENGTH
90+
self._enable_old_domain = EnableOldDomain
91+
self._enable_internal_domain = EnableInternalDomain
8892

8993
if self._domain is None:
90-
self._endpoint = format_endpoint(Endpoint, Region)
94+
self._endpoint = format_endpoint(Endpoint, Region, u'cos.', EnableOldDomain, EnableInternalDomain)
9195
if Scheme is None:
9296
Scheme = u'https'
9397
Scheme = to_unicode(Scheme)
@@ -96,7 +100,8 @@ def __init__(self, Appid=None, Region=None, SecretId=None, SecretKey=None, Token
96100
self._scheme = Scheme
97101

98102
# 格式化ci的endpoint 不支持自定义域名的
99-
self._endpoint_ci = format_endpoint(EndpointCi, Region, u'ci.')
103+
# ci暂不支持新域名
104+
self._endpoint_ci = format_endpoint(EndpointCi, Region, u'ci.', True, False)
100105

101106
# 兼容(SecretId,SecretKey)以及(AccessId,AccessKey)
102107
if (SecretId and SecretKey):
@@ -205,6 +210,8 @@ def convert_secret_value(self, value):
205210
class CosS3Client(object):
206211
"""cos客户端类,封装相应请求"""
207212

213+
__built_in_sessions = None # 内置的静态连接池,多个Client间共享使用
214+
208215
def __init__(self, conf, retry=1, session=None):
209216
"""初始化client对象
210217
@@ -214,15 +221,48 @@ def __init__(self, conf, retry=1, session=None):
214221
"""
215222
self._conf = conf
216223
self._retry = retry # 重试的次数,分片上传时可适当增大
224+
225+
if not CosS3Client.__built_in_sessions:
226+
with threading.Lock():
227+
if not CosS3Client.__built_in_sessions: # 加锁后double check
228+
CosS3Client.__built_in_sessions = self.generate_built_in_connection_pool(self._conf._pool_connections, self._conf._pool_maxsize)
229+
217230
if session is None:
218-
self._session = requests.session()
219-
self._session.mount('http://', requests.adapters.HTTPAdapter(pool_connections=self._conf._pool_connections,
220-
pool_maxsize=self._conf._pool_maxsize))
221-
self._session.mount('https://', requests.adapters.HTTPAdapter(pool_connections=self._conf._pool_connections,
222-
pool_maxsize=self._conf._pool_maxsize))
231+
self._session = CosS3Client.__built_in_sessions
223232
else:
224233
self._session = session
225234

235+
def set_built_in_connection_pool_max_size(self, PoolConnections, PoolMaxSize):
236+
"""设置SDK内置的连接池的连接大小,并且重新绑定到client中"""
237+
if not CosS3Client.__built_in_sessions:
238+
return
239+
240+
if CosS3Client.__built_in_sessions.get_adapter('http://')._pool_connections == PoolConnections \
241+
and CosS3Client.__built_in_sessions.get_adapter('http://')._pool_maxsize == PoolMaxSize:
242+
return
243+
244+
# 判断之前是否绑定到内置连接池
245+
rebound = False
246+
if self._session and self._session is CosS3Client.__built_in_sessions:
247+
rebound = True
248+
249+
# 重新生成内置连接池
250+
CosS3Client.__built_in_sessions.close()
251+
CosS3Client.__built_in_sessions = self.generate_built_in_connection_pool(PoolConnections, PoolMaxSize)
252+
253+
# 重新绑定到内置连接池
254+
if rebound:
255+
self._session = CosS3Client.__built_in_sessions
256+
logger.warn("rebound built-in connection pool success. maxsize=%d,%d" % (PoolConnections, PoolMaxSize))
257+
258+
def generate_built_in_connection_pool(self, PoolConnections, PoolMaxSize):
259+
"""生成SDK内置的连接池,此连接池是client间共用的"""
260+
built_in_sessions = requests.session()
261+
built_in_sessions.mount('http://', requests.adapters.HTTPAdapter(pool_connections=PoolConnections, pool_maxsize=PoolMaxSize))
262+
built_in_sessions.mount('https://', requests.adapters.HTTPAdapter(pool_connections=PoolConnections, pool_maxsize=PoolMaxSize))
263+
logger.warn("generate built-in connection pool success. maxsize=%d,%d" % (PoolConnections, PoolMaxSize))
264+
return built_in_sessions
265+
226266
def get_conf(self):
227267
"""获取配置"""
228268
return self._conf
@@ -778,7 +818,7 @@ def copy_object(self, Bucket, Key, CopySource, CopyStatus='Copy', **kwargs):
778818
)
779819
"""
780820
headers = mapped(kwargs)
781-
headers['x-cos-copy-source'] = gen_copy_source_url(CopySource)
821+
headers['x-cos-copy-source'] = gen_copy_source_url(CopySource, self._conf._enable_old_domain, self._conf._enable_internal_domain)
782822
if CopyStatus != 'Copy' and CopyStatus != 'Replaced':
783823
raise CosClientError('CopyStatus must be Copy or Replaced')
784824
headers['x-cos-metadata-directive'] = CopyStatus
@@ -827,7 +867,7 @@ def upload_part_copy(self, Bucket, Key, PartNumber, UploadId, CopySource, CopySo
827867
)
828868
"""
829869
headers = mapped(kwargs)
830-
headers['x-cos-copy-source'] = gen_copy_source_url(CopySource)
870+
headers['x-cos-copy-source'] = gen_copy_source_url(CopySource, self._conf._enable_old_domain, self._conf._enable_internal_domain)
831871
headers['x-cos-copy-source-range'] = CopySourceRange
832872
params = {'partNumber': PartNumber, 'uploadId': UploadId}
833873
params = format_values(params)
@@ -3199,7 +3239,12 @@ def list_buckets(self, **kwargs):
31993239
response = client.list_buckets()
32003240
"""
32013241
headers = mapped(kwargs)
3202-
url = '{scheme}://service.cos.myqcloud.com/'.format(scheme=self._conf._scheme)
3242+
3243+
if self._conf._enable_old_domain:
3244+
url = '{scheme}://service.cos.myqcloud.com/'.format(scheme=self._conf._scheme)
3245+
else:
3246+
url = '{scheme}://service.cos.tencentcos.cn/'.format(scheme=self._conf._scheme)
3247+
32033248
if self._conf._service_domain is not None:
32043249
url = '{scheme}://{domain}/'.format(scheme=self._conf._scheme, domain=self._conf._service_domain)
32053250
rt = self.send_request(
@@ -3476,7 +3521,7 @@ def upload_file(self, Bucket, Key, LocalFilePath, PartSize=1, MAXThread=5, Enabl
34763521

34773522
def _head_object_when_copy(self, CopySource, **kwargs):
34783523
"""查询源文件的长度"""
3479-
bucket, path, endpoint, versionid = get_copy_source_info(CopySource)
3524+
bucket, path, endpoint, versionid = get_copy_source_info(CopySource, self._conf._enable_old_domain, self._conf._enable_internal_domain)
34803525
params = {}
34813526
if versionid != '':
34823527
params['versionId'] = versionid
@@ -3521,7 +3566,7 @@ def _upload_part_copy(self, bucket, key, part_number, upload_id, copy_source, co
35213566
return None
35223567

35233568
def _check_same_region(self, dst_endpoint, CopySource):
3524-
src_endpoint = get_copy_source_info(CopySource)[2]
3569+
src_endpoint = get_copy_source_info(CopySource, self._conf._enable_old_domain, self._conf._enable_internal_domain)[2]
35253570
if src_endpoint == dst_endpoint:
35263571
return True
35273572
return False
@@ -5244,7 +5289,7 @@ def ci_auditing_image_batch(self, Bucket, Input, DetectType=None, BizType=None,
52445289
:param Input(dict array): 需要审核的图片信息,每个array元素为dict类型,支持的参数如下:
52455290
Object: 存储在 COS 存储桶中的图片文件名称,例如在目录 test 中的文件 image.jpg,则文件名称为 test/image.jpg。
52465291
Object 和 Url 只能选择其中一种。
5247-
Url: 图片文件的链接地址,例如 http://a-1250000.cos.ap-shanghai.myqcloud.com/image.jpg。
5292+
Url: 图片文件的链接地址,例如 http://a-1250000.cos.ap-shanghai.tencentcos.cn/image.jpg。
52485293
Object 和 Url 只能选择其中一种。
52495294
Interval: 截帧频率,GIF 图检测专用,默认值为5,表示从第一帧(包含)开始每隔5帧截取一帧
52505295
MaxFrames: 最大截帧数量,GIF 图检测专用,默认值为5,表示只截取 GIF 的5帧图片进行审核,必须大于0

qcloud_cos/cos_comm.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def format_values(data):
220220
return data
221221

222222

223-
def format_endpoint(endpoint, region, module=u'cos.'):
223+
def format_endpoint(endpoint, region, module, EnableOldDomain, EnableInternalDomain):
224224
# 客户使用全球加速域名时,只会传endpoint不会传region。此时这样endpointCi和region同时为None,就会报错。
225225
if not endpoint and not region and module == u'cos.':
226226
raise CosClientError("Region or Endpoint is required not empty!")
@@ -229,13 +229,16 @@ def format_endpoint(endpoint, region, module=u'cos.'):
229229
if endpoint:
230230
return to_unicode(endpoint)
231231
elif region:
232-
region = format_region(region, module)
233-
return u"{region}.myqcloud.com".format(region=region)
232+
region = format_region(region, module, EnableOldDomain, EnableInternalDomain)
233+
if EnableOldDomain:
234+
return u"{region}.myqcloud.com".format(region=region)
235+
else:
236+
return u"{region}.tencentcos.cn".format(region=region)
234237
else:
235238
return None
236239

237240

238-
def format_region(region, module=u'cos.'):
241+
def format_region(region, module, EnableOldDomain, EnableInternalDomain):
239242
"""格式化地域"""
240243
if not isinstance(region, string_types):
241244
raise CosClientError("region is not string type")
@@ -249,24 +252,29 @@ def format_region(region, module=u'cos.'):
249252
if region == u'cn-north' or region == u'cn-south' or region == u'cn-east' or region == u'cn-south-2' or region == u'cn-southwest' or region == u'sg':
250253
return region # 老域名不能加cos.
251254
# 支持v4域名映射到v5
255+
256+
# 转换为内部域名 (只有新域名才支持内部域名)
257+
if not EnableOldDomain and EnableInternalDomain and module == u'cos.':
258+
module = u'cos-internal.'
259+
252260
if region == u'cossh':
253-
return u'cos.ap-shanghai'
261+
return module + u'ap-shanghai'
254262
if region == u'cosgz':
255-
return u'cos.ap-guangzhou'
263+
return module + u'ap-guangzhou'
256264
if region == 'cosbj':
257-
return u'cos.ap-beijing'
265+
return module + u'ap-beijing'
258266
if region == 'costj':
259-
return u'cos.ap-beijing-1'
267+
return module + u'ap-beijing-1'
260268
if region == u'coscd':
261-
return u'cos.ap-chengdu'
269+
return module + u'ap-chengdu'
262270
if region == u'cossgp':
263-
return u'cos.ap-singapore'
271+
return module + u'ap-singapore'
264272
if region == u'coshk':
265-
return u'cos.ap-hongkong'
273+
return module + u'ap-hongkong'
266274
if region == u'cosca':
267-
return u'cos.na-toronto'
275+
return module + u'na-toronto'
268276
if region == u'cosger':
269-
return u'cos.eu-frankfurt'
277+
return module + u'eu-frankfurt'
270278

271279
return module + region # 新域名加上cos.
272280

@@ -306,7 +314,7 @@ def format_path(path):
306314
return path
307315

308316

309-
def get_copy_source_info(CopySource):
317+
def get_copy_source_info(CopySource, EnableOldDomain, EnableInternalDomain):
310318
"""获取拷贝源的所有信息"""
311319
appid = u""
312320
versionid = u""
@@ -323,7 +331,7 @@ def get_copy_source_info(CopySource):
323331
region = CopySource['Region']
324332
if 'Endpoint' in CopySource:
325333
endpoint = CopySource['Endpoint']
326-
endpoint = format_endpoint(endpoint, region)
334+
endpoint = format_endpoint(endpoint, region, u'cos.', EnableOldDomain, EnableInternalDomain)
327335
if 'Key' in CopySource:
328336
path = to_unicode(CopySource['Key'])
329337
if path and path[0] == '/':
@@ -335,9 +343,9 @@ def get_copy_source_info(CopySource):
335343
return bucket, path, endpoint, versionid
336344

337345

338-
def gen_copy_source_url(CopySource):
346+
def gen_copy_source_url(CopySource, EnableOldDomain, EnableInternalDomain):
339347
"""拼接拷贝源url"""
340-
bucket, path, endpoint, versionid = get_copy_source_info(CopySource)
348+
bucket, path, endpoint, versionid = get_copy_source_info(CopySource, EnableOldDomain, EnableInternalDomain)
341349
path = format_path(path)
342350
if versionid != u'':
343351
path = path + u'?versionId=' + versionid

qcloud_cos/cos_threadpool.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ def run(self):
3232
except Exception as e:
3333
logger.warn(str(e))
3434
self._fail_task_num += 1
35-
self._ret.append(e)
35+
if hasattr(e, '_message') and e._message:
36+
self._ret.append(e._message)
37+
elif hasattr(e, 'message') and e.message:
38+
self._ret.append(e.message)
39+
else:
40+
self._ret.append('meet some exception')
3641
finally:
3742
self._task_queue.task_done()
3843

qcloud_cos/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '5.1.9.15'
1+
__version__ = '5.1.9.16'

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def long_description():
1616

1717
setup(
1818
name='cos-python-sdk-v5',
19-
version='1.9.15',
19+
version='1.9.16',
2020
url='https://www.qcloud.com/',
2121
license='MIT',
2222
author='tiedu, lewzylu, channingliu',

ut/test.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,10 @@ def test_use_get_auth():
788788
Key='test.txt',
789789
Params={'acl': '', 'unsed': '123'}
790790
)
791-
url = 'http://' + test_bucket + '.cos.' + REGION + '.myqcloud.com/test.txt?acl&unsed=123'
791+
if conf._enable_old_domain:
792+
url = 'http://' + test_bucket + '.cos.' + REGION + '.myqcloud.com/test.txt?acl&unsed=123'
793+
else:
794+
url = 'http://' + test_bucket + '.cos.' + REGION + '.tencentcos.cn/test.txt?acl&unsed=123'
792795
response = requests.get(url, headers={'Authorization': auth})
793796
assert response.status_code == 200
794797

@@ -1681,7 +1684,7 @@ def test_ci_create_media_transcode_watermark_jobs():
16811684
'StartTime': '0',
16821685
'EndTime': '1000.5',
16831686
'Image': {
1684-
'Url': 'http://'+ci_bucket_name+".cos."+ci_region+".myqcloud.com/1215shuiyin.jpg",
1687+
'Url': 'http://'+ci_bucket_name+".cos."+ci_region+".tencentcos.cn/1215shuiyin.jpg",
16851688
'Mode': 'Fixed',
16861689
'Width': '128',
16871690
'Height': '128',

0 commit comments

Comments
 (0)