core.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. # -*- coding: utf-8 -*-
  2. import logging
  3. import os
  4. import time
  5. try:
  6. from urllib import urlencode
  7. from urlparse import urlparse
  8. except ImportError:
  9. from urllib.parse import urlencode, urlparse
  10. from Tea.vendored.requests import Request, Session, status_codes
  11. from Tea.converter import TeaConverter
  12. from Tea.exceptions import TeaException, RequiredArgumentException
  13. from Tea.model import TeaModel
  14. from Tea.response import TeaResponse
  15. DEFAULT_CONNECT_TIMEOUT = 5000
  16. DEFAULT_READ_TIMEOUT = 10000
  17. logger = logging.getLogger('alibabacloud-tea')
  18. logger.setLevel(logging.DEBUG)
  19. ch = logging.StreamHandler()
  20. logger.addHandler(ch)
  21. class TeaCore(object):
  22. @staticmethod
  23. def _prepare_http_debug(request, symbol):
  24. base = ''
  25. for key, value in request.headers.items():
  26. base += '\n%s %s : %s' % (symbol, key, value)
  27. return base
  28. @staticmethod
  29. def _do_http_debug(request, response):
  30. # logger the request
  31. url = urlparse(request.url)
  32. request_base = '\n> %s %s HTTP/1.1' % (request.method.upper(), url.path + url.query)
  33. logger.debug(request_base + TeaCore._prepare_http_debug(request, '>'))
  34. # logger the response
  35. response_base = '\n< HTTP/1.1 %s %s' % (
  36. response.status_code,
  37. status_codes._codes.get(response.status_code)[0].upper()
  38. )
  39. logger.debug(response_base + TeaCore._prepare_http_debug(response, '<'))
  40. @staticmethod
  41. def compose_url(request):
  42. host = TeaConverter.to_str(request.headers.get('host'))
  43. if not host:
  44. raise RequiredArgumentException('endpoint')
  45. else:
  46. host = host.rstrip('/')
  47. protocol = '%s://' % request.protocol.lower()
  48. pathname = request.pathname
  49. if host.startswith(('http://', 'https://')):
  50. protocol = ''
  51. if request.port == 80:
  52. port = ''
  53. else:
  54. port = ':%s' % request.port
  55. url = protocol + host + port + pathname
  56. if request.query:
  57. if "?" in url:
  58. if not url.endswith("&"):
  59. url += "&"
  60. else:
  61. url += "?"
  62. encode_query = {}
  63. for key in request.query:
  64. value = request.query[key]
  65. if value is not None:
  66. encode_query[key] = TeaConverter.to_str(value)
  67. url += urlencode(encode_query)
  68. return url.rstrip("?&")
  69. @staticmethod
  70. def do_action(request, runtime_option=None):
  71. url = TeaCore.compose_url(request)
  72. runtime_option = runtime_option or {}
  73. verify = not runtime_option.get('ignoreSSL', False)
  74. if verify:
  75. verify = runtime_option.get('ca', True) if runtime_option.get('ca', True) is not None else True
  76. cert = runtime_option.get('cert', None)
  77. connect_timeout = runtime_option.get('connectTimeout')
  78. connect_timeout = connect_timeout if connect_timeout else DEFAULT_CONNECT_TIMEOUT
  79. read_timeout = runtime_option.get('readTimeout')
  80. read_timeout = read_timeout if read_timeout else DEFAULT_READ_TIMEOUT
  81. timeout = (int(connect_timeout) / 1000, int(read_timeout) / 1000)
  82. with Session() as s:
  83. req = Request(method=request.method, url=url,
  84. data=request.body, headers=request.headers)
  85. prepped = s.prepare_request(req)
  86. proxies = {}
  87. http_proxy = runtime_option.get('httpProxy')
  88. https_proxy = runtime_option.get('httpsProxy')
  89. no_proxy = runtime_option.get('noProxy')
  90. if not http_proxy:
  91. http_proxy = os.environ.get('HTTP_PROXY') or os.environ.get('http_proxy')
  92. if not https_proxy:
  93. https_proxy = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy')
  94. if http_proxy:
  95. proxies['http'] = http_proxy
  96. if https_proxy:
  97. proxies['https'] = https_proxy
  98. if no_proxy:
  99. proxies['no_proxy'] = no_proxy
  100. resp = s.send(
  101. prepped,
  102. proxies=proxies,
  103. timeout=timeout,
  104. verify=verify,
  105. cert=cert,
  106. )
  107. debug = runtime_option.get('debug') or os.getenv('DEBUG')
  108. if debug and debug.lower() == 'sdk':
  109. TeaCore._do_http_debug(req, resp)
  110. response = TeaResponse()
  111. response.status_message = resp.reason
  112. response.status_code = resp.status_code
  113. response.headers = {k.lower(): v for k, v in resp.headers.items()}
  114. response.body = resp.content
  115. response.response = resp
  116. return response
  117. @staticmethod
  118. def get_response_body(resp):
  119. return resp.content.decode("utf-8")
  120. @staticmethod
  121. def allow_retry(dic, retry_times, now=None):
  122. if dic is None or not dic.__contains__("maxAttempts"):
  123. return False
  124. else:
  125. retry = 0 if dic.get("maxAttempts") is None else int(
  126. dic.get("maxAttempts"))
  127. return retry >= retry_times
  128. @staticmethod
  129. def get_backoff_time(dic, retry_times):
  130. default_back_off_time = 0
  131. if dic is None or not dic.get("policy") or dic.get("policy") == "no":
  132. return default_back_off_time
  133. back_off_time = dic.get('period', default_back_off_time)
  134. if not isinstance(back_off_time, int) and \
  135. not (isinstance(back_off_time, str) and back_off_time.isdigit()):
  136. return default_back_off_time
  137. back_off_time = int(back_off_time)
  138. if back_off_time < 0:
  139. return retry_times
  140. return back_off_time
  141. @staticmethod
  142. def sleep(t):
  143. time.sleep(t)
  144. @staticmethod
  145. def is_retryable(ex):
  146. return isinstance(ex, TeaException)
  147. @staticmethod
  148. def bytes_readable(body):
  149. return body
  150. @staticmethod
  151. def merge(*dic_list):
  152. dic_result = {}
  153. for item in dic_list:
  154. if isinstance(item, dict):
  155. dic_result.update(item)
  156. elif isinstance(item, TeaModel):
  157. dic_result.update(item.to_map())
  158. return dic_result
  159. @staticmethod
  160. def to_map(model):
  161. if isinstance(model, TeaModel):
  162. return model.to_map()
  163. else:
  164. return dict()
  165. @staticmethod
  166. def from_map(model, dic):
  167. if isinstance(model, TeaModel):
  168. return model.from_map(dic)
  169. else:
  170. return model