From 3b6ac5eb8d6ea1f35d88e1d0a2ef32c52edaf9b2 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 15 Jun 2020 15:01:14 +0200 Subject: [PATCH 1/2] Add host_guid to the cloud printers' metadata Since the host_guid is unique to the printer, it is more reliable for identifying the cloud printers. This comes in handy when the cloud printer is removed from the account and re-added. With the host_guid, the printer that is added again can be properly identified as an existing Cura cloud printer, and be linked to the original. To achieve that, the META_CLUSTER_ID of the printer is updated with the new one that is generated when the printer is added again to the account. CURA-7505 --- .../src/Cloud/CloudOutputDeviceManager.py | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index 33c9caba05..e473ae7cc3 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -31,6 +31,7 @@ class CloudOutputDeviceManager: """ META_CLUSTER_ID = "um_cloud_cluster_id" + META_HOST_GUID = "host_guid" META_NETWORK_KEY = "um_network_key" SYNC_SERVICE_NAME = "CloudOutputDeviceManager" @@ -113,13 +114,18 @@ class CloudOutputDeviceManager: all_clusters = {c.cluster_id: c for c in clusters} # type: Dict[str, CloudClusterResponse] online_clusters = {c.cluster_id: c for c in clusters if c.is_online} # type: Dict[str, CloudClusterResponse] - # Add the new printers in Cura. If a printer was previously added and is rediscovered, set its metadata to - # reflect that and mark the printer not removed from the account + # Add the new printers in Cura. for device_id, cluster_data in all_clusters.items(): if device_id not in self._remote_clusters: new_clusters.append(cluster_data) - if device_id in self._um_cloud_printers and not parseBool(self._um_cloud_printers[device_id].getMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, "true")): - self._um_cloud_printers[device_id].setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True) + if device_id in self._um_cloud_printers: + # Existing cloud printers may not have the host_guid meta-data entry. If that's the case, add it. + if not self._um_cloud_printers[device_id].getMetaDataEntry(self.META_HOST_GUID, None): + self._um_cloud_printers[device_id].setMetaDataEntry(self.META_HOST_GUID, cluster_data.host_guid) + # If a printer was previously not linked to the account and is rediscovered, mark the printer as linked + # to the current account + if not parseBool(self._um_cloud_printers[device_id].getMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, "true")): + self._um_cloud_printers[device_id].setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True) self._onDevicesDiscovered(new_clusters) # Hide the current removed_printers_message, if there is any @@ -161,11 +167,21 @@ class CloudOutputDeviceManager: """ new_devices = [] remote_clusters_added = False + host_guid_map = {machine.getMetaDataEntry(self.META_HOST_GUID): device_cluster_id + for device_cluster_id, machine in self._um_cloud_printers.items() + if machine.getMetaDataEntry(self.META_HOST_GUID)} + machine_manager = CuraApplication.getInstance().getMachineManager() + for cluster_data in clusters: device = CloudOutputDevice(self._api, cluster_data) - # Create a machine if we don't already have it. Do not make it the active machine. - machine_manager = CuraApplication.getInstance().getMachineManager() + if cluster_data.host_guid in host_guid_map: + machine = machine_manager.getMachine(device.printerType, {self.META_HOST_GUID: cluster_data.host_guid}) + # Update the META_CLUSTER_ID of the machine in case it has been changed (e.g. if the printer was + # removed and re-added to the account). + if machine and machine.getMetaDataEntry(self.META_CLUSTER_ID) != device.key: + machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) + # Create a machine if we don't already have it. Do not make it the active machine. # We only need to add it if it wasn't already added by "local" network or by cloud. if machine_manager.getMachine(device.printerType, {self.META_CLUSTER_ID: device.key}) is None \ and machine_manager.getMachine(device.printerType, {self.META_NETWORK_KEY: cluster_data.host_name + "*"}) is None: # The host name is part of the network key. @@ -378,6 +394,7 @@ class CloudOutputDeviceManager: def _setOutputDeviceMetadata(self, device: CloudOutputDevice, machine: GlobalStack): machine.setName(device.name) machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) + machine.setMetaDataEntry(self.META_HOST_GUID, device.clusterData.host_guid) machine.setMetaDataEntry("group_name", device.name) machine.setMetaDataEntry("group_size", device.clusterSize) machine.setMetaDataEntry("removal_warning", self.I18N_CATALOG.i18nc( From 8abaf69873bfc8b1d285b26fd803481356070465 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Wed, 17 Jun 2020 16:11:18 +0200 Subject: [PATCH 2/2] Update CloudOutputDevice of the machine when it is rediscovered Even though the metadata of the machine was updated when it was rediscovered, the new cluster id was not updated in all its references (such as in the _remote_clusters and in the _um_cloud_printers dicts). This commit fixes that issue by properly updating all the entries that depend on the machine's cluster id. CURA-7505 --- .../src/Cloud/CloudOutputDeviceManager.py | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index e473ae7cc3..bde324df24 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -174,12 +174,13 @@ class CloudOutputDeviceManager: for cluster_data in clusters: device = CloudOutputDevice(self._api, cluster_data) + # If the machine already existed before, it will be present in the host_guid_map if cluster_data.host_guid in host_guid_map: machine = machine_manager.getMachine(device.printerType, {self.META_HOST_GUID: cluster_data.host_guid}) - # Update the META_CLUSTER_ID of the machine in case it has been changed (e.g. if the printer was - # removed and re-added to the account). if machine and machine.getMetaDataEntry(self.META_CLUSTER_ID) != device.key: - machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) + # If the retrieved device has a different cluster_id than the existing machine, bring the existing + # machine up-to-date. + self._updateOutdatedMachine(outdated_machine = machine, new_cloud_output_device = device) # Create a machine if we don't already have it. Do not make it the active machine. # We only need to add it if it wasn't already added by "local" network or by cloud. @@ -266,6 +267,31 @@ class CloudOutputDeviceManager: ) message.setText(message_text) + def _updateOutdatedMachine(self, outdated_machine: GlobalStack, new_cloud_output_device: CloudOutputDevice) -> None: + """ + Update the cloud metadata of a pre-existing machine that is rediscovered (e.g. if the printer was removed and + re-added to the account) and delete the old CloudOutputDevice related to this machine. + + :param outdated_machine: The cloud machine that needs to be brought up-to-date with the new data received from + the account + :param new_cloud_output_device: The new CloudOutputDevice that should be linked to the pre-existing machine + :return: None + """ + old_cluster_id = outdated_machine.getMetaDataEntry(self.META_CLUSTER_ID) + outdated_machine.setMetaDataEntry(self.META_CLUSTER_ID, new_cloud_output_device.key) + outdated_machine.setMetaDataEntry(META_UM_LINKED_TO_ACCOUNT, True) + # Cleanup the remainings of the old CloudOutputDevice(old_cluster_id) + self._um_cloud_printers[new_cloud_output_device.key] = self._um_cloud_printers.pop(old_cluster_id) + output_device_manager = CuraApplication.getInstance().getOutputDeviceManager() + if old_cluster_id in output_device_manager.getOutputDeviceIds(): + output_device_manager.removeOutputDevice(old_cluster_id) + if old_cluster_id in self._remote_clusters: + # We need to close the device so that it stops checking for its status + self._remote_clusters[old_cluster_id].close() + del self._remote_clusters[old_cluster_id] + self._remote_clusters[new_cloud_output_device.key] = new_cloud_output_device + + def _devicesRemovedFromAccount(self, removed_device_ids: Set[str]) -> None: """ Removes the CloudOutputDevice from the received device ids and marks the specific printers as "removed from