Keep track of files that are currently being used (file being printed, source and destination for slicing) so that they can't be deleted

Also added logging to exception branches where the exception was formerly just swallowed.
This commit is contained in:
Gina Häußge 2014-10-21 19:18:59 +02:00
parent 0ab5369635
commit 6e62ecc8c1
8 changed files with 59 additions and 19 deletions

View file

@ -187,6 +187,15 @@ class FileManager(object):
finally:
os.remove(tmp_path)
source_job_key = (source_location, source_path)
dest_job_key = (dest_location, dest_path)
with self._slicing_jobs_mutex:
if source_job_key in self._slicing_jobs:
del self._slicing_jobs[source_job_key]
if dest_job_key in self._slicing_jobs:
del self._slicing_jobs[dest_job_key]
import time
start_time = time.time()
eventManager().fire(Events.SLICING_STARTED, {"stl": source_path, "gcode": dest_path})
@ -197,13 +206,15 @@ class FileManager(object):
f.close()
with self._slicing_jobs_mutex:
if dest_location in self._slicing_jobs:
job_slicer_name, job_absolute_source_path, job_temp_path = self._slicing_jobs[dest_location]
source_job_key = (source_location, source_path)
dest_job_key = (dest_location, dest_path)
if dest_job_key in self._slicing_jobs:
job_slicer_name, job_absolute_source_path, job_temp_path = self._slicing_jobs[dest_job_key]
self._slicing_manager.cancel_slicing(job_slicer_name, job_absolute_source_path, job_temp_path)
del self._slicing_jobs[dest_location]
del self._slicing_jobs[dest_job_key]
self._slicing_jobs[dest_location] = (slicer_name, absolute_source_path, temp_path)
self._slicing_jobs[dest_job_key] = self._slicing_jobs[source_job_key] = (slicer_name, absolute_source_path, temp_path)
args = (source_location, source_path, temp_path, dest_location, dest_path, start_time, callback, callback_args)
return self._slicing_manager.slice(
@ -229,7 +240,10 @@ class FileManager(object):
for callback in self._slicing_progress_callbacks:
try: callback.sendSlicingProgress(slicer, source_location, source_path, dest_location, dest_path, progress_int)
except: pass
except: self._logger.exception("Exception while pushing slicing progress")
def get_busy_files(self):
return self._slicing_jobs.keys()
def file_exists(self, destination, path):
return self._storage(destination).file_exists(path)

View file

@ -33,6 +33,8 @@ class Printer():
def __init__(self, fileManager, analysisQueue):
from collections import deque
self._logger = logging.getLogger(__name__)
self._analysisQueue = analysisQueue
self._fileManager = fileManager
@ -120,32 +122,32 @@ class Printer():
def _sendAddTemperatureCallbacks(self, data):
for callback in self._callbacks:
try: callback.addTemperature(data)
except: pass
except: self._logger.exception("Exception while adding temperature data point")
def _sendAddLogCallbacks(self, data):
for callback in self._callbacks:
try: callback.addLog(data)
except: pass
except: self._logger.exception("Exception while adding communication log entry")
def _sendAddMessageCallbacks(self, data):
for callback in self._callbacks:
try: callback.addMessage(data)
except: pass
except: self._logger.exception("Exception while adding printer message")
def _sendCurrentDataCallbacks(self, data):
for callback in self._callbacks:
try: callback.sendCurrentData(copy.deepcopy(data))
except: pass
except: self._logger.exception("Exception while pushing current data")
def _sendTriggerUpdateCallbacks(self, type):
for callback in self._callbacks:
try: callback.sendEvent(type)
except: pass
except: self._logger.exception("Exception while pushing trigger update")
def _sendFeedbackCommandOutput(self, name, output):
for callback in self._callbacks:
try: callback.sendFeedbackCommandOutput(name, output)
except: pass
except: self._logger.exception("Exception while pushing feedback command output")
#~~ callback from metadata analysis event
@ -248,7 +250,7 @@ class Printer():
def selectFile(self, filename, sd, printAfterSelect=False):
if self._comm is None or (self._comm.isBusy() or self._comm.isStreaming()):
logging.info("Cannot load file: printer not connected or currently busy")
self._logger.info("Cannot load file: printer not connected or currently busy")
return
self._printAfterSelect = printAfterSelect
@ -559,7 +561,7 @@ class Printer():
def addSdFile(self, filename, absolutePath, streamingFinishedCallback):
if not self._comm or self._comm.isBusy() or not self._comm.isSdReady():
logging.error("No connection to printer or printer is busy")
self._logger.error("No connection to printer or printer is busy")
return
self._streamingFinishedCallback = streamingFinishedCallback

View file

@ -370,11 +370,14 @@ def deleteGcodeFile(filename, target):
if not _verifyFileExists(target, filename):
return make_response("File not found on '%s': %s" % (target, filename), 404)
# prohibit deleting the file that is currently being printed
# prohibit deleting files that are currently in use
currentOrigin, currentFilename = _getCurrentFile()
if currentFilename == filename and currentOrigin == target and (printer.isPrinting() or printer.isPaused()):
make_response("Trying to delete file that is currently being printed: %s" % filename, 409)
if (target, filename) in fileManager.get_busy_files():
make_response("Trying to delete a file that is currently in use: %s" % filename, 409)
# deselect the file if it's currently selected
if currentFilename is not None and filename == currentFilename:
printer.unselectFile()

View file

@ -83,10 +83,18 @@ class PrinterStateConnection(sockjs.tornado.SockJSConnection):
messages = self._messageBacklog
self._messageBacklog = []
busy_files = [dict(origin=v[0], name=v[1]) for v in self._fileManager.get_busy_files()]
if "job" in data and data["job"] is not None \
and "file" in data["job"] and "name" in data["job"]["file"] and "origin" in data["job"]["file"] \
and data["job"]["file"]["name"] is not None and data["job"]["file"]["origin"] is not None \
and (self._printer.isPrinting() or self._printer.isPaused()):
busy_files.append(dict(origin=data["job"]["file"]["origin"], name=data["job"]["file"]["name"]))
data.update({
"temps": temperatures,
"logs": logs,
"messages": messages
"messages": messages,
"busyFiles": busy_files,
})
self._emit("current", data)

View file

@ -119,9 +119,9 @@ class SlicingManager(object):
if not ok:
callback_kwargs.update(dict(_error=result))
callback(*callback_args, **callback_kwargs)
except SlicingCancelled:
callback_kwargs.update(dict(_cancelled=True))
finally:
callback(*callback_args, **callback_kwargs)
import threading

View file

@ -239,7 +239,7 @@ function GcodeFilesViewModel(printerStateViewModel, loginStateViewModel, slicing
};
self.getEntryId = function(data) {
return "gcode_file_" + md5(data["name"] + ":" + data["origin"]);
return "gcode_file_" + md5(data["origin"] + ":" + data["name"]);
};
self.getEntryElement = function(data) {
@ -253,7 +253,7 @@ function GcodeFilesViewModel(printerStateViewModel, loginStateViewModel, slicing
};
self.enableRemove = function(data) {
return self.loginState.isUser() && !(self.listHelper.isSelected(data) && (self.isPrinting() || self.isPaused()));
return self.loginState.isUser() && !_.contains(self.printerState.busyFiles(), data.origin + ":" + data.name);
};
self.enableSelect = function(data, printAfterSelect) {

View file

@ -22,6 +22,8 @@ function PrinterStateViewModel(loginStateViewModel) {
self.sd = ko.observable(undefined);
self.timelapse = ko.observable(undefined);
self.busyFiles = ko.observableArray([]);
self.filament = ko.observableArray([]);
self.estimatedPrintTime = ko.observable(undefined);
self.lastPrintTime = ko.observable(undefined);
@ -109,6 +111,7 @@ function PrinterStateViewModel(loginStateViewModel) {
self._processJobData(data.job);
self._processProgressData(data.progress);
self._processZData(data.currentZ);
self._processBusyFiles(data.busyFiles);
};
self._processStateData = function(data) {
@ -177,6 +180,16 @@ function PrinterStateViewModel(loginStateViewModel) {
self.currentHeight(data);
};
self._processBusyFiles = function(data) {
var busyFiles = [];
_.each(data, function(entry) {
if (entry.hasOwnProperty("name") && entry.hasOwnProperty("origin")) {
busyFiles.push(entry.origin + ":" + entry.name);
}
});
self.busyFiles(busyFiles);
};
self.print = function() {
var restartCommand = function() {
self._jobCommand("restart");

View file

@ -61,7 +61,7 @@ def notifyCallbacks(timelapse):
config = timelapse.configData()
for callback in updateCallbacks:
try: callback.sendTimelapseConfig(config)
except: pass
except: logging.getLogger(__name__).exception("Exception while pushing timelapse configuration")
def configureTimelapse(config=None, persist=False):