def restartServer(self): if platform == "linux" or platform == "linux2": actions = self._settings.get(["system", "actions"]) for a in actions: if a['action'] == 'astrobox-restart': #Call to Popen will start the restart command but return inmediately before it completes threading.Timer(1.0, subprocess.Popen, [a['command'].split(' ')]).start() self._logger.info('Restart command scheduled') from astroprint.boxrouter import boxrouterManager from astroprint.printer.manager import printerManager from astroprint.camera import cameraManager from astroprint.network.manager import networkManagerShutdown #let's be nice about shutthing things down boxrouterManager().boxrouter_disconnect() printerManager().disconnect() cameraManager().close_camera() networkManagerShutdown() return True return False return True
def copy(self, src, dst, progressCb, observerId): blksize = 1048576 # 1MiB s = None d = None try: s = open(src, 'rb') d = open(dst, 'wb') sizeWritten = 0.0 total = float( os.stat(src).st_size ) while sizeWritten < total: buf = s.read(blksize) d.write(buf) sizeWritten += len(buf) progressCb((sizeWritten / total)*100, dst, observerId) printerManager().fileManager._metadataAnalyzer.addFileToQueue(dst) progressCb(100.0,dst,observerId) except (KeyboardInterrupt, Exception) as e: raise finally: if s: s.close() if d: d.close()
def set(self, changes): for k in changes: if k in self.data: if self.data[k] != changes[k]: if k == 'driver': #change printer object from astroprint.printer.manager import printerManager try: printerManager(changes['driver']) except Exception as e: self._logger.error("Error selecting driver %s: %s" % (changes['driver'], e)) #revent to previous driver printerManager(self.data['driver']) raise e elif k == 'printer_model': data = { "printerModel": changes[k] } astroprintCloud().updateBoxrouterData(data) self.data[k] = self._clean(k, changes[k]) # Send astrobox event from octoprint.events import eventManager, Events if k == 'filament': eventManager().fire(Events.FILAMENT_CHANGE, { k: self.data[k]}) eventManager().fire(Events.PRINTERPROFILE_CHANGE, { k: self.data[k]}) else: self._logger.error("trying to set unkonwn printer profile field %s to %s" % (k, str(changes[k])))
def _getLocalFileList(self, data): origin = data if origin == FileDestinations.SDCARD: sdFileList = printerManager().getSdFiles() files = [] if sdFileList is not None: for sdFile, sdSize in sdFileList: file = { "name": sdFile, "origin": FileDestinations.SDCARD, #"refs": { # "resource": url_for(".readPrintFile", target=FileDestinations.SDCARD, filename=sdFile, _external=True) #} } if sdSize is not None: file.update({"size": sdSize}) files.append(file) else: files = printerManager().fileManager.getAllFileData() '''for file in files: file.update({ "refs": { "resource": url_for(".readPrintFile", target=FileDestinations.LOCAL, filename=file["name"], _external=True), "download": url_for("index", _external=True) + "downloads/files/" + FileDestinations.LOCAL + "/" + file["name"] } })''' return files
def successCb(destFile, fileInfo): if fileInfo is True: #This means the files was already on the device data = { "type": "success", "id": printFileId, "filename": printerManager().fileManager._getBasicFilename(destFile) } self.publishEvent('f¡nished_download_printfile',data) em.fire(Events.CLOUD_DOWNLOAD,data) else: data = { "type": "success", "id": printFileId, "filename": printerManager().fileManager._getBasicFilename(destFile), "info": fileInfo["info"], "printer": fileInfo["printer"], "material": fileInfo["material"], "quality": fileInfo["quality"], "image": fileInfo["image"], "created": fileInfo["created"] } self.publishEvent('f¡nished_download_printfile',data)
def _verifyFileExists(origin, filename): if origin == FileDestinations.SDCARD: availableFiles = map(lambda x: x[0], printerManager().getSdFiles()) else: availableFiles = printerManager().fileManager.getAllFilenames() return filename in availableFiles
def selectAndOrPrint(filename, absFilename, destination): """ Callback for when the file is ready to be selected and optionally printed. For SD file uploads this is only the case after they have finished streaming to the printer, which is why this callback is also used for the corresponding call to addSdFile. Selects the just uploaded file if either selectAfterUpload or printAfterSelect are True, or if the exact file is already selected, such reloading it. """ if selectAfterUpload or printAfterSelect or (currentFilename == filename and currentOrigin == destination): printerManager().selectFile(absFilename, destination == FileDestinations.SDCARD, printAfterSelect)
def cleanup(self): global discoveryManager printerManager().rampdown() discoveryManager.shutdown() discoveryManager = None boxrouterManager().shutdown() cameraManager().shutdown() from astroprint.network.manager import networkManagerShutdown networkManagerShutdown()
def set(self, changes): for k in changes: if k in self.data: if self.data[k] != changes[k]: if k == 'driver': #change printer object from astroprint.printer.manager import printerManager printerManager(changes['driver']) self.data[k] = self._clean(k, changes[k]) else: self._logger.error("trying to set unkonwn printer profile field %s to %s" % (k, str(changes[k])))
def successCb(destFile, fileInfo): if printerManager().fileManager.saveCloudPrintFile(destFile, fileInfo, FileDestinations.LOCAL): em.fire( Events.CLOUD_DOWNLOAD, { "type": "success", "id": print_file_id, "filename": printerManager().fileManager._getBasicFilename(destFile), "info": fileInfo["info"] } ) else: errorCb(destFile, "Couldn't save the file")
def changeSerialLogs(): data = request.json if data and 'active' in data: s = settings() s.setBoolean(['serial', 'log'], data['active']) s.save() printerManager().setSerialDebugLogging(data['active']) return jsonify(); else: return ("Wrong data sent in.", 400)
def save_printer_profile_settings(): driver = request.values.get('driver', None) if driver: pp = printerProfileManager() pp.data['driver'] = driver pp.save() #swap the printerManager here printerManager(driver) return make_response("OK", 200) return make_response('Invalid Connection Settings', 400)
def download_print_file(self, print_file_id, progressCb, successCb, errorCb): progressCb(1) try: r = requests.get('%s/print-files/%s' % (self.apiHost, print_file_id), auth=self.hmacAuth) data = r.json() except: data = None destFile = None if data and "download_url" in data and "name" in data and "info" in data: progressCb(2) destFile = printerManager().fileManager.getAbsolutePath(data['name'], mustExist=False) if destFile: downloadManager().startDownload({ 'downloadUrl': data["download_url"], 'destFile': destFile, 'printFileId': print_file_id, 'printFileInfo': data['info'], 'progressCb': progressCb, 'successCb': successCb, 'errorCb': errorCb }) return True else: errorCb(destFile, 'Unable to download file') return False
def initial_state(self, data, clientId, done): printer = printerManager() cm = cameraManager() softwareManager = swManager() state = { 'printing': printer.isPrinting(), 'heatingUp': printer.isHeatingUp(), 'operational': printer.isOperational(), 'paused': printer.isPaused(), 'camera': printer.isCameraConnected(), 'filament' : printerProfileManager().data['filament'], 'printCapture': cm.timelapseInfo, 'profile': printerProfileManager().data, 'remotePrint': True, 'capabilities': softwareManager.capabilities() + cm.capabilities, 'tool': printer.getSelectedTool() if printer.isOperational() else None, 'printSpeed': printer.getPrintingSpeed(), 'printFlow': printer.getPrintingFlow() } if state['printing'] or state['paused']: #Let's add info about the ongoing print job state['job'] = printer._stateMonitor._jobData state['progress'] = printer._stateMonitor._progress done(state)
def getStatus(self): printer = printerManager() cm = cameraManager() ppm = printerProfileManager() fileName = None if printer.isPrinting(): currentJob = printer.getCurrentJob() fileName = currentJob["file"]["name"] return { 'id': boxrouterManager().boxId, 'name': networkManager().getHostname(), 'printing': printer.isPrinting(), 'fileName': fileName, 'printerModel': ppm.data['printer_model'] if ppm.data['printer_model']['id'] else None, 'filament' : ppm.data['filament'], 'material': None, 'operational': printer.isOperational(), 'paused': printer.isPaused(), 'camera': cm.isCameraConnected(), #'printCapture': cm.timelapseInfo, 'remotePrint': True, 'capabilities': ['remotePrint'] + cm.capabilities }
def printerBedCommand(): pm = printerManager() if not pm.isOperational(): return make_response("Printer is not operational", 409) valid_commands = { "target": ["target"], "offset": ["offset"] } command, data, response = util.getJsonCommandFromRequest(request, valid_commands) if response is not None: return response ##~~ temperature if command == "target": target = data["target"] # make sure the target is a number if not isinstance(target, (int, long, float)): return make_response("Not a number: %r" % target, 400) # perform the actual temperature command pm.setTemperature("bed", target) return NO_CONTENT
def _sync_print_file_store(self): if self.cloud_enabled(): try: r = requests.get( "%s/print-files?format=%s" % (self.apiHost, printerManager().fileManager.fileFormat), auth=self.hmacAuth ) self._print_file_store = r.json() except Exception as e: self._logger.error("Error syncing with cloud: %s" % e, exc_info = True)
def deletePrintFile(filename, target): if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]: return make_response("Unknown target: %s" % target, 404) if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) sd = target == FileDestinations.SDCARD printer = printerManager() currentJob = printer.getCurrentJob() currentFilename = None currentSd = None if currentJob is not None and "filename" in currentJob.keys() and "sd" in currentJob.keys(): currentFilename = currentJob["filename"] currentSd = currentJob["sd"] # prohibit deleting the file that is currently being printed if currentFilename == filename and currentSd == sd and (printer.isPrinting() or printer.isPaused()): make_response("Trying to delete file that is currently being printed: %s" % filename, 409) # deselect the file if it's currently selected if currentFilename is not None and filename == currentFilename: printer.unselectFile() # delete it if sd: printer.deleteSdFile(filename) else: printer.fileManager.removeFile(filename) return NO_CONTENT
def startPrintCapture(self, filename): data = {'name': filename} pm = printerManager() print_file_id = pm.fileManager.getFileCloudId(filename) print_job_id = pm.currentPrintJobId if print_file_id: data['print_file_id'] = print_file_id if print_job_id: data['print_job_id'] = print_job_id try: r = requests.post( "%s/prints" % self.apiHost, data= data, auth= self.hmacAuth ) status_code = r.status_code except: status_code = 500 if status_code == 201: data = r.json() return data['print_id'] else: return None
def jobState(): currentData = printerManager().getCurrentData() return jsonify({ "job": currentData["job"], "progress": currentData["progress"], "state": currentData["state"]["text"] })
def on_deleted(self, event): fm = printerManager().fileManager filename = fm._getBasicFilename(event.src_path) if not filename: return fm.removeFileFromMetadata(filename)
def printerPrintheadCommand(self, data, callback): pm = printerManager() if not pm.isOperational() or pm.isPrinting(): # do not jog when a print job is running or we don't have a connection callback("Printer is not operational or currently printing",True) valid_axes = ["x", "y", "z"] validated_values = {} for axis in valid_axes: try: value = data[axis] except: value = None if isinstance(value,(int,long,float)): validated_values[axis] = value if len(validated_values) <= 0: self._logger.error('not a number') callback('movement value is not a number',True) else: # execute the jog commands for axis, value in validated_values.iteritems(): pm.jog(axis, value) callback({'success': 'no_error'})
def _sync_print_file_store(self): if self.cloud_enabled(): try: r = requests.get( "%s/print-files?format=%s" % (self.apiHost, printerManager().fileManager.fileFormat), auth=self.hmacAuth ) self._print_file_store = r.json() except: pass
def extrude(self,data,callback): pm = printerManager() if not pm.isOperational(): callback("Printer is not operational", True) return if pm.isPrinting(): # do not extrude when a print job is running callback("Printer is currently printing", True) return amount = data["amount"] speed = data["speed"] tool = data["tool"] if not isinstance(amount, (int, long, float)): callback("Not a number for extrusion amount: " + amount, True) return if speed and not isinstance(speed, (int, long, float)): speed = None pm.extrude(tool, amount, speed) callback({'success': 'no_error'}) return
def printerState(): pm = printerManager() if not pm.isOperational(): return make_response("Printer is not operational", 409) # process excludes excludes = [] if "exclude" in request.values: excludeStr = request.values["exclude"] if len(excludeStr.strip()) > 0: excludes = filter(lambda x: x in ["temperature", "sd", "state"], map(lambda x: x.strip(), excludeStr.split(","))) result = {} # add temperature information if not "temperature" in excludes: result.update({"temperature": _getTemperatureData(lambda x: x)}) # add sd information if not "sd" in excludes and settings().getBoolean(["feature", "sdSupport"]): result.update({"sd": {"ready": pm.isSdReady()}}) # add state information if not "state" in excludes: state = pm.getCurrentData()["state"] result.update({"state": state}) return jsonify(result)
def printerCommand(): pm = printerManager() if not pm.isOperational(): return make_response("Printer is not operational", 409) if not "application/json" in request.headers["Content-Type"]: return make_response("Expected content type JSON", 400) data = request.json parameters = {} if "parameters" in data.keys(): parameters = data["parameters"] commands = [] if "command" in data.keys(): commands = [data["command"]] elif "commands" in data.keys(): commands = data["commands"] commandsToSend = [] for command in commands: commandToSend = command if len(parameters) > 0: commandToSend = command % parameters commandsToSend.append(commandToSend) pm.commands(commandsToSend) return NO_CONTENT
def printerSdCommand(): if not settings().getBoolean(["feature", "sdSupport"]): return make_response("SD support is disabled", 404) pm = printerManager() if not pm.isOperational() or pm.isPrinting() or pm.isPaused(): return make_response("Printer is not operational or currently busy", 409) valid_commands = { "init": [], "refresh": [], "release": [] } command, data, response = util.getJsonCommandFromRequest(request, valid_commands) if response is not None: return response if command == "init": pm.initSdCard() elif command == "refresh": pm.refreshSdFiles() elif command == "release": pm.releaseSdCard() return NO_CONTENT
def printerPrintheadCommand(): pm = printerManager() valid_commands = { "jog": [], "home": ["axes"], "babystepping": [] } command, data, response = util.getJsonCommandFromRequest(request, valid_commands) if not pm.isOperational() or command != "babystepping" and pm.isPrinting(): # do not jog when a print job is running or we don't have a connection return make_response("Printer is not operational or currently printing", 409) if response is not None: return response valid_axes = ["x", "y", "z"] ##~~ jog command if command == "jog": # validate all jog instructions, make sure that the values are numbers validated_values = {} for axis in valid_axes: if axis in data: value = data[axis] if not isinstance(value, (int, long, float)): return make_response("Not a number for axis %s: %r" % (axis, value), 400) validated_values[axis] = value # execute the jog commands for axis, value in validated_values.iteritems(): pm.jog(axis, value) ##~~ home command elif command == "home": validated_values = [] axes = data["axes"] for axis in axes: if not axis in valid_axes: return make_response("Invalid axis: %s" % axis, 400) validated_values.append(axis) # execute the home command pm.home(validated_values) ##~~ babystepping command elif command == "babystepping": if "amount" in data: value = data['amount'] if not isinstance(value, (int, long, float)): return make_response("Not a number for amount: %r" % (value), 400) validated_values = {} validated_values['amount'] = value # execute the babystepping command pm.babystepping(validated_values['amount']) return NO_CONTENT
def printerPrintingSpeed(self, data, callback): pm = printerManager() amount = data["amount"] pm.printingSpeed(amount) callback({'success': 'no_error'})
def setPrintingFlow(self, data, sendResponse= None): pm = printerManager() pm.setPrintingFlow(int(data)) sendResponse({'success': 'no_error'}) return
def download_print_file(self, print_file_id, progressCb, successCb, errorCb): dm = downloadManager() if dm.isDownloading(print_file_id): #We just return, there's already a download for this file in process #which means that the events will be issued for that one. return True fileManager = printerManager().fileManager try: r = requests.get('%s/print-files/%s' % (self.apiHost, print_file_id), auth=self.hmacAuth) data = r.json() except: data = None printFile = fileManager.getFileByCloudId(print_file_id) if printFile: self._logger.info('Print file %s is already on the box as %s' % (print_file_id, printFile)) if data and "printFileName" in data: pm = printerManager() localPrintFileName = pm.fileManager.getPrintFileName(printFile) if data["printFileName"] != localPrintFileName: pm.fileManager.setPrintFileName(printFile, data["printFileName"]) #update printFileName for this printFile in the collection if self._print_file_store: for x in self._print_file_store: if x['id'] == print_file_id: x['printFileName'] = data["printFileName"] break successCb(printFile, True) return True #The file wasn't there so let's go get it progressCb(1) destFile = None printFileName = None if data and "download_url" in data and (("name" in data) or ("filename" in data)) and "info" in data: progressCb(2) if "filename" in data: destFile = fileManager.getAbsolutePath(data['filename'], mustExist=False) printFileName = data["printFileName"] else: destFile = fileManager.getAbsolutePath(data['name'], mustExist=False) printFileName = data["name"] destFile = fileManager.getAbsolutePath(data['name'], mustExist=False) if destFile: def onSuccess(pf, error): self._print_file_store = None successCb(pf, error) dm.startDownload({ 'downloadUrl': data["download_url"], 'destFile': destFile, 'printFileId': print_file_id, 'printFileInfo': data['info'], 'printFileName': printFileName, 'progressCb': progressCb, 'successCb': onSuccess, 'errorCb': errorCb }) return True else: errorCb(destFile, 'Unable to download file') return False
def index(): s = settings() loggedUsername = s.get(["cloudSlicer", "loggedUser"]) if (s.getBoolean(["server", "firstRun"])): swm = swManager() # we need to get the user to sign into their AstroPrint account return render_template("setup.jinja2", debug=debug, uiApiKey=UI_API_KEY, version=VERSION, commit=swm.commit, variantData=variantManager().data, astroboxName=networkManager().getHostname(), checkSoftware=swm.shouldCheckForNew, settings=s, wsToken=create_ws_token( userManager.findUser(loggedUsername). publicKey if loggedUsername else None)) elif softwareManager.updatingRelease or softwareManager.forceUpdateInfo: return render_template( "updating.jinja2", uiApiKey=UI_API_KEY, showForceUpdate=softwareManager.forceUpdateInfo != None, releaseInfo=softwareManager.updatingRelease or softwareManager.forceUpdateInfo, lastCompletionPercent=softwareManager.lastCompletionPercent, lastMessage=softwareManager.lastMessage, variantData=variantManager().data, astroboxName=networkManager().getHostname(), wsToken=create_ws_token( userManager.findUser(loggedUsername). publicKey if loggedUsername else None)) elif loggedUsername and (current_user is None or not current_user.is_authenticated or current_user.get_id() != loggedUsername): if current_user.is_authenticated: logout_user() return render_template("locked.jinja2", username=loggedUsername, uiApiKey=UI_API_KEY, astroboxName=networkManager().getHostname(), variantData=variantManager().data) else: pm = printerManager() nm = networkManager() swm = swManager() cm = cameraManager() paused = pm.isPaused() printing = pm.isPrinting() online = nm.isOnline() return render_template( "app.jinja2", user_email=loggedUsername, show_bad_shutdown=swm.wasBadShutdown and not swm.badShutdownShown, version=VERSION, commit=swm.commit, printing=printing, paused=paused, online=online, print_capture=cm.timelapseInfo if printing or paused else None, printer_profile=printerProfileManager().data, uiApiKey=UI_API_KEY, astroboxName=nm.getHostname(), variantData=variantManager().data, checkSoftware=swm.shouldCheckForNew, serialLogActive=s.getBoolean(['serial', 'log']), cameraManager=cm.name, wsToken=create_ws_token( userManager.findUser(loggedUsername). publicKey if loggedUsername else None))
def unregisterEvents(self): if self._systemListener: printerManager().unregisterCallback(self._systemListener) self._systemListener.cleanup() self._systemListener = None
def registerEvents(self): if not self._systemListener: self._systemListener = SystemListener(self._weakRefRouter) printerManager().registerCallback(self._systemListener)
def uploadPrintFile(target): printer = printerManager() if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]: return make_response("Unknown target: %s" % target, 404) if not "file" in request.files.keys(): return make_response("No file included", 400) if target == FileDestinations.SDCARD and not settings().getBoolean( ["feature", "sdSupport"]): return make_response("SD card support is disabled", 404) file = request.files["file"] sd = target == FileDestinations.SDCARD selectAfterUpload = "select" in request.values.keys( ) and request.values["select"] in valid_boolean_trues printAfterSelect = "print" in request.values.keys( ) and request.values["print"] in valid_boolean_trues if sd: # validate that all preconditions for SD upload are met before attempting it if not (printer.isOperational() and not (printer.isPrinting() or printer.isPaused())): return make_response( "Can not upload to SD card, printer is either not operational or already busy", 409) if not printer.isSdReady(): return make_response( "Can not upload to SD card, not yet initialized", 409) # determine current job currentFilename = None currentOrigin = None currentJob = printer.getCurrentJob() if currentJob is not None and "file" in currentJob.keys(): currentJobFile = currentJob["file"] if "name" in currentJobFile.keys() and "origin" in currentJobFile.keys( ): currentFilename = currentJobFile["name"] currentOrigin = currentJobFile["origin"] # determine future filename of file to be uploaded, abort if it can't be uploaded futureFilename = printer.fileManager.getFutureFilename(file) if futureFilename is None or ( not settings().getBoolean(["cura", "enabled"]) and not printer.fileManager.isValidFilename(futureFilename)): return make_response( "Can not upload file %s, wrong format?" % file.filename, 415) # prohibit overwriting currently selected file while it's being printed if futureFilename == currentFilename and target == currentOrigin and printer.isPrinting( ) or printer.isPaused(): return make_response( "Trying to overwrite file that is currently being printed: %s" % currentFilename, 409) def fileProcessingFinished(filename, absFilename, destination): """ Callback for when the file processing (upload, optional slicing, addition to analysis queue) has finished. Depending on the file's destination triggers either streaming to SD card or directly calls selectAndOrPrint. """ if destination == FileDestinations.SDCARD: return filename, printerManager().addSdFile( filename, absFilename, selectAndOrPrint) else: selectAndOrPrint(filename, absFilename, destination) return filename def selectAndOrPrint(filename, absFilename, destination): """ Callback for when the file is ready to be selected and optionally printed. For SD file uploads this is only the case after they have finished streaming to the printer, which is why this callback is also used for the corresponding call to addSdFile. Selects the just uploaded file if either selectAfterUpload or printAfterSelect are True, or if the exact file is already selected, such reloading it. """ if selectAfterUpload or printAfterSelect or ( currentFilename == filename and currentOrigin == destination): printerManager().selectFile(absFilename, destination == FileDestinations.SDCARD, printAfterSelect) try: filename, done = printer.fileManager.addFile(file, target, fileProcessingFinished) except IOError: return make_response("Your filesystem seems to be corrupt", 500) if filename is None: return make_response("Could not upload the file %s" % file.filename, 500) sdFilename = None if isinstance(filename, tuple): filename, sdFilename = filename eventManager.fire(Events.UPLOAD, {"file": filename, "target": target}) files = {} location = url_for(".readPrintFile", target=FileDestinations.LOCAL, filename=filename, _external=True) files.update({ FileDestinations.LOCAL: { "name": filename, "origin": FileDestinations.LOCAL, "refs": { "resource": location, "download": url_for("index", _external=True) + "downloads/files/" + FileDestinations.LOCAL + "/" + filename } } }) if sd and sdFilename: location = url_for(".readPrintFile", target=FileDestinations.SDCARD, filename=sdFilename, _external=True) files.update({ FileDestinations.SDCARD: { "name": sdFilename, "origin": FileDestinations.SDCARD, "refs": { "resource": location } } }) r = make_response(jsonify(files=files, done=done), 201) r.headers["Location"] = location return r
class Server(): def __init__(self, configfile=None, basedir=None, host="0.0.0.0", port=5000, debug=False, allowRoot=False, logConf=None): self._configfile = configfile self._basedir = basedir self._host = host self._port = port self._debug = debug self._allowRoot = allowRoot self._logConf = logConf self._ioLoop = None def stop(self): if self._ioLoop: self._ioLoop.stop() self._ioLoop = None def run(self): if not self._allowRoot: self._checkForRoot() global userManager global eventManager global loginManager global debug global softwareManager global discoveryManager global VERSION global UI_API_KEY from tornado.wsgi import WSGIContainer from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop from tornado.web import Application, FallbackHandler from astroprint.printfiles.watchdogs import UploadCleanupWatchdogHandler debug = self._debug # first initialize the settings singleton and make sure it uses given configfile and basedir if available self._initSettings(self._configfile, self._basedir) s = settings() if not s.getBoolean(['api', 'regenerate']) and s.getString( ['api', 'key']): UI_API_KEY = s.getString(['api', 'key']) else: UI_API_KEY = ''.join('%02X' % ord(z) for z in uuid.uuid4().bytes) # then initialize logging self._initLogging(self._debug, self._logConf) logger = logging.getLogger(__name__) if s.getBoolean(["accessControl", "enabled"]): userManagerName = s.get(["accessControl", "userManager"]) try: clazz = util.getClass(userManagerName) userManager = clazz() except AttributeError, e: logger.exception( "Could not instantiate user manager %s, will run with accessControl disabled!" % userManagerName) softwareManager = swManager() VERSION = softwareManager.versionString logger.info("Starting AstroBox (%s) - Commit (%s)" % (VERSION, softwareManager.commit)) from astroprint.migration import migrateSettings migrateSettings() eventManager = events.eventManager() printer = printerManager(printerProfileManager().data['driver']) #Start some of the managers here to make sure there are no thread collisions from astroprint.network.manager import networkManager from astroprint.boxrouter import boxrouterManager networkManager() boxrouterManager() # configure timelapse #octoprint.timelapse.configureTimelapse() app.wsgi_app = ReverseProxied(app.wsgi_app) app.secret_key = boxrouterManager().boxId loginManager = LoginManager() loginManager.session_protection = "strong" loginManager.user_callback = load_user if userManager is None: loginManager.anonymous_user = users.DummyUser principals.identity_loaders.appendleft(users.dummy_identity_loader) loginManager.init_app(app) # setup command triggers events.CommandTrigger(printer) if self._debug: events.DebugEventListener() if networkManager().isOnline(): softwareManager.checkForcedUpdate() if self._host is None: self._host = s.get(["server", "host"]) if self._port is None: self._port = s.getInt(["server", "port"]) app.debug = self._debug from octoprint.server.api import api app.register_blueprint(api, url_prefix="/api") boxrouterManager( ) # Makes sure the singleton is created here. It doesn't need to be stored self._router = SockJSRouter(self._createSocketConnection, "/sockjs") discoveryManager = DiscoveryManager() def access_validation_factory(validator): """ Creates an access validation wrapper using the supplied validator. :param validator: the access validator to use inside the validation wrapper :return: an access validation wrapper taking a request as parameter and performing the request validation """ def f(request): """ Creates a custom wsgi and Flask request context in order to be able to process user information stored in the current session. :param request: The Tornado request for which to create the environment and context """ wsgi_environ = tornado.wsgi.WSGIContainer.environ(request) with app.request_context(wsgi_environ): app.session_interface.open_session(app, request) loginManager.reload_user() validator(request) return f self._tornado_app = Application(self._router.urls + [ #(r"/downloads/timelapse/([^/]*\.mpg)", LargeResponseHandler, {"path": s.getBaseFolder("timelapse"), "as_attachment": True}), (r"/downloads/files/local/([^/]*\.(gco|gcode))", LargeResponseHandler, { "path": s.getBaseFolder("uploads"), "as_attachment": True }), (r"/downloads/logs/([^/]*)", LargeResponseHandler, { "path": s.getBaseFolder("logs"), "as_attachment": True, "access_validation": access_validation_factory(admin_validator) }), #(r"/downloads/camera/current", UrlForwardHandler, {"url": s.get(["webcam", "snapshot"]), "as_attachment": True, "access_validation": access_validation_factory(user_validator)}), (r".*", FallbackHandler, { "fallback": WSGIContainer(app.wsgi_app) }) ]) self._server = HTTPServer(self._tornado_app, max_buffer_size=1048576 * s.getInt(['server', 'maxUploadSize'])) self._server.listen(self._port, address=self._host) logger.info("Listening on http://%s:%d" % (self._host, self._port)) eventManager.fire(events.Events.STARTUP) if s.getBoolean(["serial", "autoconnect"]): (port, baudrate) = s.get(["serial", "port" ]), s.getInt(["serial", "baudrate"]) connectionOptions = printer.getConnectionOptions() if port in connectionOptions["ports"]: printer.connect(port, baudrate) # start up watchdogs observer = Observer() observer.schedule(UploadCleanupWatchdogHandler(), s.getBaseFolder("uploads")) observer.start() try: self._ioLoop = IOLoop.instance() self._ioLoop.start() except SystemExit: pass except: logger.fatal( "Please report this including the stacktrace below in AstroPrint's bugtracker. Thanks!" ) logger.exception("Stacktrace follows:") finally: observer.stop() self.cleanup() observer.join() logger.info('Good Bye!')
def index(): s = settings() loggedUsername = s.get(["cloudSlicer", "loggedUser"]) publicKey = None if loggedUsername: user = userManager.findUser(loggedUsername) if user: publicKey = user.publicKey if (s.getBoolean(["server", "firstRun"])): swm = swManager() # we need to get the user to sign into their AstroPrint account return render_template( "setup.jinja2", debug= debug, uiApiKey= UI_API_KEY, version= VERSION, commit= swm.commit, astroboxName= networkManager().getHostname(), checkSoftware= swm.shouldCheckForNew, settings= s, wsToken= create_ws_token(publicKey), mfDefinition= manufacturerPkgManager(), apApiHost= roConfig('cloud.apiHost') ) elif softwareManager.status != 'idle' or softwareManager.forceUpdateInfo: return render_template( "updating.jinja2", uiApiKey= UI_API_KEY, forceUpdateInfo= softwareManager.forceUpdateInfo, releases= softwareManager.updatingReleases or [softwareManager.forceUpdateInfo['id']], lastCompletionPercent= softwareManager.lastCompletionPercent, lastMessage= softwareManager.lastMessage, astroboxName= networkManager().getHostname(), wsToken= create_ws_token(publicKey), status= softwareManager.status, mfDefinition= manufacturerPkgManager() ) elif loggedUsername and (current_user is None or not current_user.is_authenticated or current_user.get_id() != loggedUsername): if current_user.is_authenticated: logout_user() return render_template( "locked.jinja2", username= loggedUsername, uiApiKey= UI_API_KEY, astroboxName= networkManager().getHostname(), mfDefinition= manufacturerPkgManager() ) else: pm = printerManager() nm = networkManager() swm = swManager() cm = cameraManager() mmm = maintenanceMenuManager() paused = pm.isPaused() printing = pm.isPrinting() online = nm.isOnline() return render_template( "app.jinja2", user_email= loggedUsername, userPublicKey= publicKey, show_bad_shutdown= swm.wasBadShutdown and not swm.badShutdownShown, version= VERSION, commit= swm.commit, printing= printing, paused= paused, online= online, print_capture= cm.timelapseInfo if printing or paused else None, printer_profile= printerProfileManager().data, uiApiKey= UI_API_KEY, astroboxName= nm.getHostname(), checkSoftware= swm.shouldCheckForNew, serialLogActive= s.getBoolean(['serial', 'log']), additionalTasks= True, maintenanceMenu= True, cameraManager= cm.name, wsToken= create_ws_token(publicKey), mfDefinition= manufacturerPkgManager(), apApiHost= roConfig('cloud.apiHost'), apApiClientId= roConfig('cloud.apiClientId'), boxId= boxrouterManager().boxId )
def getFileBrowsingExtensions(self): return printerManager().fileManager.SUPPORTED_EXTENSIONS
def printerToolCommand(): pm = printerManager() if not pm.isOperational(): return make_response("Printer is not operational", 409) valid_commands = { "select": ["tool"], "target": ["targets"], "offset": ["offsets"], "extrude": ["amount"] } command, data, response = util.getJsonCommandFromRequest( request, valid_commands) if response is not None: return response validation_regex = re.compile("tool\d+") ##~~ tool selection if command == "select": tool = data["tool"] if re.match(validation_regex, tool) is None: return make_response("Invalid tool: %s" % tool, 400) if not tool.startswith("tool"): return make_response("Invalid tool for selection: %s" % tool, 400) pm.changeTool(int(tool[len("tool"):])) ##~~ temperature elif command == "target": targets = data["targets"] # make sure the targets are valid and the values are numbers validated_values = {} for tool, value in targets.iteritems(): if re.match(validation_regex, tool) is None: return make_response( "Invalid target for setting temperature: %s" % tool, 400) if not isinstance(value, (int, long, float)): return make_response("Not a number for %s: %r" % (tool, value), 400) validated_values[tool] = value # perform the actual temperature commands for tool in validated_values.keys(): pm.setTemperature(tool, validated_values[tool]) ##~~ extrusion elif command == "extrude": if pm.isPrinting(): # do not extrude when a print job is running return make_response("Printer is currently printing", 409) amount = data["amount"] speed = data.get("speed") tool = data.get("tool") if not isinstance(amount, (int, long, float)): return make_response( "Not a number for extrusion amount: %r" % amount, 400) if tool is not None and re.match(validation_regex, tool) is None: return make_response("Invalid extruder value: %r" % tool, 400) if speed and not isinstance(speed, (int, long, float)): speed = None pm.extrude( int(tool[len("tool"):]) if tool is not None else None, amount, speed) return NO_CONTENT
def printerSdState(): if not settings().getBoolean(["feature", "sdSupport"]): return make_response("SD support is disabled", 404) return jsonify(ready=printerManager().isSdReady())
def designs(): forceSyncCloud = request.args.get('forceSyncCloud') cloud_files = json.loads(astroprintCloud().print_files(forceSyncCloud)) local_files = list(printerManager().fileManager.getAllFileData()) if cloud_files: for p in cloud_files: p['local_filename'] = None p['last_print'] = None p['uploaded_on'] = None for i in range(len(local_files)): if "cloud_id" in local_files[i] and p['id'] == local_files[i][ 'cloud_id']: local_file = local_files[i] p['local_filename'] = local_file['name'] p['local_only'] = False p['uploaded_on'] = local_file['date'] if 'prints' in local_file \ and 'last' in local_file['prints'] \ and local_file['prints']['last'] \ and 'date' in local_file['prints']['last']: p['last_print'] = local_file['prints']['last']['date'] del local_files[i] break cloud_files = sorted(cloud_files, key=lambda e: e['local_filename'] is None) else: cloud_files = [] if local_files: for p in local_files: p['id'] = uuid.uuid4().hex p['local_filename'] = p['name'] p['local_only'] = True p['last_print'] = None p['uploaded_on'] = p['date'] if 'gcodeAnalysis' in p: p['info'] = p['gcodeAnalysis'] del p['gcodeAnalysis'] else: p['info'] = None if 'prints' in p \ and 'last' in p['prints'] \ and p['prints']['last'] \ and 'date' in p['prints']['last']: p['last_print'] = p['prints']['last']['date'] del p['prints'] else: local_files = [] files = sorted(local_files + cloud_files, key=lambda e: e['last_print'], reverse=True) return json.dumps(files)