api.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. """API Placeholder.
  2. You should create your api seperately and have it hosted on PYPI. This is included here for the sole purpose
  3. of making this example code executable.
  4. """
  5. import logging
  6. import base64
  7. import aiohttp
  8. import asyncio
  9. from .const import (API_SCHEMA,
  10. API_LOGIN_PATH,
  11. API_BASE_PATH,
  12. API_TIMEOUT,
  13. LOGIN_PAYLOAD,
  14. KEY_RESULT,
  15. KEY_OBJECT,
  16. VAL_SUCCES)
  17. _LOGGER = logging.getLogger(__name__)
  18. class RouterAPI:
  19. """Class for example API."""
  20. def __init__(self,
  21. host: str,
  22. user: str,
  23. pwd: str,
  24. session: aiohttp) -> None:
  25. """Initialise."""
  26. self.host = host
  27. self.user = user
  28. self.pwd = pwd
  29. self.session: aiohttp.ClientSession = session
  30. async def async_login(self) -> bool:
  31. """Login and obtain the session cookie"""
  32. payload = LOGIN_PAYLOAD.copy()
  33. payload['Input_Account'] = self.user
  34. payload['Input_Passwd'] = base64.b64encode(
  35. self.pwd.encode('utf-8')).decode('utf-8')
  36. _LOGGER.warning(str(payload))
  37. response = await self.session.post(
  38. f'{API_SCHEMA}://{self.host}{API_LOGIN_PATH}',
  39. json=payload)
  40. if response.ok:
  41. _LOGGER.warning(await response.text)
  42. try:
  43. data = await response.json()
  44. if 'result' in data:
  45. if data['result'] == VAL_SUCCES:
  46. return True
  47. else:
  48. raise RouterAPIAuthError('Login failed')
  49. else:
  50. raise RouterAPIInvalidResponse('Key "result" not set in response')
  51. except Exception as json_exception:
  52. raise RouterAPIInvalidResponse(f'Unable to decode login response') \
  53. from json_exception
  54. raise RouterAPIConnectionError(
  55. f'Error connecting to router. Status: {response.status}')
  56. async def async_query_api(self,
  57. oid: str) -> dict:
  58. """Query an authenticated API endpoint"""
  59. try:
  60. async with asyncio.timeout(API_TIMEOUT):
  61. response = await self.session.get(
  62. f'{API_SCHEMA}://{self.host}{API_BASE_PATH}',
  63. params={'oid': oid})
  64. if response.ok:
  65. try:
  66. data: dict = await response.json()
  67. if data.get(KEY_RESULT, None) == VAL_SUCCES:
  68. return data.get(KEY_OBJECT, [{}])[0]
  69. else:
  70. raise RouterAPIInvalidResponse(f'Response returned error')
  71. except Exception as json_exception:
  72. raise RouterAPIInvalidResponse(f'Unable to decode JSON') \
  73. from json_exception
  74. else:
  75. raise RouterAPIConnectionError(
  76. f'Error retrieving API. Status: {response.status}')
  77. except Exception as exception:
  78. raise RouterAPIConnectionError('Unable to connect to router API') \
  79. from exception
  80. @property
  81. def controller_name(self) -> str:
  82. """Return the name of the controller."""
  83. return self.host.replace(".", "_")
  84. class RouterAPIAuthError(Exception):
  85. """Exception class for auth error."""
  86. class RouterAPIConnectionError(Exception):
  87. """Exception class for connection error."""
  88. class RouterAPIInvalidResponse(Exception):
  89. """Exception class for invalid API response."""