Now using watchdog to monitor a "watchdog" folder for gcode or stl files being added
Use this to define a folder on your system from which to automatically import/move added files into OctoPrint. Also now monitoring the uploads folder so that if files are removed externally during runtime, the metadata.yaml will be cleaned up.
This commit is contained in:
parent
030ffe6dce
commit
4739c71ee0
3 changed files with 86 additions and 3 deletions
|
|
@ -10,6 +10,7 @@ from sockjs.tornado import SockJSRouter
|
|||
from flask import Flask, render_template, send_from_directory, make_response
|
||||
from flask.ext.login import LoginManager
|
||||
from flask.ext.principal import Principal, Permission, RoleNeed, identity_loaded, UserNeed
|
||||
from watchdog.observers import Observer
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
|
@ -33,7 +34,7 @@ user_permission = Permission(RoleNeed("user"))
|
|||
|
||||
# only import the octoprint stuff down here, as it might depend on things defined above to be initialized already
|
||||
from octoprint.server.util import LargeResponseHandler, ReverseProxied, restricted_access, PrinterStateConnection, admin_validator, \
|
||||
UrlForwardHandler, user_validator
|
||||
UrlForwardHandler, user_validator, GcodeWatchdogHandler, UploadCleanupWatchdogHandler
|
||||
from octoprint.printer import Printer, getConnectionOptions
|
||||
from octoprint.settings import settings
|
||||
import octoprint.gcodefiles as gcodefiles
|
||||
|
|
@ -220,6 +221,13 @@ class Server():
|
|||
connectionOptions = getConnectionOptions()
|
||||
if port in connectionOptions["ports"]:
|
||||
printer.connect(port, baudrate)
|
||||
|
||||
# start up watchdogs
|
||||
observer = Observer()
|
||||
observer.schedule(GcodeWatchdogHandler(gcodeManager, printer), settings().getBaseFolder("watchdog"))
|
||||
observer.schedule(UploadCleanupWatchdogHandler(gcodeManager), settings().getBaseFolder("uploads"))
|
||||
observer.start()
|
||||
|
||||
try:
|
||||
IOLoop.instance().start()
|
||||
except KeyboardInterrupt:
|
||||
|
|
@ -227,6 +235,9 @@ class Server():
|
|||
except:
|
||||
logger.fatal("Now that is embarrassing... Something really really went wrong here. Please report this including the stacktrace below in OctoPrint's bugtracker. Thanks!")
|
||||
logger.exception("Stacktrace follows:")
|
||||
finally:
|
||||
observer.stop()
|
||||
observer.join()
|
||||
|
||||
def _createSocketConnection(self, session):
|
||||
global printer, gcodeManager, userManager, eventManager
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
# coding=utf-8
|
||||
from octoprint.filemanager.destinations import FileDestinations
|
||||
|
||||
__author__ = "Gina Häußge <osd@foosel.net>"
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
|
||||
|
|
@ -19,13 +21,15 @@ import os
|
|||
import threading
|
||||
import logging
|
||||
from functools import wraps
|
||||
from watchdog.events import PatternMatchingEventHandler
|
||||
|
||||
from octoprint.settings import settings
|
||||
import octoprint.timelapse
|
||||
import octoprint.server
|
||||
from octoprint.users import ApiUser
|
||||
from octoprint.events import Events
|
||||
|
||||
from octoprint import gcodefiles
|
||||
import octoprint.util as util
|
||||
|
||||
def restricted_access(func, apiEnabled=True):
|
||||
"""
|
||||
|
|
@ -485,3 +489,70 @@ def redirectToTornado(request, target):
|
|||
redirectUrl += fragment
|
||||
return redirect(redirectUrl)
|
||||
|
||||
|
||||
class UploadCleanupWatchdogHandler(PatternMatchingEventHandler):
|
||||
"""
|
||||
Takes care of automatically deleting metadata entries for files that get deleted from the uploads folder
|
||||
"""
|
||||
|
||||
patterns = map(lambda x: "*.%s" % x, gcodefiles.GCODE_EXTENSIONS)
|
||||
|
||||
def __init__(self, gcode_manager):
|
||||
PatternMatchingEventHandler.__init__(self)
|
||||
self._gcode_manager = gcode_manager
|
||||
|
||||
def on_deleted(self, event):
|
||||
filename = self._gcode_manager._getBasicFilename(event.src_path)
|
||||
if not filename:
|
||||
return
|
||||
|
||||
self._gcode_manager.removeFileFromMetadata(filename)
|
||||
|
||||
|
||||
class GcodeWatchdogHandler(PatternMatchingEventHandler):
|
||||
"""
|
||||
Takes care of automatically "uploading" files that get added to the watchdog folder.
|
||||
"""
|
||||
|
||||
patterns = map(lambda x: "*.%s" % x, gcodefiles.SUPPORTED_EXTENSIONS)
|
||||
|
||||
def __init__(self, gcodeManager, printer):
|
||||
PatternMatchingEventHandler.__init__(self)
|
||||
self._gcodeManager = gcodeManager
|
||||
self._printer = printer
|
||||
|
||||
def _upload(self, path):
|
||||
class WatchdogFileWrapper(object):
|
||||
|
||||
def __init__(self, path):
|
||||
self._path = path
|
||||
self.filename = os.path.basename(self._path)
|
||||
|
||||
def save(self, target):
|
||||
util.safeRename(self._path, target)
|
||||
|
||||
fileWrapper = WatchdogFileWrapper(path)
|
||||
|
||||
# determine current job
|
||||
currentFilename = None
|
||||
currentSd = None
|
||||
currentJob = self._printer.getCurrentJob()
|
||||
if currentJob is not None and "filename" in currentJob.keys() and "sd" in currentJob.keys():
|
||||
currentFilename = currentJob["filename"]
|
||||
currentSd = currentJob["sd"]
|
||||
|
||||
# determine future filename of file to be uploaded, abort if it can't be uploaded
|
||||
futureFilename = self._gcodeManager.getFutureFilename(fileWrapper)
|
||||
if futureFilename is None or (not settings().getBoolean(["cura", "enabled"]) and not gcodefiles.isGcodeFileName(futureFilename)):
|
||||
return # Invalid file
|
||||
|
||||
# prohibit overwriting currently selected file while it's being printed
|
||||
if futureFilename == currentFilename and not currentSd and self._printer.isPrinting() or self._printer.isPaused():
|
||||
return # Trying to overwrite file that is currently being printed
|
||||
|
||||
self._gcodeManager.addFile(fileWrapper, FileDestinations.LOCAL)
|
||||
|
||||
def on_created(self, event):
|
||||
self._upload(event.src_path)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ default_settings = {
|
|||
"timelapse": None,
|
||||
"timelapse_tmp": None,
|
||||
"logs": None,
|
||||
"virtualSd": None
|
||||
"virtualSd": None,
|
||||
"watchdog": None
|
||||
},
|
||||
"temperature": {
|
||||
"profiles":
|
||||
|
|
|
|||
Loading…
Reference in a new issue