From 53ff3c5f799bf0173cf7c7a7e6d69f8141e917e7 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sun, 30 Oct 2022 21:14:14 -0600 Subject: [PATCH] bug: fix `_load_api_data()` raising an error when api data is an arbitrarily large size and overflows the receive buffer by parsing out the last incomplete item and repairing the json. --- pyasic/API/__init__.py | 50 +++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/pyasic/API/__init__.py b/pyasic/API/__init__.py index c53547c3..378c6053 100644 --- a/pyasic/API/__init__.py +++ b/pyasic/API/__init__.py @@ -204,31 +204,35 @@ If you are sure you want to use this command please use API.send_command("{comma @staticmethod def _load_api_data(data: bytes) -> dict: str_data = None + # some json from the API returns with a null byte (\x00) on the end + if data.endswith(b"\x00"): + # handle the null byte + str_data = data.decode("utf-8")[:-1] + else: + # no null byte + str_data = data.decode("utf-8") + # fix an error with a btminer return having an extra comma that breaks json.loads() + str_data = str_data.replace(",}", "}") + # fix an error with a btminer return having a newline that breaks json.loads() + str_data = str_data.replace("\n", "") + # fix an error with a bmminer return not having a specific comma that breaks json.loads() + str_data = str_data.replace("}{", "},{") + # fix an error with a bmminer return having a specific comma that breaks json.loads() + str_data = str_data.replace("[,{", "[{") + # fix an error with Avalonminers returning inf and nan + str_data = str_data.replace("inf", "0") + str_data = str_data.replace("nan", "0") + # fix whatever this garbage from avalonminers is `,"id":1}` + if str_data.startswith(","): + str_data = f"{{{str_data[1:]}" + # try to fix an error with overflowing the receive buffer + # this can happen in cases such as bugged btminers returning arbitrary length error info with 100s of errors. + if not str_data.endswith("}"): + str_data = ",".join(str_data.split(",")[:-1]) + "}" + + # parse the json try: - # some json from the API returns with a null byte (\x00) on the end - if data.endswith(b"\x00"): - # handle the null byte - str_data = data.decode("utf-8")[:-1] - else: - # no null byte - str_data = data.decode("utf-8") - # fix an error with a btminer return having an extra comma that breaks json.loads() - str_data = str_data.replace(",}", "}") - # fix an error with a btminer return having a newline that breaks json.loads() - str_data = str_data.replace("\n", "") - # fix an error with a bmminer return not having a specific comma that breaks json.loads() - str_data = str_data.replace("}{", "},{") - # fix an error with a bmminer return having a specific comma that breaks json.loads() - str_data = str_data.replace("[,{", "[{") - # fix an error with Avalonminers returning inf and nan - str_data = str_data.replace("inf", "0") - str_data = str_data.replace("nan", "0") - # fix whatever this garbage from avalonminers is `,"id":1}` - if str_data.startswith(","): - str_data = f"{{{str_data[1:]}" - # parse the json parsed_data = json.loads(str_data) - # handle bad json except json.decoder.JSONDecodeError as e: raise APIError(f"Decode Error {e}: {str_data}") return parsed_data