Skip to content

Commit efdd2e2

Browse files
authored
Refactor2.haowei (aliyun#229)
* add more logics * add retry logic
1 parent df78fb5 commit efdd2e2

File tree

16 files changed

+260
-137
lines changed

16 files changed

+260
-137
lines changed

aliyun-python-sdk-core/alibabacloud/client.py

Lines changed: 81 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import os
15+
import time
16+
from alibabacloud.handlers import RequestContext
1517

1618
DEFAULT_HANDLERS = [
1719
HttpHeaderHandler, # 获取请求头
@@ -25,19 +27,24 @@
2527
]
2628

2729
DEFAULT_FORMAT = 'JSON'
28-
29-
from alibabacloud.handlers import RequestContext
30+
DEFAULT_ENABLE_RETRY_POLICY = True
31+
DEFAULT_MAX_RETRY_TIMES = 3
32+
DEFAULT_CONNECTION_TIMEOUT = 5
33+
DEFAULT_READ_TIMEOUT = 10
34+
DEFAULT_ENABLE_HTTP_DEBUG = False
35+
DEFAULT_ENABLE_HTTPS = False
3036

3137

3238
class ClientConfig:
3339
"""
3440
处理client级别的所有的参数
3541
"""
42+
3643
def __init__(self, access_key_id=None, access_key_secret=None, region_id=None,
37-
enable_retry_policy=True, max_retry_times=None, user_agent=None,
38-
extra_user_agent=None, enable_https=True, http_port=None, https_port=None,
39-
connection_timeout=None, read_timeout=None, accept_format=DEFAULT_FORMAT,
40-
specific_signer=None):
44+
enable_retry_policy=None, max_retry_times=None, user_agent=None,
45+
extra_user_agent=None, enable_https=None, http_port=None, https_port=None,
46+
connection_timeout=None, read_timeout=None, enable_http_debug=None,
47+
http_proxy=None, https_proxy=None, enable_stream_logger=None):
4148

4249
self.access_key_id = access_key_id
4350
self.access_key_secret = access_key_secret
@@ -51,64 +58,81 @@ def __init__(self, access_key_id=None, access_key_secret=None, region_id=None,
5158
self.https_port = https_port
5259
self.connection_timeout = connection_timeout
5360
self.read_timeout = read_timeout
54-
self.timeout = (connection_timeout, read_timeout)
55-
# yan 添加的
56-
self.accept_format = accept_format
57-
self.specific_signer = specific_signer
61+
self._timeout = (self.connection_timeout, self.read_timeout)
62+
self.enable_http_debug = enable_http_debug
63+
self.http_proxy = http_proxy
64+
self.https_proxy = https_proxy
65+
self.enable_stream_logger = enable_stream_logger
66+
67+
def read_from_env(self):
68+
69+
def _set_env_to_config(config_name, env_name):
70+
71+
env_value = os.environ.get(env_name)
72+
if env_value is not None:
73+
setattr(self, key, os.environ.get(env_value))
5874

59-
self.http_debug = os.environ.get('DEBUG') or os.environ.get('debug')
60-
self.proxy_https = os.environ.get('HTTPS_PROXY') or os.environ.get(
61-
'https_proxy')
62-
self.proxy_http = os.environ.get(
63-
'HTTP_PROXY') or os.environ.get('http_proxy')
64-
# 用户硬编码传参、环境变量、读配置文件的获取参数的方式
65-
# TODO assign more attributes
75+
if config_name == 'enable_http_debug':
76+
# FIXME recursive calls will be indefinite
77+
_set_env_to_config(config_name, 'HTTP_DEBUG')
78+
_set_env_to_config(config_name, 'http_debug')
79+
elif config_name == 'https_proxy':
80+
_set_env_to_config(config_name, 'HTTPS_PROXY')
81+
_set_env_to_config(config_name, 'https_proxy')
82+
elif config_name == 'http_proxy':
83+
_set_env_to_config(config_name, 'HTTP_PROXY')
84+
_set_env_to_config(config_name, 'http_proxy')
85+
86+
for key in dir(self):
87+
# FIXME make sure we get only configuration members here, not functions & internal
88+
# variables
89+
if getattr(self, key) is None:
90+
env_name = 'ALIBABA_CLOUD_' + key.upper()
91+
_set_env_to_config(key, env_name)
92+
93+
def read_from_profile(self):
94+
# TODO read from profile
95+
pass
96+
97+
def read_from_default(self):
98+
pass
99+
100+
101+
def get_merged_client_config(config):
102+
config.read_from_env()
103+
config.read_from_profile()
104+
config.read_from_default()
105+
return config
66106

67107

68108
class AlibabaCloudClient:
69109

70110
def __init__(self, client_config, credentials_provider):
71-
self.config = client_config
111+
self.config = get_merged_client_config(client_config)
72112
self.credentials_provider = credentials_provider
73113
self.handlers = []
114+
self.endpoint_resolver = None # TODO initialize
115+
self.logger = None # TODO initialize
74116

75-
def handle_request(self, request):
117+
def handle_request(self, api_request, request_handlers=None, context=None):
76118
# TODO handle different types of request
77-
prepare_request = PreparedRequest(request) # 对request层面进行的语法封装
78-
context = RequestContext()
79-
context.request = prepare_request
80-
context.config = self.config
81-
82-
for handler in self.handlers:
83-
# 所有的一系列handler实际是组装参数,获取endpoint等等的数据
84-
if hasattr(handler, 'handle_request'):
85-
result = handler.handle_request(context)
86-
if result is not None:
87-
return result
88-
http_request = context.http_request
89-
90-
# 应该返回原始的response,对error进行的处理
91-
try:
92-
response = http_request.get_response_object()
93-
except IOError as e:
94-
exception = ClientException(error_code.SDK_HTTP_ERROR, str(e))
95-
return None, None, None, exception
96-
97-
response_flag = True
98-
# 对返回结果进行一层 exceptions 的校验
99-
for handler in reversed(self.handlers):
100-
if hasattr(handler, 'handle_exceptions'):
101-
result = handler.handle_exceptions(response)
102-
# TODO : result 有值,说明是ServerExceptions 下面的不走了
103-
if request is not None:
104-
response_flag = False
105-
return result
106-
107-
# 对response 进行的一层处理,原本是response对象
108-
if response_flag:
109-
for handler in reversed(self.handlers):
110-
if hasattr(handler, 'handle_response'):
111-
result = handler.handle_response(response)
112-
return result
113-
114-
119+
if not context:
120+
context = RequestContext()
121+
context.api_request = api_request
122+
context.config = self.config
123+
124+
if not request_handlers:
125+
request_handlers = self.handlers
126+
127+
for i in range(len(request_handlers)):
128+
request_handlers[i].handle_request(context)
129+
130+
for i in reversed(range(len(request_handlers))):
131+
request_handlers[i].handle_response(context)
132+
if context.retry_flag:
133+
time.sleep(context.retry_backoff)
134+
self.handle_request(api_request,
135+
request_handlers=request_handlers[i:],
136+
context=context)
137+
138+
return context.result
Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,45 @@
1+
# Copyright 2019 Alibaba Cloud Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
class AlibabaCloudCredentials:
17+
18+
def __init__(self):
19+
self.access_key_id = None
20+
self.access_key_secret = None
21+
self.security_token = None
22+
self.bearer_token = None
23+
24+
125
# credentials
2-
class AccessKeyCredentials:
26+
class AccessKeyCredentials(AlibabaCloudCredentials):
27+
328
def __init__(self, access_key_id, access_key_secret):
29+
AlibabaCloudCredentials.__init__(self)
430
self.access_key_id = access_key_id
531
self.access_key_secret = access_key_secret
632

733

8-
class BearTokenCredentials:
34+
class BearTokenCredentials(AlibabaCloudCredentials):
935
def __init__(self, bearer_token):
36+
AlibabaCloudCredentials.__init__(self)
1037
self.bearer_token = bearer_token
1138

1239

13-
class SecurityCredentials:
14-
def __init__(self, access_key_id, access_key_secret, token):
40+
class SecurityCredentials(AlibabaCloudCredentials):
41+
def __init__(self, access_key_id, access_key_secret, security_token):
42+
AlibabaCloudCredentials.__init__(self)
1543
self.access_key_id = access_key_id
1644
self.access_key_secret = access_key_secret
17-
self.token = token
45+
self.security_token = security_token

aliyun-python-sdk-core/alibabacloud/credentials/credentials_provider.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,10 @@ def load_credentials(self):
267267

268268

269269
class CredentialsProvider(object):
270-
@staticmethod
271-
def load():
272-
return True
270+
271+
# if no credentials got, return None
272+
def load(self):
273+
return None
273274

274275

275276
class UserProvider(CredentialsProvider):

aliyun-python-sdk-core/alibabacloud/handlers/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@
1414

1515

1616
class RequestContext:
17-
pass
17+
18+
def __init__(self):
19+
self.api_request = None
20+
self.http_request = None
21+
self.api_response = None
22+
self.http_response = None
23+
self.retry_flag = False
24+
self.retry_backoff = 0
1825

1926

2027
class RequestHandler:

aliyun-python-sdk-core/alibabacloud/handlers/endpoint_handler.py

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,19 @@
1313
# limitations under the License.
1414

1515
from alibabacloud.handlers import RequestHandler
16+
from alibabacloud.endpoint.resolver_endpoint_request import ResolveEndpointRequest
1617

1718

1819
class EndpointHandler(RequestHandler):
1920

20-
resolve_request_cls = ResolveEndpointRequest
21-
# TODO client 内部仅仅是再次发送了一次请求,可以再次的优化这个方法
22-
resolve_endpoint_cls = DefaultEndpointResolver(client)
23-
2421
def handle_request(self, context):
25-
request = context.request
26-
if request.endpoint:
27-
context.endpoint = request.endpoint
28-
else:
29-
context.endpoint = self.resolve_endpoint(context.confi8g.region_id, request)
22+
resolve_request = ResolveEndpointRequest(
23+
context.config.region_id,
24+
context.client.product_code,
25+
context.client.location_service_code,
26+
context.client.location_service_type,
27+
)
28+
context.endpoint = context.client.endpoint_resolver.resolve(resolve_request)
3029

3130
def handle_response(self, response):
3231
pass
33-
34-
def resolve_endpoint(self, region_id, request):
35-
resolve_request = self.resolve_request_cls(
36-
region_id,
37-
request.get_product(),
38-
request.get_location_service_code(),
39-
request.get_location_endpoint_type(),
40-
)
41-
return self.resolve_endpoint_cls.resolve(resolve_request)

aliyun-python-sdk-core/alibabacloud/handlers/http_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ def handle_request(self, context):
2929
http_request.set_content(body, "utf-8", 'application/x-www-form-urlencoded')
3030
context.http_request = http_request
3131

32-
def handle_response(self, request, response):
32+
def handle_response(self, context):
3333
pass
3434

0 commit comments

Comments
 (0)