From 092126bded08618aa02fe40d2bbee07adb324190 Mon Sep 17 00:00:00 2001 From: 1e9abhi1e10 <2311abhiptdr@gmail.com> Date: Wed, 3 Jul 2024 08:43:22 +0530 Subject: [PATCH] Added checksum validation and command handling --- pyasic/miners/backends/epic.py | 68 +++------------------------------- pyasic/web/epic.py | 31 ++++++++++++++++ 2 files changed, 37 insertions(+), 62 deletions(-) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index 126bd2bd..ad7e7d3f 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -14,10 +14,6 @@ # limitations under the License. - # ------------------------------------------------------------------------------ -import logging -import aiofiles -import hashlib -import aiohttp from pathlib import Path from typing import List, Optional @@ -455,69 +451,17 @@ class ePIC(ePICFirmware): return pool_data except LookupError: pass - - async def upgrade_firmware(self, file: Path, keepsettings: bool, password: str): + + async def upgrade_firmware(self, file: Path | str, keep_settings: bool = True) -> bool: """ Upgrade the firmware of the ePIC miner device. Args: - file (Path): The local file path of the firmware to be uploaded. - keepsettings (bool): Whether to keep the current settings after the update. - password (str): The password for authentication. + file (Path | str): The local file path of the firmware to be uploaded. + keep_settings (bool): Whether to keep the current settings after the update. Returns: - str: Confirmation message after upgrading the firmware. + bool: Whether the firmware update succeeded. """ - try: - logging.info("Starting firmware upgrade process for ePIC miner.") - - if not file: - raise ValueError("File location must be provided for firmware upgrade.") - - # calculate the SHA256 checksum of the firmware file - sha256_hash = hashlib.sha256() - async with aiofiles.open(file, "rb") as f: - while chunk := await f.read(8192): - sha256_hash.update(chunk) - checksum = sha256_hash.hexdigest() - - # prepare the multipart/form-data request - form_data = aiohttp.FormData() - form_data.add_field('checksum', checksum) - form_data.add_field('keepsettings', str(keepsettings).lower()) - form_data.add_field('password', password) - form_data.add_field('update.zip', open(file, 'rb'), filename='update.zip') - - # Send the POST request to the ePIC miner device - async with self.web.post(f"http://{self.ip}:{self.port}/systemupdate", data=form_data) as response: - if response.status == 200: - result = await response.json() - if result.get("result"): - logging.info("Firmware upgrade process completed successfully for ePIC miner.") - return "Firmware upgrade completed successfully." - else: - error = result.get("error", "Unknown error") - logging.error(f"Firmware upgrade failed: {error}") - raise Exception(f"Firmware upgrade failed: {error}") - else: - logging.error(f"Firmware upgrade failed with status code: {response.status}") - raise Exception(f"Firmware upgrade failed with status code: {response.status}") - - except FileNotFoundError as e: - logging.error(f"File not found during the firmware upgrade process: {e}") - raise - except ValueError as e: - logging.error( - f"Validation error occurred during the firmware upgrade process: {e}" - ) - raise - except OSError as e: - logging.error(f"OS error occurred during the firmware upgrade process: {e}") - raise - except Exception as e: - logging.error( - f"An unexpected error occurred during the firmware upgrade process: {e}", - exc_info=True, - ) - raise \ No newline at end of file + return await self.web.system_update(file=file, keep_settings=keep_settings) \ No newline at end of file diff --git a/pyasic/web/epic.py b/pyasic/web/epic.py index 8f0e1b41..5c19a98e 100644 --- a/pyasic/web/epic.py +++ b/pyasic/web/epic.py @@ -19,6 +19,10 @@ import json from typing import Any import httpx +import aiofiles +import aiohttp +import hashlib +from pathlib import Path from pyasic import settings from pyasic.errors import APIError @@ -46,6 +50,14 @@ class ePICWebAPI(BaseWebAPI): async with httpx.AsyncClient(transport=settings.transport()) as client: for retry_cnt in range(settings.get("get_data_retries", 1)): try: + if parameters.get("form") is not None: + form_data = parameters["form"] + form_data.add_field('password', self.pwd) + response = await client.post( + f"http://{self.ip}:{self.port}/{command}", + timeout=5, + data=form_data, + ) if post: response = await client.post( f"http://{self.ip}:{self.port}/{command}", @@ -135,3 +147,22 @@ class ePICWebAPI(BaseWebAPI): async def capabilities(self) -> dict: return await self.send_command("capabilities") + + async def system_update(self, file: Path | str, keep_settings: bool = True): + """Perform a system update by uploading a firmware file and sending a + command to initiate the update.""" + + # calculate the SHA256 checksum of the firmware file + sha256_hash = hashlib.sha256() + async with aiofiles.open(str(file), "rb") as f: + while chunk := await f.read(8192): + sha256_hash.update(chunk) + checksum = sha256_hash.hexdigest() + + # prepare the multipart/form-data request + form_data = aiohttp.FormData() + form_data.add_field('checksum', checksum) + form_data.add_field('keepsettings', str(keep_settings).lower()) + form_data.add_field('update.zip', open(file, 'rb'), filename='update.zip') + + await self.send_command("systemupdate", form=form_data) \ No newline at end of file