Cleaned up and bug fixed the command loop.

CURA-3335 Single instance Cura and model reloading
This commit is contained in:
Simon Edwards 2017-02-07 13:33:37 +01:00
parent 0e306df1bc
commit 412e299f0c
2 changed files with 77 additions and 54 deletions

View File

@ -1,9 +1,7 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import json
from PyQt5.QtCore import QTextStream
from PyQt5.QtNetwork import QLocalServer
from PyQt5.QtNetwork import QLocalSocket
from UM.Qt.QtApplication import QtApplication
from UM.Scene.SceneNode import SceneNode
@ -63,7 +61,8 @@ import numpy
import copy
import urllib.parse
import os
import argparse
import json
numpy.seterr(all="ignore")
@ -430,6 +429,7 @@ class CuraApplication(QtApplication):
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
parser.add_argument("--single-instance", action="store_true", default=False)
# Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
def _setUpSingleInstanceServer(self):
if self.getCommandLineOption("single_instance", False):
self.__single_instance_server = QLocalServer()
@ -437,25 +437,79 @@ class CuraApplication(QtApplication):
self.__single_instance_server.listen("ultimaker-cura")
def _singleInstanceServerNewConnection(self):
Logger.log('d', 'Saw something on the single instance server')
other_cura_connection = self.__single_instance_server.nextPendingConnection()
if other_cura_connection is not None:
def readyRead():
while other_cura_connection.canReadLine():
line = other_cura_connection.readLine()
payload = json.loads(str(line, encoding="ASCII").strip())
command = payload["command"]
if command == "clear-all":
self.deleteAll()
Logger.log("i", "New connection recevied on our single-instance server")
remote_cura_connection = self.__single_instance_server.nextPendingConnection()
elif command == "open":
self.deleteAll()
self._openFile(payload["filePath"])
if remote_cura_connection is not None:
def readCommands():
line = remote_cura_connection.readLine()
while len(line) != 0: # There is also a .canReadLine()
try:
Logger.log('d', "JSON command: " + str(line, encoding="ASCII"))
payload = json.loads(str(line, encoding="ASCII").strip())
command = payload["command"]
elif command == "focus":
self.focusWindow()
# Command: Remove all models from the build plate.
if command == "clear-all":
self.deleteAll()
other_cura_connection.readyRead.connect(readyRead)
# Command: Load a model file
elif command == "open":
self._openFile(payload["filePath"])
# FIXME ^ this method is async and we really should wait until
# the file load is complete before processing more commands.
# Command: Activate the window and bring it to the top.
elif command == "focus":
self.getMainWindow().raise_()
self.focusWindow()
else:
Logger.log("w", "Received an unrecognized command " + str(command))
except json.decoder.JSONDecodeError as ex:
Logger.log("w", "Unable to parse JSON command in _singleInstanceServerNewConnection(): " + repr(ex))
line = remote_cura_connection.readLine()
remote_cura_connection.readyRead.connect(readCommands)
remote_cura_connection.disconnected.connect(readCommands) # Get any last commands before it is destroyed.
## Perform any checks before creating the main application.
#
# This should be called directly before creating an instance of CuraApplication.
# \returns \type{bool} True if the whole Cura app should continue running.
@classmethod
def preStartUp(cls):
# Peek the arguments and look for the 'single-instance' flag.
parser = argparse.ArgumentParser(prog="cura") # pylint: disable=bad-whitespace
CuraApplication.addCommandLineOptions(parser)
parsed_command_line = vars(parser.parse_args())
if "single_instance" in parsed_command_line and parsed_command_line["single_instance"]:
Logger.log("i", "Checking for the presence of an ready running Cura instance.")
single_instance_socket = QLocalSocket()
single_instance_socket.connectToServer("ultimaker-cura")
single_instance_socket.waitForConnected()
if single_instance_socket.state() == QLocalSocket.ConnectedState:
Logger.log("i", "Connection has been made to the single-instance Cura socket.")
# Protocol is one line of JSON terminated with a carriage return.
# "command" field is required and holds the name of the command to execute.
# Other fields depend on the command.
payload = {"command": "clear-all"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
payload = {"command": "focus"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
if len(parsed_command_line["file"]) != 0:
for filename in parsed_command_line["file"]:
payload = {"command": "open", "filePath": filename}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
single_instance_socket.flush()
single_instance_socket.close()
return False
return True
def run(self):
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))

View File

@ -2,14 +2,10 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import argparse
import json
import os
import sys
import platform
import time
from PyQt5.QtNetwork import QLocalSocket
from UM.Platform import Platform
#WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
@ -61,36 +57,9 @@ if Platform.isWindows() and hasattr(sys, "frozen"):
# Force an instance of CuraContainerRegistry to be created and reused later.
cura.Settings.CuraContainerRegistry.getInstance()
# Peek the arguments and look for the 'single-instance' flag.
parser = argparse.ArgumentParser(prog="cura") # pylint: disable=bad-whitespace
cura.CuraApplication.CuraApplication.addCommandLineOptions(parser)
parsed_command_line = vars(parser.parse_args())
if "single_instance" in parsed_command_line and parsed_command_line["single_instance"]:
print("Check for single instance")
single_instance_socket = QLocalSocket()
single_instance_socket.connectToServer("ultimaker-cura")
single_instance_socket.waitForConnected()
if single_instance_socket.state() == QLocalSocket.ConnectedState:
print("Connected to the other Cura instance.")
print(repr(parsed_command_line))
payload = {"command": "clear-all"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
payload = {"command": "focus"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
if len(parsed_command_line["file"]) != 0:
for filename in parsed_command_line["file"]:
payload = { "command": "open", "filePath": filename }
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
single_instance_socket.flush()
single_instance_socket.close()
sys.exit(0)
# This prestart up check is needed to determine if we should start the application at all.
if not cura.CuraApplication.CuraApplication.preStartUp():
sys.exit(0)
app = cura.CuraApplication.CuraApplication.getInstance()
app.run()