mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-12-11 16:00:47 -07:00
Fixes
This commit is contained in:
parent
9e4c71cce3
commit
bfca117bff
6 changed files with 119 additions and 110 deletions
|
|
@ -9,6 +9,7 @@ from PyQt5.QtGui import QDesktopServices
|
|||
from UM import i18nCatalog
|
||||
from UM.Backend.Backend import BackendState
|
||||
from UM.FileHandler.FileHandler import FileHandler
|
||||
from UM.FileHandler.WriteFileJob import WriteFileJob
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
|
|
@ -16,6 +17,7 @@ from UM.Version import Version
|
|||
from cura.CuraApplication import CuraApplication
|
||||
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
|
||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||
from plugins.UM3NetworkPrinting.src.ExportFileJob import ExportFileJob
|
||||
|
||||
from .CloudApiClient import CloudApiClient
|
||||
from ..UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
||||
|
|
@ -93,6 +95,7 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
self._received_print_jobs = None # type: Optional[List[ClusterPrintJobStatus]]
|
||||
|
||||
# Reference to the uploaded print job / mesh
|
||||
# We do this to prevent re-uploading the same file multiple times.
|
||||
self._tool_path = None # type: Optional[bytes]
|
||||
self._uploaded_print_job = None # type: Optional[CloudPrintJobResponse]
|
||||
|
||||
|
|
@ -129,7 +132,7 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
return True
|
||||
return False
|
||||
|
||||
## Set all the interface elements and texts for this output device.
|
||||
## Set all the interface elements and texts for this output device.
|
||||
def _setInterfaceElements(self) -> None:
|
||||
self.setPriority(2) # Make sure we end up below the local networking and above 'save to file'.
|
||||
self.setName(self._id)
|
||||
|
|
@ -137,6 +140,32 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print via Cloud"))
|
||||
self.setConnectionText(I18N_CATALOG.i18nc("@info:status", "Connected via Cloud"))
|
||||
|
||||
## Called when the network data should be updated.
|
||||
def _update(self) -> None:
|
||||
super()._update()
|
||||
if self._last_request_time and time() - self._last_request_time < self.CHECK_CLUSTER_INTERVAL:
|
||||
return # Avoid calling the cloud too often
|
||||
|
||||
Logger.log("d", "Updating: %s - %s >= %s", time(), self._last_request_time, self.CHECK_CLUSTER_INTERVAL)
|
||||
if self._account.isLoggedIn:
|
||||
self.setAuthenticationState(AuthState.Authenticated)
|
||||
self._last_request_time = time()
|
||||
self._api.getClusterStatus(self.key, self._onStatusCallFinished)
|
||||
else:
|
||||
self.setAuthenticationState(AuthState.NotAuthenticated)
|
||||
|
||||
## Method called when HTTP request to status endpoint is finished.
|
||||
# Contains both printers and print jobs statuses in a single response.
|
||||
def _onStatusCallFinished(self, status: CloudClusterStatus) -> None:
|
||||
# Update all data from the cluster.
|
||||
self._last_response_time = time()
|
||||
if self._received_printers != status.printers:
|
||||
self._received_printers = status.printers
|
||||
self._updatePrinters(status.printers)
|
||||
if status.print_jobs != self._received_print_jobs:
|
||||
self._received_print_jobs = status.print_jobs
|
||||
self._updatePrintJobs(status.print_jobs)
|
||||
|
||||
## Called when Cura requests an output device to receive a (G-code) file.
|
||||
def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False,
|
||||
file_handler: Optional[FileHandler] = None, filter_by_machine: bool = False, **kwargs) -> None:
|
||||
|
|
@ -159,54 +188,29 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
# Indicate we have started sending a job.
|
||||
self.writeStarted.emit(self)
|
||||
|
||||
mesh_format = MeshFormatHandler(file_handler, self.firmwareVersion)
|
||||
if not mesh_format.is_valid:
|
||||
Logger.log("e", "Missing file or mesh writer!")
|
||||
return self._onUploadError(I18N_CATALOG.i18nc("@info:status", "Could not export print job."))
|
||||
# Export the scene to the correct file type.
|
||||
job = ExportFileJob(file_handler=file_handler, nodes=nodes, firmware_version=self.firmwareVersion)
|
||||
job.finished.connect(self._onPrintJobCreated)
|
||||
job.start()
|
||||
|
||||
# TODO: use stream just like the network output device
|
||||
mesh = mesh_format.getBytes(nodes)
|
||||
self._tool_path = mesh
|
||||
## Handler for when the print job was created locally.
|
||||
# It can now be sent over the cloud.
|
||||
def _onPrintJobCreated(self, job: WriteFileJob) -> None:
|
||||
self._progress.show()
|
||||
self._tool_path = job.getOutput()
|
||||
request = CloudPrintJobUploadRequest(
|
||||
job_name=file_name or mesh_format.file_extension,
|
||||
file_size=len(mesh),
|
||||
content_type=mesh_format.mime_type,
|
||||
job_name=job.getFileName(),
|
||||
file_size=len(self._tool_path),
|
||||
content_type=job.getMimeType(),
|
||||
)
|
||||
self._api.requestUpload(request, self._onPrintJobCreated)
|
||||
|
||||
## Called when the network data should be updated.
|
||||
def _update(self) -> None:
|
||||
super()._update()
|
||||
if self._last_request_time and time() - self._last_request_time < self.CHECK_CLUSTER_INTERVAL:
|
||||
return # Avoid calling the cloud too often
|
||||
|
||||
Logger.log("d", "Updating: %s - %s >= %s", time(), self._last_request_time, self.CHECK_CLUSTER_INTERVAL)
|
||||
if self._account.isLoggedIn:
|
||||
self.setAuthenticationState(AuthState.Authenticated)
|
||||
self._last_request_time = time()
|
||||
self._api.getClusterStatus(self.key, self._onStatusCallFinished)
|
||||
else:
|
||||
self.setAuthenticationState(AuthState.NotAuthenticated)
|
||||
|
||||
## Method called when HTTP request to status endpoint is finished.
|
||||
# Contains both printers and print jobs statuses in a single response.
|
||||
def _onStatusCallFinished(self, status: CloudClusterStatus) -> None:
|
||||
# Update all data from the cluster.
|
||||
self._last_response_time = time()
|
||||
if self._received_printers != status.printers:
|
||||
self._received_printers = status.printers
|
||||
self._updatePrinters(status.printers)
|
||||
if status.print_jobs != self._received_print_jobs:
|
||||
self._received_print_jobs = status.print_jobs
|
||||
self._updatePrintJobs(status.print_jobs)
|
||||
self._api.requestUpload(request, self._uploadPrintJob)
|
||||
|
||||
## Uploads the mesh when the print job was registered with the cloud API.
|
||||
# \param job_response: The response received from the cloud API.
|
||||
def _onPrintJobCreated(self, job_response: CloudPrintJobResponse) -> None:
|
||||
def _uploadPrintJob(self, job_response: CloudPrintJobResponse) -> None:
|
||||
self._progress.show()
|
||||
self._uploaded_print_job = job_response
|
||||
tool_path = cast(bytes, self._tool_path)
|
||||
self._api.uploadToolPath(job_response, tool_path, self._onPrintJobUploaded, self._progress.update,
|
||||
self._uploaded_print_job = job_response # store the last uploaded job to prevent re-upload of the same file
|
||||
self._api.uploadToolPath(job_response, self._tool_path, self._onPrintJobUploaded, self._progress.update,
|
||||
self._onUploadError)
|
||||
|
||||
## Requests the print to be sent to the printer when we finished uploading the mesh.
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class CloudOutputDeviceManager:
|
|||
self._remote_clusters = {} # type: Dict[str, CloudOutputDevice]
|
||||
self._account = CuraApplication.getInstance().getCuraAPI().account # type: Account
|
||||
self._api = CloudApiClient(self._account, self._onApiError)
|
||||
self._account.loginStateChanged.connect(self._onLoginStateChanged)
|
||||
|
||||
# Create a timer to update the remote cluster list
|
||||
self._update_timer = QTimer()
|
||||
|
|
@ -53,17 +54,22 @@ class CloudOutputDeviceManager:
|
|||
def start(self):
|
||||
if self._running:
|
||||
return
|
||||
self._account.loginStateChanged.connect(self._onLoginStateChanged)
|
||||
if not self._account.isLoggedIn:
|
||||
return
|
||||
self._running = True
|
||||
if not self._update_timer.isActive():
|
||||
self._update_timer.start()
|
||||
self._update_timer.timeout.connect(self._getRemoteClusters)
|
||||
self._onLoginStateChanged(is_logged_in=self._account.isLoggedIn)
|
||||
|
||||
## Stops running the cloud output device manager.
|
||||
def stop(self):
|
||||
if not self._running:
|
||||
return
|
||||
self._account.loginStateChanged.disconnect(self._onLoginStateChanged)
|
||||
self._running = False
|
||||
if self._update_timer.isActive():
|
||||
self._update_timer.stop()
|
||||
self._onGetRemoteClustersFinished([]) # Make sure we remove all cloud output devices.
|
||||
self._update_timer.timeout.disconnect(self._getRemoteClusters)
|
||||
self._onLoginStateChanged(is_logged_in=False)
|
||||
|
||||
## Force refreshing connections.
|
||||
def refreshConnections(self) -> None:
|
||||
|
|
@ -72,17 +78,13 @@ class CloudOutputDeviceManager:
|
|||
## Called when the uses logs in or out
|
||||
def _onLoginStateChanged(self, is_logged_in: bool) -> None:
|
||||
if is_logged_in:
|
||||
if not self._update_timer.isActive():
|
||||
self._update_timer.start()
|
||||
self._getRemoteClusters()
|
||||
self.start()
|
||||
else:
|
||||
if self._update_timer.isActive():
|
||||
self._update_timer.stop()
|
||||
# Notify that all clusters have disappeared
|
||||
self._onGetRemoteClustersFinished([])
|
||||
self.stop()
|
||||
|
||||
## Gets all remote clusters from the API.
|
||||
def _getRemoteClusters(self) -> None:
|
||||
print("getRemoteClusters")
|
||||
self._api.getClusters(self._onGetRemoteClustersFinished)
|
||||
|
||||
## Callback for when the request for getting the clusters is finished.
|
||||
|
|
@ -113,6 +115,8 @@ class CloudOutputDeviceManager:
|
|||
keys = self._remote_clusters.keys()
|
||||
removed_devices = [cluster for cluster in self._remote_clusters.values() if cluster.key not in keys]
|
||||
for device in removed_devices:
|
||||
device.disconnect()
|
||||
device.close()
|
||||
CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device.key)
|
||||
discovery.removeDiscoveredPrinter(device.key)
|
||||
|
||||
|
|
@ -127,11 +131,13 @@ class CloudOutputDeviceManager:
|
|||
return
|
||||
|
||||
# The newly added machine is automatically activated.
|
||||
CuraApplication.getInstance().getMachineManager().addMachine(device.printerType,
|
||||
device.clusterData.friendly_name)
|
||||
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||
machine_manager.addMachine(device.printerType, device.clusterData.friendly_name)
|
||||
active_machine = CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if active_machine:
|
||||
self._connectToOutputDevice(device, active_machine)
|
||||
if not active_machine:
|
||||
return
|
||||
active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
|
||||
self._connectToOutputDevice(device, active_machine)
|
||||
|
||||
## Callback for when the active machine was changed by the user or a new remote cluster was found.
|
||||
def _connectToActiveMachine(self) -> None:
|
||||
|
|
@ -150,28 +156,25 @@ class CloudOutputDeviceManager:
|
|||
device = self._remote_clusters[stored_cluster_id]
|
||||
self._connectToOutputDevice(device, active_machine)
|
||||
Logger.log("d", "Device connected by metadata cluster ID %s", stored_cluster_id)
|
||||
else:
|
||||
self._connectByNetworkKey(active_machine)
|
||||
# else:
|
||||
# self._connectByNetworkKey(active_machine)
|
||||
|
||||
## Tries to match the local network key to the cloud cluster host name.
|
||||
def _connectByNetworkKey(self, active_machine: GlobalStack) -> None:
|
||||
# Check if the active printer has a local network connection and match this key to the remote cluster.
|
||||
local_network_key = active_machine.getMetaDataEntry("um_network_key")
|
||||
if not local_network_key:
|
||||
return
|
||||
|
||||
device = next((c for c in self._remote_clusters.values() if c.matchesNetworkKey(local_network_key)), None)
|
||||
if not device:
|
||||
return
|
||||
|
||||
Logger.log("i", "Found cluster %s with network key %s", device, local_network_key)
|
||||
active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
|
||||
self._connectToOutputDevice(device, active_machine)
|
||||
|
||||
## Connects to an output device and makes sure it is registered in the output device manager.
|
||||
def _connectToOutputDevice(self, device: CloudOutputDevice, active_machine: GlobalStack) -> None:
|
||||
@staticmethod
|
||||
def _connectToOutputDevice(device: CloudOutputDevice, active_machine: GlobalStack) -> None:
|
||||
device.connect()
|
||||
active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
|
||||
active_machine.addConfiguredConnectionType(device.connectionType.value)
|
||||
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue