diff --git a/adafruit_matrixportal/network.py b/adafruit_matrixportal/network.py index c88f7d5..2f3aa71 100755 --- a/adafruit_matrixportal/network.py +++ b/adafruit_matrixportal/network.py @@ -28,6 +28,7 @@ import os import time import gc +from micropython import const import adafruit_esp32spi.adafruit_esp32spi_socket as socket from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError import adafruit_requests as requests @@ -70,6 +71,14 @@ STATUS_DATA_RECEIVED = (0, 0, 100) STATUS_OFF = (0, 0, 0) +CONTENT_TEXT = const(1) +CONTENT_JSON = const(2) +CONTENT_IMAGE = const(3) + + +class HttpError(Exception): + """HTTP Specific Error""" + class Network: """Class representing the Adafruit RGB Matrix Portal. @@ -223,9 +232,32 @@ def wget(self, url, filename, *, chunk_size=12000): self.neo_status(STATUS_FETCHING) response = requests.get(url, stream=True) + headers = {} + for title, content in response.headers.items(): + headers[title.lower()] = content + + if response.status_code == 200: + print("Reply is OK!") + self.neo_status((0, 0, 100)) # green = got data + else: + if self._debug: + if "content-length" in headers: + print("Content-Length: {}".format(int(headers["content-length"]))) + if "date" in headers: + print("Date: {}".format(headers["date"])) + self.neo_status((100, 0, 0)) # red = http error + raise HttpError( + "Code {}: {}".format( + response.status_code, response.reason.decode("utf-8") + ) + ) + if self._debug: print(response.headers) - content_length = int(response.headers["content-length"]) + if "content-length" in headers: + content_length = int(headers["content-length"]) + else: + raise RuntimeError("Content-Length missing from headers") remaining = content_length print("Saving data to ", filename) stamp = time.monotonic() @@ -392,8 +424,6 @@ def fetch(self, url, *, headers=None, timeout=10): gc.collect() response = requests.get(url, headers=headers, timeout=timeout) gc.collect() - self.neo_status(STATUS_DATA_RECEIVED) # green = got data - print("Reply is OK!") return response @@ -403,10 +433,40 @@ def fetch_data( """Fetch data from the specified url and perfom any parsing""" json_out = None values = [] + content_type = CONTENT_TEXT response = self.fetch(url, headers=headers, timeout=timeout) - if json_path is not None: + headers = {} + for title, content in response.headers.items(): + headers[title.lower()] = content + gc.collect() + if self._debug: + print("Headers:", headers) + if response.status_code == 200: + print("Reply is OK!") + self.neo_status(STATUS_DATA_RECEIVED) # green = got data + if "content-type" in headers: + if "image/" in headers["content-type"]: + content_type = CONTENT_IMAGE + elif "application/json" in headers["content-type"]: + content_type = CONTENT_JSON + elif "application/javascript" in headers["content-type"]: + content_type = CONTENT_JSON + else: + if self._debug: + if "content-length" in headers: + print("Content-Length: {}".format(int(headers["content-length"]))) + if "date" in headers: + print("Date: {}".format(headers["date"])) + self.neo_status((100, 0, 0)) # red = http error + raise HttpError( + "Code {}: {}".format( + response.status_code, response.reason.decode("utf-8") + ) + ) + + if content_type == CONTENT_JSON and json_path is not None: if isinstance(json_path, (list, tuple)) and ( not json_path or not isinstance(json_path[0], (list, tuple)) ): @@ -436,18 +496,24 @@ def fetch_data( raise # extract desired text/values from json - if json_path: + if json_out and json_path: for path in json_path: try: values.append(self.json_traverse(json_out, path)) except KeyError: print(json_out) raise - elif regexp_path: + elif content_type == CONTENT_TEXT and regexp_path: for regexp in regexp_path: values.append(re.search(regexp, response.text).group(1)) else: - values = response.text + if json_out: + # No path given, so return JSON as string for compatibility + import json # pylint: disable=import-outside-toplevel + + values = json.dumps(response.json()) + else: + values = response.text # we're done with the requests object, lets delete it so we can do more! json_out = None