def _send_request(self): if not self.queue: if self.request_loop.running: self.request_loop.stop() return now = time.time() - 1 # 1 second buffer if (self.rate_remaining < 1+1 and self.rate_reset > now or DiscordRestApiLoop.global_wait > now): self.log.warn("Rate limited: {}".format(self.channel_id)) return payload = self.queue.pop() method = payload['method'] url = payload['url'] content = payload['content'] # url = '{}/channels/{}/messages'.format(HOST, self.channel_id) content = json.dumps({"content": content}) self.log.debug('at _send_request: {} url {}'.format(self.channel_id, url)) if method == 'post': d = treq.post(url, content, headers=HEADERS) elif method == 'patch': d = treq.patch(url, content, headers=HEADERS) elif method == 'delete': d = treq.delete(url, headers=HEADERS) elif method == 'get': d = treq.get(url, headers=HEADERS) d.addCallback(self.update_rate_limits) if not self.queue: self.request_loop.stop()
def request(self, method, uri, data=None, name=''): """ Send a REST request to the Adtran device :param method: (string) HTTP method :param uri: (string) fully URL to perform method on :param data: (string) optional data for the request body :param name: (string) optional name of the request, useful for logging purposes :return: (deferred) """ if method.upper() not in self._valid_methods: raise NotImplementedError( "REST method '{}' is not supported".format(method)) url = 'http://{}:{}{}{}'.format(self.ip, self.rest_port, '/' if uri[0] != '/' else '', uri) try: if method.upper() == 'GET': response = yield treq.get(url, auth=(self.username, self.password), timeout=self.timeout, headers=self.REST_GET_REQUEST_HEADER) elif method.upper() == 'POST' or method.upper() == 'PUT': response = yield treq.post( url, data=data, auth=(self.username, self.password), timeout=self.timeout, headers=self.REST_POST_REQUEST_HEADER) elif method.upper() == 'PATCH': response = yield treq.patch( url, data=data, auth=(self.username, self.password), timeout=self.timeout, headers=self.REST_PATCH_REQUEST_HEADER) elif method.upper() == 'DELETE': response = yield treq.delete( url, auth=(self.username, self.password), timeout=self.timeout, headers=self.REST_DELETE_REQUEST_HEADER) else: raise NotImplementedError( "REST method '{}' is not supported".format(method)) except NotImplementedError: raise except ConnectionClosed: returnValue(None) except Exception, e: log.exception("REST {} '{}' request to '{}' failed: {}".format( method, name, url, str(e))) raise
def _patch(self, path, headers, data): # print("yapi patch called. path: %s... headers: %s... data: %s" % (path, headers, data)) response = yield treq.patch(path, data=data, agent=self.custom_agent, headers=headers) content = yield treq.content(response) final_response = self.decode_results(content, self.response_headers(response), response.code, response.phrase) return final_response
def request(self, method, uri, data=None, name='', timeout=None, is_retry=False, suppress_error=False): """ Send a REST request to the Adtran device :param method: (string) HTTP method :param uri: (string) fully URL to perform method on :param data: (string) optional data for the request body :param name: (string) optional name of the request, useful for logging purposes :param timeout: (int) Number of seconds to wait for a response before timing out :param is_retry: (boolean) True if this method called recursively in order to recover from a connection loss. Can happen sometimes in debug sessions and in the real world. :param suppress_error: (boolean) If true, do not output ERROR message on REST request failure :return: (dict) On success with the proper results """ log.debug('request', method=method, uri=uri, data=data, retry=is_retry) if method.upper() not in self._valid_methods: raise NotImplementedError( "REST method '{}' is not supported".format(method)) url = 'http://{}:{}{}{}'.format(self._ip, self._port, '/' if uri[0] != '/' else '', uri) response = None timeout = timeout or self._timeout try: if method.upper() == 'GET': response = yield treq.get(url, auth=(self._username, self._password), timeout=timeout, headers=self.REST_GET_REQUEST_HEADER) elif method.upper() == 'POST' or method.upper() == 'PUT': response = yield treq.post( url, data=data, auth=(self._username, self._password), timeout=timeout, headers=self.REST_POST_REQUEST_HEADER) elif method.upper() == 'PATCH': response = yield treq.patch( url, data=data, auth=(self._username, self._password), timeout=timeout, headers=self.REST_PATCH_REQUEST_HEADER) elif method.upper() == 'DELETE': response = yield treq.delete( url, auth=(self._username, self._password), timeout=timeout, headers=self.REST_DELETE_REQUEST_HEADER) else: raise NotImplementedError( "REST method '{}' is not supported".format(method)) except NotImplementedError: raise except (ConnectionDone, ConnectionLost) as e: if is_retry: raise returnValue( self.request(method, uri, data=data, name=name, timeout=timeout, is_retry=True)) except ConnectionClosed: returnValue(ConnectionClosed) except Exception as e: log.exception("rest-request", method=method, url=url, name=name, e=e) raise if response.code not in self._valid_results[method.upper()]: message = "REST {} '{}' request to '{}' failed with status code {}".format( method, name, url, response.code) if not suppress_error: log.error(message) raise RestInvalidResponseCode(message, url, response.code) if response.code == self.HTTP_NO_CONTENT: returnValue(None) else: # TODO: May want to support multiple body encodings in the future headers = response.headers type_key = 'content-type' type_val = 'application/json' if not headers.hasHeader( type_key) or type_val not in headers.getRawHeaders( type_key, []): raise Exception( "REST {} '{}' request response from '{}' was not JSON", method, name, url) content = yield response.content() try: result = json.loads(content) except Exception as e: log.exception("json-decode", method=method, url=url, name=name, content=content, e=e) raise returnValue(result)
def request(self, method, uri, data=None, name='', timeout=None, is_retry=False, suppress_error=False): """ Send a REST request to the Adtran device :param method: (string) HTTP method :param uri: (string) fully URL to perform method on :param data: (string) optional data for the request body :param name: (string) optional name of the request, useful for logging purposes :param timeout: (int) Number of seconds to wait for a response before timing out :param is_retry: (boolean) True if this method called recursively in order to recover from a connection loss. Can happen sometimes in debug sessions and in the real world. :return: (dict) On success with the proper results """ log.debug('request', method=method, uri=uri, data=data, retry=is_retry) if method.upper() not in self._valid_methods: raise NotImplementedError("REST method '{}' is not supported".format(method)) url = 'http://{}:{}{}{}'.format(self._ip, self._port, '/' if uri[0] != '/' else '', uri) response = None timeout = timeout or self._timeout try: if method.upper() == 'GET': response = yield treq.get(url, auth=(self._username, self._password), timeout=timeout, headers=self.REST_GET_REQUEST_HEADER) elif method.upper() == 'POST' or method.upper() == 'PUT': response = yield treq.post(url, data=data, auth=(self._username, self._password), timeout=timeout, headers=self.REST_POST_REQUEST_HEADER) elif method.upper() == 'PATCH': response = yield treq.patch(url, data=data, auth=(self._username, self._password), timeout=timeout, headers=self.REST_PATCH_REQUEST_HEADER) elif method.upper() == 'DELETE': response = yield treq.delete(url, auth=(self._username, self._password), timeout=timeout, headers=self.REST_DELETE_REQUEST_HEADER) else: raise NotImplementedError("REST method '{}' is not supported".format(method)) except NotImplementedError: raise except (ConnectionDone, ConnectionLost) as e: if is_retry: raise returnValue(self.request(method, uri, data=data, name=name, timeout=timeout, is_retry=True)) except ConnectionClosed: returnValue(ConnectionClosed) except Exception as e: log.exception("rest-request", method=method, url=url, name=name, e=e) raise if response.code not in self._valid_results[method.upper()]: message = "REST {} '{}' request to '{}' failed with status code {}".format(method, name, url, response.code) if not suppress_error: log.error(message) raise RestInvalidResponseCode(message, url, response.code) if response.code == self.HTTP_NO_CONTENT: returnValue(None) else: # TODO: May want to support multiple body encodings in the future headers = response.headers type_key = 'content-type' type_val = 'application/json' if not headers.hasHeader(type_key) or type_val not in headers.getRawHeaders(type_key, []): raise Exception("REST {} '{}' request response from '{}' was not JSON", method, name, url) content = yield response.content() try: result = json.loads(content) except Exception as e: log.exception("json-decode", method=method, url=url, name=name, content=content, e=e) raise returnValue(result)