From 1bc8b90b56876c04029b80dbde354d2aff2561fe Mon Sep 17 00:00:00 2001 From: Frederic Meeuwissen <13856291+Frederic98@users.noreply.github.com> Date: Thu, 14 Mar 2024 11:46:59 +0100 Subject: [PATCH 1/4] Move definition ID to cloud name map to json file --- .../src/Cloud/CloudApiClient.py | 18 +++++++++++------- .../src/Cloud/machine_id_to_name.json | 5 +++++ 2 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 plugins/UM3NetworkPrinting/src/Cloud/machine_id_to_name.json diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py index e5524a2e45..379d66f9bb 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py @@ -5,6 +5,7 @@ import urllib.parse from json import JSONDecodeError from time import time from typing import Callable, List, Type, TypeVar, Union, Optional, Tuple, Dict, Any, cast +from pathlib import Path from PyQt6.QtCore import QUrl from PyQt6.QtNetwork import QNetworkRequest, QNetworkReply @@ -30,6 +31,14 @@ CloudApiClientModel = TypeVar("CloudApiClientModel", bound=BaseModel) """The generic type variable used to document the methods below.""" +try: + with open(Path(__file__).parent / "machine_id_to_name.json", "rt") as f: + MACHINE_ID_TO_NAME: Dict[str, str] = json.load(f) +except Exception as e: + Logger.logException("e", f"Could not load machine_id_to_name.json: '{e}'") + MACHINE_ID_TO_NAME = {} + + class CloudApiClient: """The cloud API client is responsible for handling the requests and responses from the cloud. @@ -84,13 +93,8 @@ class CloudApiClient: # conversion! # API points to "MakerBot Method" for a makerbot printertypes which we already changed to allign with other printer_type - method_x = { - "ultimaker_method":"MakerBot Method", - "ultimaker_methodx":"MakerBot Method X", - "ultimaker_methodxl":"MakerBot Method XL" - } - if machine_type in method_x: - machine_type = method_x[machine_type] + if machine_type in MACHINE_ID_TO_NAME: + machine_type = MACHINE_ID_TO_NAME[machine_type] else: machine_type = machine_type.replace("_plus", "+") machine_type = machine_type.replace("_", " ") diff --git a/plugins/UM3NetworkPrinting/src/Cloud/machine_id_to_name.json b/plugins/UM3NetworkPrinting/src/Cloud/machine_id_to_name.json new file mode 100644 index 0000000000..ccd76ab34b --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/machine_id_to_name.json @@ -0,0 +1,5 @@ +{ + "ultimaker_method": "MakerBot Method", + "ultimaker_methodx": "MakerBot Method X", + "ultimaker_methodxl": "MakerBot Method XL" +} From 8012df65181199d3020a155c5a04feb2ed73dd7f Mon Sep 17 00:00:00 2001 From: Frederic Meeuwissen <13856291+Frederic98@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:29:40 +0100 Subject: [PATCH 2/4] Convert str.format to f-string --- plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py index 379d66f9bb..6fe44c90d4 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py @@ -47,8 +47,8 @@ class CloudApiClient: # The cloud URL to use for this remote cluster. ROOT_PATH = UltimakerCloudConstants.CuraCloudAPIRoot - CLUSTER_API_ROOT = "{}/connect/v1".format(ROOT_PATH) - CURA_API_ROOT = "{}/cura/v1".format(ROOT_PATH) + CLUSTER_API_ROOT = f"{ROOT_PATH}/connect/v1" + CURA_API_ROOT = f"{ROOT_PATH}/cura/v1" DEFAULT_REQUEST_TIMEOUT = 10 # seconds From 484cc6d42f17bc89ceff572e47447219fcf98765 Mon Sep 17 00:00:00 2001 From: Frederic Meeuwissen <13856291+Frederic98@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:30:53 +0100 Subject: [PATCH 3/4] Clean up CloudApiClient.py --- .../src/Cloud/CloudApiClient.py | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py index 6fe44c90d4..42538293ff 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py @@ -82,10 +82,10 @@ class CloudApiClient: url = f"{self.CLUSTER_API_ROOT}/clusters?status=active" self._http.get(url, - scope = self._scope, - callback = self._parseCallback(on_finished, CloudClusterResponse, failed), - error_callback = failed, - timeout = self.DEFAULT_REQUEST_TIMEOUT) + scope=self._scope, + callback=self._parseCallback(on_finished, CloudClusterResponse, failed), + error_callback=failed, + timeout=self.DEFAULT_REQUEST_TIMEOUT) def getClustersByMachineType(self, machine_type, on_finished: Callable[[List[CloudClusterWithConfigResponse]], Any], failed: Callable) -> None: # HACK: There is something weird going on with the API, as it reports printer types in formats like @@ -118,9 +118,9 @@ class CloudApiClient: url = f"{self.CLUSTER_API_ROOT}/clusters/{cluster_id}/status" self._http.get(url, - scope = self._scope, - callback = self._parseCallback(on_finished, CloudClusterStatus), - timeout = self.DEFAULT_REQUEST_TIMEOUT) + scope=self._scope, + callback=self._parseCallback(on_finished, CloudClusterStatus), + timeout=self.DEFAULT_REQUEST_TIMEOUT) def requestUpload(self, request: CloudPrintJobUploadRequest, on_finished: Callable[[CloudPrintJobResponse], Any]) -> None: @@ -135,10 +135,10 @@ class CloudApiClient: data = json.dumps({"data": request.toDict()}).encode() self._http.put(url, - scope = self._scope, - data = data, - callback = self._parseCallback(on_finished, CloudPrintJobResponse), - timeout = self.DEFAULT_REQUEST_TIMEOUT) + scope=self._scope, + data=data, + callback=self._parseCallback(on_finished, CloudPrintJobResponse), + timeout=self.DEFAULT_REQUEST_TIMEOUT) def uploadToolPath(self, print_job: CloudPrintJobResponse, mesh: bytes, on_finished: Callable[[], Any], on_progress: Callable[[int], Any], on_error: Callable[[], Any]): @@ -164,11 +164,11 @@ class CloudApiClient: def requestPrint(self, cluster_id: str, job_id: str, on_finished: Callable[[CloudPrintResponse], Any], on_error) -> None: url = f"{self.CLUSTER_API_ROOT}/clusters/{cluster_id}/print/{job_id}" self._http.post(url, - scope = self._scope, - data = b"", - callback = self._parseCallback(on_finished, CloudPrintResponse), - error_callback = on_error, - timeout = self.DEFAULT_REQUEST_TIMEOUT) + scope=self._scope, + data=b"", + callback=self._parseCallback(on_finished, CloudPrintResponse), + error_callback=on_error, + timeout=self.DEFAULT_REQUEST_TIMEOUT) def doPrintJobAction(self, cluster_id: str, cluster_job_id: str, action: str, data: Optional[Dict[str, Any]] = None) -> None: @@ -178,14 +178,15 @@ class CloudApiClient: :param cluster_id: The ID of the cluster. :param cluster_job_id: The ID of the print job within the cluster. :param action: The name of the action to execute. + :param data: Optional data to send with the POST request """ body = json.dumps({"data": data}).encode() if data else b"" url = f"{self.CLUSTER_API_ROOT}/clusters/{cluster_id}/print_jobs/{cluster_job_id}/action/{action}" self._http.post(url, - scope = self._scope, - data = body, - timeout = self.DEFAULT_REQUEST_TIMEOUT) + scope=self._scope, + data=body, + timeout=self.DEFAULT_REQUEST_TIMEOUT) def _createEmptyRequest(self, path: str, content_type: Optional[str] = "application/json") -> QNetworkRequest: """We override _createEmptyRequest in order to add the user credentials. @@ -220,8 +221,11 @@ class CloudApiClient: Logger.logException("e", "Could not parse the stardust response: %s", error.toDict()) return status_code, {"errors": [error.toDict()]} - def _parseResponse(self, response: Dict[str, Any], on_finished: Union[Callable[[CloudApiClientModel], Any], - Callable[[List[CloudApiClientModel]], Any]], model_class: Type[CloudApiClientModel]) -> None: + def _parseResponse(self, + response: Dict[str, Any], + on_finished: Union[Callable[[CloudApiClientModel], Any], + Callable[[List[CloudApiClientModel]], Any]], + model_class: Type[CloudApiClientModel]) -> None: """Parses the given response and calls the correct callback depending on the result. :param response: The response from the server, after being converted to a dict. From f665281a6a5dafa167382c84947e58dfcac7448f Mon Sep 17 00:00:00 2001 From: Frederic Meeuwissen <13856291+Frederic98@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:54:16 +0100 Subject: [PATCH 4/4] Only load machine_id_to_name.json when it's needed for the first time --- .../src/Cloud/CloudApiClient.py | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py index 42538293ff..4feb77222a 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py @@ -31,14 +31,6 @@ CloudApiClientModel = TypeVar("CloudApiClientModel", bound=BaseModel) """The generic type variable used to document the methods below.""" -try: - with open(Path(__file__).parent / "machine_id_to_name.json", "rt") as f: - MACHINE_ID_TO_NAME: Dict[str, str] = json.load(f) -except Exception as e: - Logger.logException("e", f"Could not load machine_id_to_name.json: '{e}'") - MACHINE_ID_TO_NAME = {} - - class CloudApiClient: """The cloud API client is responsible for handling the requests and responses from the cloud. @@ -55,6 +47,9 @@ class CloudApiClient: # In order to avoid garbage collection we keep the callbacks in this list. _anti_gc_callbacks = [] # type: List[Callable[[Any], None]] + # Custom machine definition ID to cloud cluster name mapping + _machine_id_to_name: Dict[str, str] = None + def __init__(self, app: CuraApplication, on_error: Callable[[List[CloudError]], None]) -> None: """Initializes a new cloud API client. @@ -93,8 +88,9 @@ class CloudApiClient: # conversion! # API points to "MakerBot Method" for a makerbot printertypes which we already changed to allign with other printer_type - if machine_type in MACHINE_ID_TO_NAME: - machine_type = MACHINE_ID_TO_NAME[machine_type] + machine_id_to_name = self.getMachineIDMap() + if machine_type in machine_id_to_name: + machine_type = machine_id_to_name[machine_type] else: machine_type = machine_type.replace("_plus", "+") machine_type = machine_type.replace("_", " ") @@ -284,3 +280,14 @@ class CloudApiClient: self._anti_gc_callbacks.append(parse) return parse + + @classmethod + def getMachineIDMap(cls) -> Dict[str, str]: + if cls._machine_id_to_name is None: + try: + with open(Path(__file__).parent / "machine_id_to_name.json", "rt") as f: + cls._machine_id_to_name = json.load(f) + except Exception as e: + Logger.logException("e", f"Could not load machine_id_to_name.json: '{e}'") + cls._machine_id_to_name = {} + return cls._machine_id_to_name