Add a sync timeout to CloudOutputDeviceManager

Fixes an issue where printer syncing breaks when switching networks etc.

CURA-7290
This commit is contained in:
Nino van Hooff 2020-05-14 15:47:45 +02:00
parent a9692e3d27
commit 15f813a4ff

View file

@ -26,6 +26,9 @@ class CloudOutputDeviceManager:
API spec is available on https://api.ultimaker.com/docs/connect/spec/. API spec is available on https://api.ultimaker.com/docs/connect/spec/.
""" """
SYNC_TIMEOUT = 50.0
"""seconds. Adding many different kinds of printers can take a long time"""
META_CLUSTER_ID = "um_cloud_cluster_id" META_CLUSTER_ID = "um_cloud_cluster_id"
META_NETWORK_KEY = "um_network_key" META_NETWORK_KEY = "um_network_key"
SYNC_SERVICE_NAME = "CloudOutputDeviceManager" SYNC_SERVICE_NAME = "CloudOutputDeviceManager"
@ -46,7 +49,13 @@ class CloudOutputDeviceManager:
# Ensure we don't start twice. # Ensure we don't start twice.
self._running = False self._running = False
self._syncing = False # Unfortunately, not all cases of a failed request result in an error callback, such as VPN connection
# being broken or possibly switching wifi networks. Better solution: Refactor CloudApiClient to use
# HttpRequestManager, which supports timeout.
self._sync_timeout_timer = QTimer()
self._sync_timeout_timer.setInterval(int(self.SYNC_TIMEOUT * 1000))
self._sync_timeout_timer.setSingleShot(True)
self._sync_timeout_timer.timeout.connect(self._onSyncTimeout)
def start(self): def start(self):
"""Starts running the cloud output device manager, thus periodically requesting cloud data.""" """Starts running the cloud output device manager, thus periodically requesting cloud data."""
@ -84,12 +93,13 @@ class CloudOutputDeviceManager:
def _getRemoteClusters(self) -> None: def _getRemoteClusters(self) -> None:
"""Gets all remote clusters from the API.""" """Gets all remote clusters from the API."""
if self._syncing: if self._sync_timeout_timer.isActive():
# A sync is running
return return
Logger.info("Syncing cloud printer clusters") Logger.info("Syncing cloud printer clusters")
self._syncing = True self._sync_timeout_timer.start()
self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SYNCING) self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SYNCING)
self._api.getClusters(self._onGetRemoteClustersFinished, self._onGetRemoteClusterFailed) self._api.getClusters(self._onGetRemoteClustersFinished, self._onGetRemoteClusterFailed)
@ -115,12 +125,10 @@ class CloudOutputDeviceManager:
# If the removed device was active we should connect to the new active device # If the removed device was active we should connect to the new active device
self._connectToActiveMachine() self._connectToActiveMachine()
self._syncing = False self._onSyncFinished(True)
self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SUCCESS)
def _onGetRemoteClusterFailed(self): def _onGetRemoteClusterFailed(self):
self._syncing = False self._onSyncFinished(False)
self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.ERROR)
def _onDevicesDiscovered(self, clusters: List[CloudClusterResponse]) -> None: def _onDevicesDiscovered(self, clusters: List[CloudClusterResponse]) -> None:
"""**Synchronously** create machines for discovered devices """**Synchronously** create machines for discovered devices
@ -223,6 +231,19 @@ class CloudOutputDeviceManager:
if device.key in output_device_manager.getOutputDeviceIds(): if device.key in output_device_manager.getOutputDeviceIds():
output_device_manager.removeOutputDevice(device.key) output_device_manager.removeOutputDevice(device.key)
def _onSyncTimeout(self):
Logger.warning("Cloud printer sync timed out after {} seconds".format(self.SYNC_TIMEOUT))
self._onSyncFinished(False)
def _onSyncFinished(self, success: bool):
if self._sync_timeout_timer.isActive():
self._sync_timeout_timer.stop()
if success:
self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SUCCESS)
else:
self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.ERROR)
def _createMachineFromDiscoveredDevice(self, key: str, activate: bool = True) -> None: def _createMachineFromDiscoveredDevice(self, key: str, activate: bool = True) -> None:
device = self._remote_clusters[key] device = self._remote_clusters[key]
if not device: if not device: