This commit is contained in:
ChrisTerBeke 2019-07-30 22:21:36 +02:00
parent 72ac8b5f4c
commit d280252437
No known key found for this signature in database
GPG key ID: A49F1AB9D7E0C263
7 changed files with 81 additions and 91 deletions

View file

@ -5,13 +5,14 @@ from json import JSONDecodeError
from typing import Callable, List, Optional, Dict, Union, Any, Type, cast, TypeVar, Tuple
from PyQt5.QtCore import QUrl
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply, QNetworkConfiguration
from UM.Logger import Logger
from ..Models.BaseModel import BaseModel
from ..Models.Http.ClusterPrintJobStatus import ClusterPrintJobStatus
from ..Models.Http.ClusterPrinterStatus import ClusterPrinterStatus
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
## The generic type variable used to document the methods below.
@ -21,11 +22,8 @@ ClusterApiClientModel = TypeVar("ClusterApiClientModel", bound=BaseModel)
## The ClusterApiClient is responsible for all network calls to local network clusters.
class ClusterApiClient:
PRINTER_API_VERSION = "1"
PRINTER_API_PREFIX = "/api/v" + PRINTER_API_VERSION
CLUSTER_API_VERSION = "1"
CLUSTER_API_PREFIX = "/cluster-api/v" + CLUSTER_API_VERSION
PRINTER_API_PREFIX = "/api/v1"
CLUSTER_API_PREFIX = "/cluster-api/v1"
## Initializes a new cluster API client.
# \param address: The network address of the cluster to call.
@ -43,7 +41,8 @@ class ClusterApiClient:
# \param on_finished: The callback in case the response is successful.
def getSystem(self, on_finished: Callable) -> None:
url = "{}/system/".format(self.PRINTER_API_PREFIX)
self._manager.get(self._createEmptyRequest(url))
reply = self._manager.get(self._createEmptyRequest(url))
self._addCallback(reply, on_finished, PrinterSystemStatus)
## Get the printers in the cluster.
# \param on_finished: The callback in case the response is successful.
@ -132,12 +131,17 @@ class ClusterApiClient:
Callable[[List[ClusterApiClientModel]], Any]],
model: Optional[Type[ClusterApiClientModel]] = None,
) -> None:
def parse() -> None:
self._anti_gc_callbacks.remove(parse)
# Don't try to parse the reply if we didn't get one
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) is None:
return
self._anti_gc_callbacks.remove(parse)
if reply.error() > 0:
self._on_error(reply.errorString())
return
# If no parse model is given, simply return the raw data in the callback.
if not model:

View file

@ -1,14 +1,13 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, Dict, List, Any
from typing import Optional, Dict, List
from PyQt5.QtGui import QDesktopServices, QImage
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty
from PyQt5.QtNetwork import QNetworkReply
from UM.FileHandler.FileHandler import FileHandler
from UM.FileHandler.WriteFileJob import WriteFileJob
from UM.Logger import Logger
from UM.Message import Message
from UM.i18n import i18nCatalog
from UM.Scene.SceneNode import SceneNode
@ -39,7 +38,7 @@ class NetworkOutputDevice(UltimakerNetworkedPrinterOutputDevice):
)
# API client for making requests to the print cluster.
self._cluster_api = ClusterApiClient(address, on_error=self._onNetworkError)
self._cluster_api = ClusterApiClient(address, on_error=lambda error: print(error))
# We don't have authentication over local networking, so we're always authenticated.
self.setAuthenticationState(AuthState.Authenticated)
self._setInterfaceElements()
@ -95,11 +94,6 @@ class NetworkOutputDevice(UltimakerNetworkedPrinterOutputDevice):
def setJobState(self, print_job_uuid: str, action: str) -> None:
self._cluster_api.setPrintJobState(print_job_uuid, action)
## Handle network errors.
@staticmethod
def _onNetworkError(errors: Dict[str, Any]):
Logger.log("w", str(errors))
def _update(self) -> None:
super()._update()
self._cluster_api.getPrinters(self._updatePrinters)
@ -152,7 +146,7 @@ class NetworkOutputDevice(UltimakerNetworkedPrinterOutputDevice):
self.writeProgress.emit()
## Handler for when the print job was fully uploaded to the cluster.
def _onPrintUploadCompleted(self, reply: QNetworkReply) -> None:
def _onPrintUploadCompleted(self, _: QNetworkReply) -> None:
self._progress.hide()
Message(
text=I18N_CATALOG.i18nc("@info:status", "Print job was successfully sent to the printer."),

View file

@ -14,6 +14,7 @@ from cura.Settings.GlobalStack import GlobalStack
from .ZeroConfClient import ZeroConfClient
from .ClusterApiClient import ClusterApiClient
from .NetworkOutputDevice import NetworkOutputDevice
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
## The NetworkOutputDeviceManager is responsible for discovering and managing local networked clusters.
@ -64,18 +65,8 @@ class NetworkOutputDeviceManager:
self._manual_instances[address] = callback
new_manual_devices = ",".join(self._manual_instances.keys())
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_manual_devices)
device_id = "manual:{}".format(address)
if device_id not in self._discovered_devices:
self._onDeviceDiscovered(device_id, address, {
b"name": address.encode("utf-8"),
b"address": address.encode("utf-8"),
b"manual": b"true",
b"incomplete": b"true",
b"temporary": b"true"
})
self._checkManualDevice(address, lambda status_code, response: self._onCheckManualDeviceResponse(
status_code, address))
api_client = ClusterApiClient(address, self._onApiError)
api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status))
## Remove a manually added networked printer.
def removeManualDevice(self, device_id: str, address: Optional[str] = None) -> None:
@ -119,19 +110,19 @@ class NetworkOutputDeviceManager:
active_machine.addConfiguredConnectionType(device.connectionType.value)
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)
## Checks if a networked printer exists at the given address.
# If the printer responds it will replace the preliminary printer created from the stored manual instances.
def _checkManualDevice(self, address: str, on_finished: Callable) -> None:
api_client = ClusterApiClient(address, self._onApiError)
api_client.getSystem(on_finished)
## Callback for when a manual device check request was responded to.
def _onCheckManualDeviceResponse(self, status_code: int, address: str) -> None:
Logger.log("d", "manual device check response: {} {}".format(status_code, address))
if address in self._manual_instances:
callback = self._manual_instances[address]
if callback is not None:
CuraApplication.getInstance().callLater(callback, status_code == 200, address)
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None:
callback = self._manual_instances.get(address, None)
if callback is None:
return
self._onDeviceDiscovered("manual:{}".format(address), address, {
b"name": status.name.encode("utf-8"),
b"address": address.encode("utf-8"),
b"manual": b"true",
b"incomplete": b"true",
b"temporary": b"true"
})
CuraApplication.getInstance().callLater(callback, True, address)
## Returns a dict of printer BOM numbers to machine types.
# These numbers are available in the machine definition already so we just search for them here.
@ -179,9 +170,10 @@ class NetworkOutputDeviceManager:
## Remove a device.
def _onDiscoveredDeviceRemoved(self, device_id: str) -> None:
device = self._discovered_devices.pop(device_id, None)
device = self._discovered_devices.pop(device_id, None) # type: Optional[NetworkOutputDevice]
if not device:
return
device.close()
CuraApplication.getInstance().getDiscoveredPrintersModel().removeDiscoveredPrinter(device.address)
self.discoveredDevicesChanged.emit()