uri.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import json
  2. import logging
  3. import os
  4. import requests
  5. from core.NeuronModule import NeuronModule, InvalidParameterException
  6. logging.basicConfig()
  7. logger = logging.getLogger("kalliope")
  8. class Uri(NeuronModule):
  9. def __init__(self, **kwargs):
  10. super(Uri, self).__init__(**kwargs)
  11. # input variables
  12. self.url = kwargs.get('url', None)
  13. self.headers = kwargs.get('headers', None)
  14. self.data = kwargs.get('data', None)
  15. self.data_from_file = kwargs.get('data_from_file', None)
  16. self.method = kwargs.get('method', "GET")
  17. self.user = kwargs.get('user', None)
  18. self.password = kwargs.get('password', None)
  19. self.timeout = kwargs.get('timeout', None)
  20. # processing parameters
  21. self.parameters = None
  22. # output variable
  23. self.status_code = None
  24. self.content = None
  25. self.text = None
  26. self.response_header = None
  27. # this is a switch case option
  28. switch_case = {
  29. "GET": self.do_get,
  30. "POST": self.do_post,
  31. "DELETE": self.do_delete,
  32. "PUT": self.do_put,
  33. "HEAD": self.do_head,
  34. "PATCH": self.do_patch,
  35. "OPTIONS": self.do_options
  36. }
  37. # check parameters
  38. if self._is_parameters_ok():
  39. # we get parameters that will be passed to the requests lib
  40. self.parameters = self.get_parameters()
  41. # we call the right method depending of the method selected
  42. switch_case[self.method]()
  43. message = {
  44. "status_code": self.status_code,
  45. "content": self.content,
  46. "response_header": self.response_header
  47. }
  48. self.say(message)
  49. def do_get(self):
  50. logger.debug(self.neuron_name + " do_get method called")
  51. r = requests.get(url=self.url, **self.parameters)
  52. self.post_processing_request(r)
  53. def do_post(self):
  54. logger.debug(self.neuron_name + " do_post method called")
  55. r = requests.post(url=self.url, **self.parameters)
  56. self.post_processing_request(r)
  57. def do_delete(self):
  58. logger.debug(self.neuron_name + " do_delete method called")
  59. r = requests.delete(url=self.url, **self.parameters)
  60. self.post_processing_request(r)
  61. def do_put(self):
  62. logger.debug(self.neuron_name + " do_put method called")
  63. r = requests.put(url=self.url, **self.parameters)
  64. self.post_processing_request(r)
  65. def do_head(self):
  66. logger.debug(self.neuron_name + " do_head method called")
  67. r = requests.head(url=self.url, **self.parameters)
  68. self.post_processing_request(r)
  69. def do_patch(self):
  70. logger.debug(self.neuron_name + " do_patch method called")
  71. r = requests.patch(url=self.url, **self.parameters)
  72. self.post_processing_request(r)
  73. def do_options(self):
  74. logger.debug(self.neuron_name + " do_options method called")
  75. r = requests.options(url=self.url, **self.parameters)
  76. self.post_processing_request(r)
  77. def get_parameters(self):
  78. """
  79. :return: Dict of parameters usable by the "requests" lib
  80. """
  81. returned_parameters = dict()
  82. if self.headers is not None:
  83. returned_parameters["headers"] = self.headers
  84. if self.timeout is not None:
  85. returned_parameters["timeout"] = self.timeout
  86. if self.data is not None:
  87. returned_parameters["data"] = self.data
  88. if self.data_from_file is not None:
  89. returned_parameters["data"] = self.data_from_file
  90. if self.user is not None:
  91. # this implicitly means that the password is set too, the check has been done in _is_parameters_ok
  92. returned_parameters["auth"] = self.user, self.password
  93. logger.debug(self.neuron_name + " parameters: %s" % returned_parameters)
  94. return returned_parameters
  95. def post_processing_request(self, r):
  96. self.status_code = r.status_code
  97. self.content = r.content
  98. # we try to load into a json object the content. So Kalliope can use it to talk
  99. try:
  100. self.content = json.loads(self.content)
  101. except ValueError:
  102. logger.debug(self.neuron_name + "cannot get a valid json from returned content")
  103. pass
  104. self.text = r.text
  105. self.response_header = r.headers
  106. logger.debug(self.neuron_name + " status_code: %s" % self.status_code)
  107. logger.debug(self.neuron_name + " content: %s" % self.content)
  108. logger.debug(self.neuron_name + " response_header: %s" % self.response_header)
  109. def _is_parameters_ok(self):
  110. """
  111. Check that all provided parameters in the neurons are valid
  112. :return: True if all check passed
  113. """
  114. # URL is mandatory
  115. if self.url is None:
  116. raise InvalidParameterException("Uri needs an url")
  117. # headers can be null, but if provided it must be a list
  118. if self.headers is not None:
  119. if not isinstance(self.headers, dict):
  120. raise InvalidParameterException("headers must be a list of key: value")
  121. # timeout in second must be an integer
  122. if self.timeout is not None:
  123. if not isinstance(self.timeout, int):
  124. raise InvalidParameterException("timeout must be an integer")
  125. # data must be loadable with json
  126. if self.data is not None:
  127. try:
  128. json.loads(self.data)
  129. except ValueError, e:
  130. raise InvalidParameterException("error in \"data\" parameter: %s" % e)
  131. # data_from_file path must exist and data inside must be loadable by json
  132. if self.data_from_file is not None:
  133. # check that the file exist
  134. if not os.path.exists(self.data_from_file):
  135. raise InvalidParameterException("error in \"data_file\". File does not exist: %s" % self.data_from_file)
  136. # then try to load the json from the file
  137. try:
  138. self.data_from_file = self.readfile(self.data_from_file)
  139. except ValueError, e:
  140. raise InvalidParameterException("error in \"data\" parameter: %s" % e)
  141. # we cannot provide both data and data from file
  142. if self.data is not None and self.data_from_file is not None:
  143. raise InvalidParameterException("URI can be used with data or data_from_file, not both in same time")
  144. # the provided method must exist
  145. allowed_method = ["GET", "POST", "DELETE", "PUT", "HEAD", "PATCH", "OPTIONS"]
  146. if self.method not in allowed_method:
  147. raise InvalidParameterException("method %s not in: %s" % (self.method, allowed_method))
  148. return True
  149. @staticmethod
  150. def readfile(file_path):
  151. """
  152. return the content of the file <file_path>
  153. :param file_path: File path to read
  154. :return: Str content of the file
  155. """
  156. file_to_read = open(file_path, 'r')
  157. return file_to_read.read()