core.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. import asyncio
  2. import aiohttp
  3. import logging
  4. import io
  5. import os
  6. import ssl
  7. import time
  8. import re
  9. import certifi
  10. import json
  11. from requests import status_codes, adapters, PreparedRequest
  12. from typing import Any, Dict, Optional, Union
  13. from enum import Enum
  14. from urllib.parse import urlencode, urlparse
  15. from requests import status_codes, adapters, PreparedRequest, Session
  16. from darabonba.exceptions import RequiredArgumentException, RetryError
  17. from darabonba.model import DaraModel
  18. from darabonba.request import DaraRequest
  19. from darabonba.response import DaraResponse
  20. from darabonba.utils.stream import BaseStream, SSEResponseWrapper, SyncSSEResponseWrapper
  21. from darabonba.policy.retry import RetryOptions, RetryPolicyContext
  22. DEFAULT_CONNECT_TIMEOUT = 5000
  23. DEFAULT_READ_TIMEOUT = 10000
  24. DEFAULT_POOL_SIZE = 10
  25. MAX_DELAY_TIME = 120 * 1000
  26. MIN_DELAY_TIME = 100
  27. logger = logging.getLogger('darabonba-core')
  28. logger.setLevel(logging.DEBUG)
  29. ch = logging.StreamHandler()
  30. logger.addHandler(ch)
  31. class _ModelEncoder(json.JSONEncoder):
  32. def default(self, o: Any) -> Any:
  33. if isinstance(o, DaraModel):
  34. return o.to_map()
  35. elif isinstance(o, bytes):
  36. return o.decode('utf-8')
  37. super().default(o)
  38. class TLSVersion(Enum):
  39. TLSv1 = 'TLSv1'
  40. TLSv1_1 = 'TLSv1.1'
  41. TLSv1_2 = 'TLSv1.2'
  42. TLSv1_3 = 'TLSv1.3'
  43. class _TLSAdapter(adapters.HTTPAdapter):
  44. """A HTTPAdapter that uses an arbitrary TLS version."""
  45. def __init__(self, ssl_context=None, **kwargs):
  46. self.ssl_context = ssl_context
  47. super().__init__(**kwargs)
  48. def init_poolmanager(self, *args, **kwargs):
  49. """Override the init_poolmanager method to set the SSL."""
  50. kwargs['ssl_context'] = self.ssl_context
  51. super().init_poolmanager(*args, **kwargs)
  52. class DaraCore:
  53. _sessions = {}
  54. http_adapter = adapters.HTTPAdapter(pool_connections=DEFAULT_POOL_SIZE, pool_maxsize=DEFAULT_POOL_SIZE * 4)
  55. https_adapter = adapters.HTTPAdapter(pool_connections=DEFAULT_POOL_SIZE, pool_maxsize=DEFAULT_POOL_SIZE * 4)
  56. @staticmethod
  57. def to_json_string(
  58. val: Any,
  59. ) -> str:
  60. """
  61. Stringify a value by JSON format
  62. @return: the JSON format string
  63. """
  64. if isinstance(val, str):
  65. return str(val)
  66. return json.dumps(
  67. val, cls=_ModelEncoder, ensure_ascii=False, separators=(",", ":")
  68. )
  69. @staticmethod
  70. def _set_tls_minimum_version(sls_context, tls_min_version):
  71. context = sls_context
  72. if tls_min_version is not None:
  73. if tls_min_version == 'TLSv1':
  74. context.minimum_version = ssl.TLSVersion.TLSv1
  75. elif tls_min_version == 'TLSv1.1':
  76. context.minimum_version = ssl.TLSVersion.TLSv1_1
  77. elif tls_min_version == 'TLSv1.2':
  78. context.minimum_version = ssl.TLSVersion.TLSv1_2
  79. elif tls_min_version == 'TLSv1.3':
  80. context.minimum_version = ssl.TLSVersion.TLSv1_3
  81. return context
  82. @staticmethod
  83. def get_adapter(prefix, tls_min_version: str = None):
  84. ca_cert = certifi.where()
  85. context = ssl.create_default_context()
  86. if ca_cert and prefix.upper() == 'HTTPS':
  87. context = DaraCore._set_tls_minimum_version(context, tls_min_version)
  88. context.load_verify_locations(ca_cert)
  89. adapter = _TLSAdapter(ssl_context=context, pool_connections=DEFAULT_POOL_SIZE,
  90. pool_maxsize=DEFAULT_POOL_SIZE * 4)
  91. return adapter
  92. @staticmethod
  93. def _prepare_http_debug(request, symbol):
  94. base = ''
  95. for key, value in request.headers.items():
  96. base += f'\n{symbol} {key} : {value}'
  97. return base
  98. @staticmethod
  99. def _do_http_debug(request, response):
  100. # logger the request
  101. url = urlparse(request.url)
  102. request_base = f'\n> {request.method.upper()} {url.path + url.query} HTTP/1.1'
  103. logger.debug(request_base + DaraCore._prepare_http_debug(request, '>'))
  104. # logger the response
  105. response_base = f'\n< HTTP/1.1 {response.status_code}' \
  106. f' {status_codes._codes.get(response.status_code)[0].upper()}'
  107. logger.debug(response_base + DaraCore._prepare_http_debug(response, '<'))
  108. @staticmethod
  109. def compose_url(request):
  110. host = request.headers.get('host')
  111. if not host:
  112. raise RequiredArgumentException('endpoint')
  113. else:
  114. host = host.rstrip('/')
  115. protocol = f'{request.protocol.lower()}://'
  116. pathname = request.pathname
  117. if host.startswith(('http://', 'https://')):
  118. protocol = ''
  119. if request.port == 80:
  120. port = ''
  121. else:
  122. port = f':{request.port}'
  123. url = protocol + host + port + pathname
  124. if request.query:
  125. if "?" in url:
  126. if not url.endswith("&"):
  127. url += "&"
  128. else:
  129. url += "?"
  130. encode_query = {}
  131. for key in request.query:
  132. value = request.query[key]
  133. if value is not None:
  134. encode_query[key] = str(value)
  135. url += urlencode(encode_query)
  136. return url.rstrip("?&")
  137. @staticmethod
  138. async def async_do_action(
  139. request: DaraRequest,
  140. runtime_option=None
  141. ) -> DaraResponse:
  142. runtime_option = runtime_option or {}
  143. url = DaraCore.compose_url(request)
  144. ignore_ssl = runtime_option.get('ignoreSSL', False)
  145. verify: Union[bool, str] = not ignore_ssl
  146. tls_min_version = runtime_option.get('tlsMinVersion')
  147. if isinstance(tls_min_version, Enum):
  148. tls_min_version = tls_min_version.value
  149. if verify:
  150. ca = runtime_option.get('ca')
  151. if ca is not None:
  152. verify = ca
  153. cert = runtime_option.get('cert', None)
  154. timeout = runtime_option.get('timeout')
  155. connect_timeout = runtime_option.get('connectTimeout') or timeout or DEFAULT_CONNECT_TIMEOUT
  156. read_timeout = runtime_option.get('readTimeout') or timeout or DEFAULT_READ_TIMEOUT
  157. connect_timeout, read_timeout = (int(connect_timeout) / 1000, int(read_timeout) / 1000)
  158. proxy = None
  159. if request.protocol.upper() == 'HTTP':
  160. proxy = runtime_option.get('httpProxy')
  161. if not proxy:
  162. proxy = os.environ.get('HTTP_PROXY') or os.environ.get('http_proxy')
  163. elif request.protocol.upper() == 'HTTPS':
  164. proxy = runtime_option.get('httpsProxy')
  165. if not proxy:
  166. proxy = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy')
  167. connector = None
  168. ca_cert = certifi.where()
  169. ssl_context = None
  170. if isinstance(verify, str) and request.protocol.upper() == 'HTTPS':
  171. ssl_context = ssl.create_default_context()
  172. ssl_context = DaraCore._set_tls_minimum_version(ssl_context, tls_min_version)
  173. ssl_context.load_verify_locations(verify)
  174. # Handle cert if provided
  175. if cert is not None:
  176. if isinstance(cert, (list, tuple)):
  177. ssl_context.load_cert_chain(certfile=cert[0], keyfile=cert[1] if len(cert) > 1 else None)
  178. else:
  179. ssl_context.load_cert_chain(certfile=cert, keyfile=None)
  180. connector = aiohttp.TCPConnector(ssl=ssl_context)
  181. elif ca_cert and request.protocol.upper() == 'HTTPS' and verify:
  182. ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
  183. ssl_context = DaraCore._set_tls_minimum_version(ssl_context, tls_min_version)
  184. ssl_context.load_verify_locations(ca_cert)
  185. # Handle cert if provided
  186. if cert is not None:
  187. if isinstance(cert, (list, tuple)):
  188. ssl_context.load_cert_chain(certfile=cert[0], keyfile=cert[1] if len(cert) > 1 else None)
  189. else:
  190. ssl_context.load_cert_chain(certfile=cert, keyfile=None)
  191. connector = aiohttp.TCPConnector(ssl=ssl_context)
  192. else:
  193. verify = False
  194. timeout = aiohttp.ClientTimeout(
  195. sock_read=read_timeout,
  196. sock_connect=connect_timeout
  197. )
  198. async with aiohttp.ClientSession(
  199. connector=connector
  200. ) as s:
  201. body = b''
  202. if isinstance(request.body, BaseStream):
  203. for content in request.body:
  204. body += content
  205. elif isinstance(request.body, str):
  206. body = request.body.encode('utf-8')
  207. else:
  208. body = request.body or b''
  209. try:
  210. ssl_param: Union[bool, ssl.SSLContext] = ssl_context if ssl_context is not None else bool(verify)
  211. async with s.request(request.method, url,
  212. data=body,
  213. headers=request.headers,
  214. ssl=ssl_param,
  215. proxy=proxy,
  216. timeout=timeout) as response:
  217. tea_resp: DaraResponse = DaraResponse()
  218. tea_resp.body = await response.read()
  219. tea_resp.headers = dict({k.lower(): v for k, v in response.headers.items()})
  220. tea_resp.status_code = response.status
  221. tea_resp.status_message = response.reason
  222. tea_resp.response = response
  223. except IOError as e:
  224. raise RetryError(str(e))
  225. return tea_resp
  226. @staticmethod
  227. def do_action(
  228. request: DaraRequest,
  229. runtime_option=None
  230. ) -> DaraResponse:
  231. url = DaraCore.compose_url(request)
  232. runtime_option = runtime_option or {}
  233. verify = not runtime_option.get('ignoreSSL', False)
  234. tls_min_version = runtime_option.get('tlsMinVersion')
  235. if isinstance(tls_min_version, Enum):
  236. tls_min_version = tls_min_version.value
  237. if verify:
  238. verify = runtime_option.get('ca', True) if runtime_option.get('ca', True) is not None else True
  239. cert = runtime_option.get('cert', None)
  240. timeout = runtime_option.get('timeout')
  241. connect_timeout = runtime_option.get('connectTimeout') or timeout or DEFAULT_CONNECT_TIMEOUT
  242. read_timeout = runtime_option.get('readTimeout') or timeout or DEFAULT_READ_TIMEOUT
  243. timeout = (int(connect_timeout) / 1000, int(read_timeout) / 1000)
  244. if isinstance(request.body, str):
  245. request.body = request.body.encode('utf-8')
  246. p = PreparedRequest()
  247. p.prepare(
  248. method=request.method.upper(),
  249. url=url,
  250. data=request.body,
  251. headers=request.headers,
  252. )
  253. proxies = {}
  254. http_proxy = runtime_option.get('httpProxy')
  255. https_proxy = runtime_option.get('httpsProxy')
  256. no_proxy = runtime_option.get('noProxy')
  257. if not http_proxy:
  258. http_proxy = os.environ.get('HTTP_PROXY') or os.environ.get('http_proxy')
  259. if not https_proxy:
  260. https_proxy = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy')
  261. if http_proxy:
  262. proxies['http'] = http_proxy
  263. if https_proxy:
  264. proxies['https'] = https_proxy
  265. if no_proxy:
  266. proxies['no_proxy'] = no_proxy
  267. host = request.headers.get('host')
  268. host = host.rstrip('/')
  269. session_key = f'{request.protocol.lower()}://{host}:{request.port}'
  270. session = DaraCore._get_session(session_key=session_key, protocol=request.protocol,
  271. tls_min_version=tls_min_version, verify=verify)
  272. try:
  273. resp = session.send(
  274. p,
  275. proxies=proxies,
  276. timeout=timeout,
  277. verify=verify,
  278. cert=cert,
  279. )
  280. except IOError as e:
  281. raise RetryError(str(e))
  282. debug = runtime_option.get('debug') or os.getenv('DEBUG')
  283. if debug and debug.lower() == 'sdk':
  284. DaraCore._do_http_debug(p, resp)
  285. response = DaraResponse()
  286. response.status_message = resp.reason
  287. response.status_code = resp.status_code
  288. response.headers = {k.lower(): v for k, v in resp.headers.items()}
  289. response.body = resp.content
  290. response.response = resp
  291. return response
  292. @staticmethod
  293. async def async_do_sse_action(
  294. request: DaraRequest,
  295. runtime_option=None
  296. ) -> DaraResponse:
  297. runtime_option = runtime_option or {}
  298. url = DaraCore.compose_url(request)
  299. ignore_ssl = runtime_option.get('ignoreSSL', False)
  300. verify: Union[bool, str] = not ignore_ssl
  301. tls_min_version = runtime_option.get('tlsMinVersion')
  302. if isinstance(tls_min_version, Enum):
  303. tls_min_version = tls_min_version.value
  304. if verify:
  305. ca = runtime_option.get('ca')
  306. if ca is not None:
  307. verify = ca
  308. cert = runtime_option.get('cert', None)
  309. timeout = runtime_option.get('timeout')
  310. connect_timeout = runtime_option.get('connectTimeout') or timeout or DEFAULT_CONNECT_TIMEOUT
  311. read_timeout = runtime_option.get('readTimeout') or timeout or DEFAULT_READ_TIMEOUT
  312. connect_timeout, read_timeout = (int(connect_timeout) / 1000, int(read_timeout) / 1000)
  313. proxy = None
  314. if request.protocol.upper() == 'HTTP':
  315. proxy = runtime_option.get('httpProxy')
  316. if not proxy:
  317. proxy = os.environ.get('HTTP_PROXY') or os.environ.get('http_proxy')
  318. elif request.protocol.upper() == 'HTTPS':
  319. proxy = runtime_option.get('httpsProxy')
  320. if not proxy:
  321. proxy = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy')
  322. connector = None
  323. ca_cert = certifi.where()
  324. ssl_context = None
  325. if isinstance(verify, str) and request.protocol.upper() == 'HTTPS':
  326. ssl_context = ssl.create_default_context()
  327. ssl_context = DaraCore._set_tls_minimum_version(ssl_context, tls_min_version)
  328. ssl_context.load_verify_locations(verify)
  329. # Handle cert if provided
  330. if cert is not None:
  331. if isinstance(cert, (list, tuple)):
  332. ssl_context.load_cert_chain(certfile=cert[0], keyfile=cert[1] if len(cert) > 1 else None)
  333. else:
  334. ssl_context.load_cert_chain(certfile=cert, keyfile=None)
  335. connector = aiohttp.TCPConnector(ssl=ssl_context)
  336. elif ca_cert and request.protocol.upper() == 'HTTPS' and verify:
  337. ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
  338. ssl_context = DaraCore._set_tls_minimum_version(ssl_context, tls_min_version)
  339. ssl_context.load_verify_locations(ca_cert)
  340. # Handle cert if provided
  341. if cert is not None:
  342. if isinstance(cert, (list, tuple)):
  343. ssl_context.load_cert_chain(certfile=cert[0], keyfile=cert[1] if len(cert) > 1 else None)
  344. else:
  345. ssl_context.load_cert_chain(certfile=cert, keyfile=None)
  346. connector = aiohttp.TCPConnector(ssl=ssl_context)
  347. else:
  348. verify = False
  349. timeout = aiohttp.ClientTimeout(
  350. sock_read=read_timeout,
  351. sock_connect=connect_timeout
  352. )
  353. session = aiohttp.ClientSession(connector=connector)
  354. body = b''
  355. if isinstance(request.body, BaseStream):
  356. for content in request.body:
  357. body += content
  358. elif isinstance(request.body, str):
  359. body = request.body.encode('utf-8')
  360. else:
  361. body = request.body or b''
  362. try:
  363. headers = request.headers.copy()
  364. ssl_param: Union[bool, ssl.SSLContext] = ssl_context if ssl_context is not None else bool(verify)
  365. response = await session.request(
  366. request.method,
  367. url,
  368. data=body,
  369. headers=headers,
  370. ssl=ssl_param,
  371. proxy=proxy,
  372. timeout=timeout
  373. )
  374. tea_resp: DaraResponse = DaraResponse()
  375. tea_resp.status_code = response.status
  376. tea_resp.status_message = response.reason
  377. tea_resp.headers = dict({k.lower(): v for k, v in response.headers.items()})
  378. tea_resp.body = SSEResponseWrapper(session, response)
  379. return tea_resp
  380. except IOError as e:
  381. await session.close()
  382. raise RetryError(str(e))
  383. @staticmethod
  384. def do_sse_action(
  385. request: DaraRequest,
  386. runtime_option=None
  387. ) -> DaraResponse:
  388. url = DaraCore.compose_url(request)
  389. runtime_option = runtime_option or {}
  390. verify = not runtime_option.get('ignoreSSL', False)
  391. tls_min_version = runtime_option.get('tlsMinVersion')
  392. if isinstance(tls_min_version, Enum):
  393. tls_min_version = tls_min_version.value
  394. if verify:
  395. verify = runtime_option.get('ca', True) if runtime_option.get('ca', True) is not None else True
  396. cert = runtime_option.get('cert', None)
  397. timeout = runtime_option.get('timeout')
  398. connect_timeout = runtime_option.get('connectTimeout') or timeout or DEFAULT_CONNECT_TIMEOUT
  399. read_timeout = runtime_option.get('readTimeout') or timeout or DEFAULT_READ_TIMEOUT
  400. timeout = (int(connect_timeout) / 1000, int(read_timeout) / 1000)
  401. if isinstance(request.body, str):
  402. request.body = request.body.encode('utf-8')
  403. p = PreparedRequest()
  404. p.prepare(
  405. method=request.method.upper(),
  406. url=url,
  407. data=request.body,
  408. headers=request.headers,
  409. )
  410. proxies = {}
  411. http_proxy = runtime_option.get('httpProxy')
  412. https_proxy = runtime_option.get('httpsProxy')
  413. no_proxy = runtime_option.get('noProxy')
  414. if not http_proxy:
  415. http_proxy = os.environ.get('HTTP_PROXY') or os.environ.get('http_proxy')
  416. if not https_proxy:
  417. https_proxy = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy')
  418. if http_proxy:
  419. proxies['http'] = http_proxy
  420. if https_proxy:
  421. proxies['https'] = https_proxy
  422. if no_proxy:
  423. proxies['no_proxy'] = no_proxy
  424. host = request.headers.get('host')
  425. host = host.rstrip('/') if host else ''
  426. session_key = f'{request.protocol.lower()}://{host}:{request.port}'
  427. session = DaraCore._get_session(session_key=session_key, protocol=request.protocol,
  428. tls_min_version=tls_min_version, verify=verify)
  429. try:
  430. resp = session.send(
  431. p,
  432. proxies=proxies,
  433. timeout=timeout,
  434. verify=verify,
  435. cert=cert,
  436. stream=True
  437. )
  438. except IOError as e:
  439. raise RetryError(str(e))
  440. debug = runtime_option.get('debug') or os.getenv('DEBUG')
  441. if debug and debug.lower() == 'sdk':
  442. DaraCore._do_http_debug(p, resp)
  443. response = DaraResponse()
  444. response.status_message = resp.reason
  445. response.status_code = resp.status_code
  446. response.headers = {k.lower(): v for k, v in resp.headers.items()}
  447. response.body = SyncSSEResponseWrapper(session, resp)
  448. return response
  449. @staticmethod
  450. def get_response_body(resp) -> str:
  451. return resp.content.decode("utf-8")
  452. @staticmethod
  453. def allow_retry(dic, retry_times, now=None) -> bool:
  454. if retry_times == 0:
  455. return True
  456. if dic is None or not dic.__contains__("maxAttempts") or \
  457. dic.get('retryable') is not True and retry_times >= 1:
  458. return False
  459. else:
  460. retry = 0 if dic.get("maxAttempts") is None else int(
  461. dic.get("maxAttempts"))
  462. return retry >= retry_times
  463. @staticmethod
  464. def should_retry(options: RetryOptions, ctx: RetryPolicyContext) -> bool:
  465. if ctx.retries_attempted == 0:
  466. return True
  467. if not options or not options.retryable:
  468. return False
  469. retries_attempted = ctx.retries_attempted
  470. ex = ctx.exception
  471. for condition in options.no_retry_condition:
  472. if getattr(ex, 'name', None) in condition.exception or getattr(ex, 'code', None) in condition.error_code:
  473. return False
  474. for condition in options.retry_condition:
  475. if getattr(ex, 'name', None) not in condition.exception and getattr(ex, 'code', None) not in condition.error_code:
  476. continue
  477. if retries_attempted >= condition.max_attempts:
  478. return False
  479. return True
  480. return False
  481. @staticmethod
  482. def get_backoff_time(options: RetryOptions, ctx: RetryPolicyContext) -> int:
  483. ex = ctx.exception
  484. conditions = options.retry_condition
  485. for condition in conditions:
  486. if getattr(ex, 'name', None) not in condition.exception and getattr(ex, 'code', None) not in condition.error_code:
  487. continue
  488. max_delay = condition.max_delay or MAX_DELAY_TIME
  489. retry_after = getattr(ctx.exception, "retry_after", None)
  490. if retry_after is not None:
  491. return min(retry_after, max_delay)
  492. if not condition.backoff:
  493. return MIN_DELAY_TIME
  494. return min(condition.backoff.get_delay_time(ctx), max_delay)
  495. return MIN_DELAY_TIME
  496. @staticmethod
  497. async def sleep_async(millisecond: int):
  498. await asyncio.sleep(millisecond / 1000)
  499. @staticmethod
  500. def sleep(millisecond: int):
  501. time.sleep(millisecond / 1000)
  502. @staticmethod
  503. def is_retryable(ex) -> bool:
  504. return isinstance(ex, RetryError)
  505. @staticmethod
  506. def bytes_readable(body):
  507. return body
  508. @staticmethod
  509. def merge(*dic_list) -> dict:
  510. dic_result = {}
  511. for item in dic_list:
  512. if isinstance(item, dict):
  513. dic_result.update(item)
  514. elif isinstance(item, DaraModel):
  515. dic_result.update(item.to_map())
  516. return dic_result
  517. @staticmethod
  518. def is_null(value) -> bool:
  519. return value is None
  520. @staticmethod
  521. def to_readable_stream(data):
  522. if isinstance(data, str):
  523. return io.StringIO(data)
  524. elif isinstance(data, bytes):
  525. return io.BytesIO(data)
  526. else:
  527. raise TypeError("Input data must be of type str or bytes")
  528. @staticmethod
  529. def to_map(model: Optional[DaraModel]) -> Dict[str, Any]:
  530. if isinstance(model, DaraModel):
  531. return model.to_map()
  532. else:
  533. return dict()
  534. @staticmethod
  535. def to_number(model) -> int:
  536. if isinstance(model, int):
  537. return model
  538. if isinstance(model, str):
  539. if model == "":
  540. return 0
  541. return int(model)
  542. if isinstance(model, float):
  543. return int(model)
  544. return 0
  545. @staticmethod
  546. def from_map(
  547. model: DaraModel,
  548. dic: Dict[str, Any]
  549. ) -> DaraModel:
  550. if isinstance(model, DaraModel):
  551. try:
  552. return model.from_map(dic)
  553. except Exception:
  554. model._map = dic
  555. return model
  556. else:
  557. return model
  558. @staticmethod
  559. def _get_session(session_key: str, protocol: str, tls_min_version: str = None, verify: bool = True):
  560. if session_key not in DaraCore._sessions:
  561. session = Session()
  562. adapter = DaraCore.get_adapter(protocol, tls_min_version)
  563. if protocol.upper() == 'HTTPS':
  564. if verify:
  565. session.mount('https://', adapter)
  566. else:
  567. session.mount('https://', DaraCore.https_adapter)
  568. else:
  569. session.mount('http://', adapter)
  570. DaraCore._sessions[session_key] = session
  571. return DaraCore._sessions[session_key]