Ejemplo n.º 1
0
def gcodeFileCommand(filename, target):
	if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
		return make_response("Unknown target: %s" % target, 404)

	# valid file commands, dict mapping command name to mandatory parameters
	valid_commands = {
		"select": [],
		"slice": [],
		"copy": ["destination"],
		"move": ["destination"]
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	if command == "select":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		# selects/loads a file
		if not octoprint.filemanager.valid_file_type(filename, type="machinecode"):
			return make_response("Cannot select {filename} for printing, not a machinecode file".format(**locals()), 415)

		printAfterLoading = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			printAfterLoading = True

		sd = False
		if target == FileDestinations.SDCARD:
			filenameToSelect = filename
			sd = True
		else:
			filenameToSelect = fileManager.path_on_disk(target, filename)
		printer.select_file(filenameToSelect, sd, printAfterLoading)

	elif command == "slice":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		try:
			if "slicer" in data:
				slicer = data["slicer"]
				del data["slicer"]
				slicer_instance = slicingManager.get_slicer(slicer)

			elif "cura" in slicingManager.registered_slicers:
				slicer = "cura"
				slicer_instance = slicingManager.get_slicer("cura")

			else:
				return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415)
		except octoprint.slicing.UnknownSlicer as e:
			return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400)

		if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]):
			return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415)

		if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()):
			# slicer runs on same device as OctoPrint, slicing while printing is hence disabled
			return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409)

		if "destination" in data and data["destination"]:
			destination = data["destination"]
			del data["destination"]
		elif "gcode" in data and data["gcode"]:
			destination = data["gcode"]
			del data["gcode"]
		else:
			import os
			name, _ = os.path.splitext(filename)
			destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0]

		full_path = destination
		if "path" in data and data["path"]:
			full_path = fileManager.join_path(target, data["path"], destination)
		else:
			path, _ = fileManager.split_path(target, filename)
			if path:
				full_path = fileManager.join_path(target, path, destination)

		# prohibit overwriting the file that is currently being printed
		currentOrigin, currentFilename = _getCurrentFile()
		if currentFilename == full_path and currentOrigin == target and (printer.is_printing() or printer.is_paused()):
			make_response("Trying to slice into file that is currently being printed: %s" % full_path, 409)

		if "profile" in data.keys() and data["profile"]:
			profile = data["profile"]
			del data["profile"]
		else:
			profile = None

		if "printerProfile" in data.keys() and data["printerProfile"]:
			printerProfile = data["printerProfile"]
			del data["printerProfile"]
		else:
			printerProfile = None

		if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]:
			position = data["position"]
			del data["position"]
		else:
			position = None

		select_after_slicing = False
		if "select" in data.keys() and data["select"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly select for printing", 409)
			select_after_slicing = True

		print_after_slicing = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			select_after_slicing = print_after_slicing = True

		override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None]
		overrides = dict()
		for key in override_keys:
			overrides[key[len("profile."):]] = data[key]

		def slicing_done(target, path, select_after_slicing, print_after_slicing):
			if select_after_slicing or print_after_slicing:
				sd = False
				if target == FileDestinations.SDCARD:
					filenameToSelect = path
					sd = True
				else:
					filenameToSelect = fileManager.path_on_disk(target, path)
				printer.select_file(filenameToSelect, sd, print_after_slicing)

		try:
			fileManager.slice(slicer, target, filename, target, full_path,
			                  profile=profile,
			                  printer_profile_id=printerProfile,
			                  position=position,
			                  overrides=overrides,
			                  callback=slicing_done,
			                  callback_args=(target, full_path, select_after_slicing, print_after_slicing))
		except octoprint.slicing.UnknownProfile:
			return make_response("Profile {profile} doesn't exist".format(**locals()), 400)

		files = {}
		location = url_for(".readGcodeFile", target=target, filename=full_path, _external=True)
		result = {
			"name": destination,
			"path": full_path,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location,
				"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + full_path
			}
		}

		r = make_response(jsonify(result), 202)
		r.headers["Location"] = location
		return r

	elif command == "copy" or command == "move":
		# Copy and move are only possible on local storage
		if not target in [FileDestinations.LOCAL]:
			return make_response("Unsupported target for {}: {}".format(command, target), 400)

		if not _verifyFileExists(target, filename) and not _verifyFolderExists(target, filename):
			return make_response("File or folder not found on {}: {}".format(target, filename), 404)

		path, name = fileManager.split_path(target, filename)
		destination = data["destination"]
		if _verifyFolderExists(target, destination):
			# destination is an existing folder, we'll assume we are supposed to move filename to this
			# folder under the same name
			destination = fileManager.join_path(target, destination, name)

		if _verifyFileExists(target, destination) or _verifyFolderExists(target, destination):
			return make_response("File or folder does already exist on {}: {}".format(target, destination), 409)

		is_file = fileManager.file_exists(target, filename)
		is_folder = fileManager.folder_exists(target, filename)

		if not (is_file or is_folder):
			return make_response("{} on {} is neither file or folder, can't {}".format(filename, target, command), 400)

		if command == "copy":
			if is_file:
				fileManager.copy_file(target, filename, destination)
			else:
				fileManager.copy_folder(target, filename, destination)
		elif command == "move":
			if _isBusy(target, filename):
				return make_response("Trying to move a file or folder that is currently in use: {}".format(filename), 409)

			# deselect the file if it's currently selected
			currentOrigin, currentFilename = _getCurrentFile()
			if currentFilename is not None and filename == currentFilename:
				printer.unselect_file()

			if is_file:
				fileManager.move_file(target, filename, destination)
			else:
				fileManager.move_folder(target, filename, destination)

		location = url_for(".readGcodeFile", target=target, filename=destination, _external=True)
		result = {
			"name": name,
			"path": destination,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location
			}
		}
		if is_file:
			result["refs"]["download"] = url_for("index", _external=True) + "downloads/files/" + target + "/" + destination

		r = make_response(jsonify(result), 201)
		r.headers["Location"] = location
		return r

	return NO_CONTENT
Ejemplo n.º 2
0
def gcodeFileCommand(filename, target):
	if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
		return make_response("Unknown target: %s" % target, 404)

	# valid file commands, dict mapping command name to mandatory parameters
	valid_commands = {
		"select": [],
		"slice": [],
		"analyse": [],
		"copy": ["destination"],
		"move": ["destination"]
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	user = current_user.get_name()

	if command == "select":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		# selects/loads a file
		if not octoprint.filemanager.valid_file_type(filename, type="machinecode"):
			return make_response("Cannot select {filename} for printing, not a machinecode file".format(**locals()), 415)

		printAfterLoading = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			printAfterLoading = True

		sd = False
		if target == FileDestinations.SDCARD:
			filenameToSelect = filename
			sd = True
		else:
			filenameToSelect = fileManager.path_on_disk(target, filename)
		printer.select_file(filenameToSelect, sd, printAfterLoading, user)

	elif command == "slice":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		try:
			if "slicer" in data:
				slicer = data["slicer"]
				del data["slicer"]
				slicer_instance = slicingManager.get_slicer(slicer)

			elif "cura" in slicingManager.registered_slicers:
				slicer = "cura"
				slicer_instance = slicingManager.get_slicer("cura")

			else:
				return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415)
		except octoprint.slicing.UnknownSlicer as e:
			return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400)

		if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]):
			return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415)

		if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()):
			# slicer runs on same device as OctoPrint, slicing while printing is hence disabled
			return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409)

		if "destination" in data and data["destination"]:
			destination = data["destination"]
			del data["destination"]
		elif "gcode" in data and data["gcode"]:
			destination = data["gcode"]
			del data["gcode"]
		else:
			import os
			name, _ = os.path.splitext(filename)
			destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0]

		full_path = destination
		if "path" in data and data["path"]:
			full_path = fileManager.join_path(target, data["path"], destination)
		else:
			path, _ = fileManager.split_path(target, filename)
			if path:
				full_path = fileManager.join_path(target, path, destination)

		canon_path, canon_name = fileManager.canonicalize(target, full_path)
		sanitized_name = fileManager.sanitize_name(target, canon_name)

		if canon_path:
			full_path = fileManager.join_path(target, canon_path, sanitized_name)
		else:
			full_path = sanitized_name

		# prohibit overwriting the file that is currently being printed
		currentOrigin, currentFilename = _getCurrentFile()
		if currentFilename == full_path and currentOrigin == target and (printer.is_printing() or printer.is_paused()):
			make_response("Trying to slice into file that is currently being printed: %s" % full_path, 409)

		if "profile" in data.keys() and data["profile"]:
			profile = data["profile"]
			del data["profile"]
		else:
			profile = None

		if "printerProfile" in data.keys() and data["printerProfile"]:
			printerProfile = data["printerProfile"]
			del data["printerProfile"]
		else:
			printerProfile = None

		if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]:
			position = data["position"]
			del data["position"]
		else:
			position = None

		select_after_slicing = False
		if "select" in data.keys() and data["select"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly select for printing", 409)
			select_after_slicing = True

		print_after_slicing = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			select_after_slicing = print_after_slicing = True

		override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None]
		overrides = dict()
		for key in override_keys:
			overrides[key[len("profile."):]] = data[key]

		def slicing_done(target, path, select_after_slicing, print_after_slicing):
			if select_after_slicing or print_after_slicing:
				sd = False
				if target == FileDestinations.SDCARD:
					filenameToSelect = path
					sd = True
				else:
					filenameToSelect = fileManager.path_on_disk(target, path)
				printer.select_file(filenameToSelect, sd, print_after_slicing, user)

		try:
			fileManager.slice(slicer, target, filename, target, full_path,
			                  profile=profile,
			                  printer_profile_id=printerProfile,
			                  position=position,
			                  overrides=overrides,
			                  display=canon_name,
			                  callback=slicing_done,
			                  callback_args=(target, full_path, select_after_slicing, print_after_slicing))
		except octoprint.slicing.UnknownProfile:
			return make_response("Profile {profile} doesn't exist".format(**locals()), 400)

		files = {}
		location = url_for(".readGcodeFile", target=target, filename=full_path, _external=True)
		result = {
			"name": sanitized_name,
			"path": full_path,
			"display": canon_name,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location,
				"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + full_path
			}
		}

		r = make_response(jsonify(result), 202)
		r.headers["Location"] = location
		return r

	elif command == "analyse":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		printer_profile = None
		if "printerProfile" in data and data["printerProfile"]:
			printer_profile = data["printerProfile"]

		if not fileManager.analyse(target, filename, printer_profile_id=printer_profile):
			return make_response("No analysis possible for {} on {}".format(filename, target), 400)

	elif command == "copy" or command == "move":
		# Copy and move are only possible on local storage
		if not target in [FileDestinations.LOCAL]:
			return make_response("Unsupported target for {}: {}".format(command, target), 400)

		if not _verifyFileExists(target, filename) and not _verifyFolderExists(target, filename):
			return make_response("File or folder not found on {}: {}".format(target, filename), 404)

		path, name = fileManager.split_path(target, filename)

		destination = data["destination"]
		dst_path, dst_name = fileManager.split_path(target, destination)
		sanitized_destination = fileManager.join_path(target, dst_path, fileManager.sanitize_name(target, dst_name))

		if _verifyFolderExists(target, destination) and sanitized_destination != filename:
			# destination is an existing folder and not ourselves (= display rename), we'll assume we are supposed
			# to move filename to this folder under the same name
			destination = fileManager.join_path(target, destination, name)

		is_file = fileManager.file_exists(target, filename)
		is_folder = fileManager.folder_exists(target, filename)

		if not (is_file or is_folder):
			return make_response("{} on {} is neither file or folder, can't {}".format(filename, target, command), 400)

		if command == "copy":
			# destination already there? error...
			if _verifyFileExists(target, destination) or _verifyFolderExists(target, destination):
				return make_response("File or folder does already exist on {}: {}".format(target, destination), 409)

			if is_file:
				fileManager.copy_file(target, filename, destination)
			else:
				fileManager.copy_folder(target, filename, destination)

		elif command == "move":
			if _isBusy(target, filename):
				return make_response("Trying to move a file or folder that is currently in use: {}".format(filename), 409)

			# destination already there AND not ourselves (= display rename)? error...
			if (_verifyFileExists(target, destination) or _verifyFolderExists(target, destination)) \
					and sanitized_destination != filename:
				return make_response("File or folder does already exist on {}: {}".format(target, destination), 409)

			# deselect the file if it's currently selected
			currentOrigin, currentFilename = _getCurrentFile()
			if currentFilename is not None and filename == currentFilename:
				printer.unselect_file()

			if is_file:
				fileManager.move_file(target, filename, destination)
			else:
				fileManager.move_folder(target, filename, destination)

		location = url_for(".readGcodeFile", target=target, filename=destination, _external=True)
		result = {
			"name": name,
			"path": destination,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location
			}
		}
		if is_file:
			result["refs"]["download"] = url_for("index", _external=True) + "downloads/files/" + target + "/" + destination

		r = make_response(jsonify(result), 201)
		r.headers["Location"] = location
		return r

	return NO_CONTENT
Ejemplo n.º 3
0
def gcodeFileCommand(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)

	# valid file commands, dict mapping command name to mandatory parameters
	valid_commands = {
		"select": [],
		"slice": []
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	if command == "select":
		# selects/loads a file
		printAfterLoading = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			printAfterLoading = True

		sd = False
		if target == FileDestinations.SDCARD:
			filenameToSelect = filename
			sd = True
		else:
			filenameToSelect = fileManager.path_on_disk(target, filename)
		printer.select_file(filenameToSelect, sd, printAfterLoading)

	elif command == "slice":
		try:
			if "slicer" in data:
				slicer = data["slicer"]
				del data["slicer"]
				slicer_instance = slicingManager.get_slicer(slicer)

			elif "cura" in slicingManager.registered_slicers:
				slicer = "cura"
				slicer_instance = slicingManager.get_slicer("cura")

			else:
				return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415)
		except octoprint.slicing.UnknownSlicer as e:
			return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400)

		if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]):
			return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415)

		if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()):
			# slicer runs on same device as OctoPrint, slicing while printing is hence disabled
			return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409)

		if "destination" in data and data["destination"]:
			destination = data["destination"]
			del data["destination"]
		elif "gcode" in data and data["gcode"]:
			destination = data["gcode"]
			del data["gcode"]
		else:
			import os
			name, _ = os.path.splitext(filename)
			destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0]

		# prohibit overwriting the file that is currently being printed
		currentOrigin, currentFilename = _getCurrentFile()
		if currentFilename == destination and currentOrigin == target and (printer.is_printing() or printer.is_paused()):
			make_response("Trying to slice into file that is currently being printed: %s" % destination, 409)

		if "profile" in data.keys() and data["profile"]:
			profile = data["profile"]
			del data["profile"]
		else:
			profile = None

		if "printerProfile" in data.keys() and data["printerProfile"]:
			printerProfile = data["printerProfile"]
			del data["printerProfile"]
		else:
			printerProfile = None

		if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]:
			position = data["position"]
			del data["position"]
		else:
			position = None

		select_after_slicing = False
		if "select" in data.keys() and data["select"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly select for printing", 409)
			select_after_slicing = True

		print_after_slicing = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			select_after_slicing = print_after_slicing = True

		override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None]
		overrides = dict()
		for key in override_keys:
			overrides[key[len("profile."):]] = data[key]

		def slicing_done(target, gcode_name, select_after_slicing, print_after_slicing):
			if select_after_slicing or print_after_slicing:
				sd = False
				if target == FileDestinations.SDCARD:
					filenameToSelect = gcode_name
					sd = True
				else:
					filenameToSelect = fileManager.path_on_disk(target, gcode_name)
				printer.select_file(filenameToSelect, sd, print_after_slicing)

		try:
			fileManager.slice(slicer, target, filename, target, destination,
			                  profile=profile,
			                  printer_profile_id=printerProfile,
			                  position=position,
			                  overrides=overrides,
			                  callback=slicing_done,
			                  callback_args=(target, destination, select_after_slicing, print_after_slicing))
		except octoprint.slicing.UnknownProfile:
			return make_response("Profile {profile} doesn't exist".format(**locals()), 400)

		files = {}
		location = url_for(".readGcodeFile", target=target, filename=destination, _external=True)
		result = {
			"name": destination,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location,
				"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + destination
			}
		}

		r = make_response(jsonify(result), 202)
		r.headers["Location"] = location
		return r

	return NO_CONTENT
Ejemplo n.º 4
0
def gcodeFileCommand(filename, target):
    if target not in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
        abort(404)

    if not _validate(target, filename):
        abort(404)

    # valid file commands, dict mapping command name to mandatory parameters
    valid_commands = {
        "select": [],
        "unselect": [],
        "slice": [],
        "analyse": [],
        "copy": ["destination"],
        "move": ["destination"],
    }

    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    user = current_user.get_name()

    if command == "select":
        with Permissions.FILES_SELECT.require(403):
            if not _verifyFileExists(target, filename):
                abort(404)

            # selects/loads a file
            if not octoprint.filemanager.valid_file_type(filename,
                                                         type="machinecode"):
                abort(
                    415,
                    description=
                    "Cannot select file for printing, not a machinecode file",
                )

            if not printer.is_ready():
                abort(
                    409,
                    description=
                    "Printer is already printing, cannot select a new file",
                )

            printAfterLoading = False
            if "print" in data and data["print"] in valid_boolean_trues:
                with Permissions.PRINT.require(403):
                    if not printer.is_operational():
                        abort(
                            409,
                            description=
                            "Printer is not operational, cannot directly start printing",
                        )
                    printAfterLoading = True

            sd = False
            if target == FileDestinations.SDCARD:
                filenameToSelect = filename
                sd = True
            else:
                filenameToSelect = fileManager.path_on_disk(target, filename)
            printer.select_file(filenameToSelect, sd, printAfterLoading, user)

    elif command == "unselect":
        with Permissions.FILES_SELECT.require(403):
            if not printer.is_ready():
                return make_response(
                    "Printer is already printing, cannot unselect current file",
                    409)

            _, currentFilename = _getCurrentFile()
            if currentFilename is None:
                return make_response(
                    "Cannot unselect current file when there is no file selected",
                    409)

            if filename != currentFilename and filename != "current":
                return make_response(
                    "Only the currently selected file can be unselected", 400)

            printer.unselect_file()

    elif command == "slice":
        with Permissions.SLICE.require(403):
            if not _verifyFileExists(target, filename):
                abort(404)

            try:
                if "slicer" in data:
                    slicer = data["slicer"]
                    del data["slicer"]
                    slicer_instance = slicingManager.get_slicer(slicer)

                elif "cura" in slicingManager.registered_slicers:
                    slicer = "cura"
                    slicer_instance = slicingManager.get_slicer("cura")

                else:
                    abort(415,
                          description="Cannot slice file, no slicer available")
            except octoprint.slicing.UnknownSlicer:
                abort(404)

            if not any([
                    octoprint.filemanager.valid_file_type(
                        filename, type=source_file_type)
                    for source_file_type in slicer_instance.
                    get_slicer_properties().get("source_file_types", ["model"])
            ]):
                abort(415, description="Cannot slice file, not a model file")

            cores = psutil.cpu_count()
            if (slicer_instance.get_slicer_properties().get(
                    "same_device", True)
                    and (printer.is_printing() or printer.is_paused())
                    and (cores is None or cores < 2)):
                # slicer runs on same device as OctoPrint, slicing while printing is hence disabled
                abort(
                    409,
                    description=
                    "Cannot slice on this slicer while printing on single core systems or systems of unknown core count due to performance reasons",
                )

            if "destination" in data and data["destination"]:
                destination = data["destination"]
                del data["destination"]
            elif "gcode" in data and data["gcode"]:
                destination = data["gcode"]
                del data["gcode"]
            else:
                import os

                name, _ = os.path.splitext(filename)
                destination = (
                    name + "." + slicer_instance.get_slicer_properties().get(
                        "destination_extensions", ["gco", "gcode", "g"])[0])

            full_path = destination
            if "path" in data and data["path"]:
                full_path = fileManager.join_path(target, data["path"],
                                                  destination)
            else:
                path, _ = fileManager.split_path(target, filename)
                if path:
                    full_path = fileManager.join_path(target, path,
                                                      destination)

            canon_path, canon_name = fileManager.canonicalize(
                target, full_path)
            sanitized_name = fileManager.sanitize_name(target, canon_name)

            if canon_path:
                full_path = fileManager.join_path(target, canon_path,
                                                  sanitized_name)
            else:
                full_path = sanitized_name

            # prohibit overwriting the file that is currently being printed
            currentOrigin, currentFilename = _getCurrentFile()
            if (currentFilename == full_path and currentOrigin == target
                    and (printer.is_printing() or printer.is_paused())):
                abort(
                    409,
                    description=
                    "Trying to slice into file that is currently being printed",
                )

            if "profile" in data and data["profile"]:
                profile = data["profile"]
                del data["profile"]
            else:
                profile = None

            if "printerProfile" in data and data["printerProfile"]:
                printerProfile = data["printerProfile"]
                del data["printerProfile"]
            else:
                printerProfile = None

            if ("position" in data and data["position"]
                    and isinstance(data["position"], dict)
                    and "x" in data["position"] and "y" in data["position"]):
                position = data["position"]
                del data["position"]
            else:
                position = None

            select_after_slicing = False
            if "select" in data and data["select"] in valid_boolean_trues:
                if not printer.is_operational():
                    abort(
                        409,
                        description=
                        "Printer is not operational, cannot directly select for printing",
                    )
                select_after_slicing = True

            print_after_slicing = False
            if "print" in data and data["print"] in valid_boolean_trues:
                if not printer.is_operational():
                    abort(
                        409,
                        description=
                        "Printer is not operational, cannot directly start printing",
                    )
                select_after_slicing = print_after_slicing = True

            override_keys = [
                k for k in data
                if k.startswith("profile.") and data[k] is not None
            ]
            overrides = {}
            for key in override_keys:
                overrides[key[len("profile."):]] = data[key]

            def slicing_done(target, path, select_after_slicing,
                             print_after_slicing):
                if select_after_slicing or print_after_slicing:
                    sd = False
                    if target == FileDestinations.SDCARD:
                        filenameToSelect = path
                        sd = True
                    else:
                        filenameToSelect = fileManager.path_on_disk(
                            target, path)
                    printer.select_file(filenameToSelect, sd,
                                        print_after_slicing, user)

            try:
                fileManager.slice(
                    slicer,
                    target,
                    filename,
                    target,
                    full_path,
                    profile=profile,
                    printer_profile_id=printerProfile,
                    position=position,
                    overrides=overrides,
                    display=canon_name,
                    callback=slicing_done,
                    callback_args=(
                        target,
                        full_path,
                        select_after_slicing,
                        print_after_slicing,
                    ),
                )
            except octoprint.slicing.UnknownProfile:
                abort(404, description="Unknown profile")

            location = url_for(".readGcodeFile",
                               target=target,
                               filename=full_path,
                               _external=True)
            result = {
                "name": destination,
                "path": full_path,
                "display": canon_name,
                "origin": FileDestinations.LOCAL,
                "refs": {
                    "resource":
                    location,
                    "download":
                    url_for("index", _external=True) + "downloads/files/" +
                    target + "/" + full_path,
                },
            }

            r = make_response(jsonify(result), 202)
            r.headers["Location"] = location
            return r

    elif command == "analyse":
        with Permissions.FILES_UPLOAD.require(403):
            if not _verifyFileExists(target, filename):
                abort(404)

            printer_profile = None
            if "printerProfile" in data and data["printerProfile"]:
                printer_profile = data["printerProfile"]

            if not fileManager.analyse(
                    target, filename, printer_profile_id=printer_profile):
                abort(400, description="No analysis possible")

    elif command == "copy" or command == "move":
        with Permissions.FILES_UPLOAD.require(403):
            # Copy and move are only possible on local storage
            if target not in [FileDestinations.LOCAL]:
                abort(400,
                      description="Unsupported target for {}".format(command))

            if not _verifyFileExists(target,
                                     filename) and not _verifyFolderExists(
                                         target, filename):
                abort(404)

            path, name = fileManager.split_path(target, filename)

            destination = data["destination"]
            dst_path, dst_name = fileManager.split_path(target, destination)
            sanitized_destination = fileManager.join_path(
                target, dst_path, fileManager.sanitize_name(target, dst_name))

            # Check for exception thrown by _verifyFolderExists, if outside the root directory
            try:
                if (_verifyFolderExists(target, destination)
                        and sanitized_destination != filename):
                    # destination is an existing folder and not ourselves (= display rename), we'll assume we are supposed
                    # to move filename to this folder under the same name
                    destination = fileManager.join_path(
                        target, destination, name)

                if _verifyFileExists(target,
                                     destination) or _verifyFolderExists(
                                         target, destination):
                    abort(409, description="File or folder does already exist")

            except Exception:
                abort(409,
                      description=
                      "Exception thrown by storage, bad folder/file name?")

            is_file = fileManager.file_exists(target, filename)
            is_folder = fileManager.folder_exists(target, filename)

            if not (is_file or is_folder):
                abort(400,
                      description="Neither file nor folder, can't {}".format(
                          command))

            if command == "copy":
                # destination already there? error...
                if _verifyFileExists(target,
                                     destination) or _verifyFolderExists(
                                         target, destination):
                    abort(409, description="File or folder does already exist")

                if is_file:
                    fileManager.copy_file(target, filename, destination)
                else:
                    fileManager.copy_folder(target, filename, destination)

            elif command == "move":
                with Permissions.FILES_DELETE.require(403):
                    if _isBusy(target, filename):
                        abort(
                            409,
                            description=
                            "Trying to move a file or folder that is currently in use",
                        )

                    # destination already there AND not ourselves (= display rename)? error...
                    if (_verifyFileExists(target, destination)
                            or _verifyFolderExists(target, destination)
                        ) and sanitized_destination != filename:
                        abort(409,
                              description="File or folder does already exist")

                    # deselect the file if it's currently selected
                    currentOrigin, currentFilename = _getCurrentFile()
                    if currentFilename is not None and filename == currentFilename:
                        printer.unselect_file()

                    if is_file:
                        fileManager.move_file(target, filename, destination)
                    else:
                        fileManager.move_folder(target, filename, destination)

            location = url_for(".readGcodeFile",
                               target=target,
                               filename=destination,
                               _external=True)
            result = {
                "name": name,
                "path": destination,
                "origin": FileDestinations.LOCAL,
                "refs": {
                    "resource": location
                },
            }
            if is_file:
                result["refs"]["download"] = (
                    url_for("index", _external=True) + "downloads/files/" +
                    target + "/" + destination)

            r = make_response(jsonify(result), 201)
            r.headers["Location"] = location
            return r

    return NO_CONTENT
Ejemplo n.º 5
0
def gcodeConvertCommand():
    target = FileDestinations.LOCAL

    # valid file commands, dict mapping command name to mandatory parameters
    valid_commands = {"convert": []}
    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    appendGcodeFiles = data['gcodeFilesToAppend']
    del data['gcodeFilesToAppend']

    #	def appendCallback(location, path, sources, **kwargs):
    #		if '_error' in kwargs:
    #			result = kwargs['_error']
    #			return make_response("Could not slice: {result}".format(result=result), 500)
    #		else:
    #			output_path = fileManager.path_on_disk(location, path)
    #			# append additioal gcodes
    #			with open(output_path,'ab') as wfd:
    #				for f in sources:
    #					path = fileManager.path_on_disk(f['origin'], f['name'])
    #					wfd.write( "\n; "+ f['name'] + "\n")
    #
    #					with open(path,'rb') as fd:
    #						shutil.copyfileobj(fd, wfd, 1024*1024*10)
    #
    #					wfd.write( "\nM05\n") # ensure that the laser is off.
    #			#files = {}
    #			#location = url_for(".readGcodeFile", target=target, filename=gcode_name, _external=True)
    #			#result = {
    ##				"name": gcode_name,
    ##				"origin": FileDestinations.LOCAL,
    ##				"refs": {
    ##					"resource": location,
    ##					"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + gcode_name
    ##				}
    ##			}
    #
    #			#r = make_response(jsonify(result), 202)
    #			#r.headers["Location"] = location
    #			#return r

    if command == "convert":
        # TODO stripping non-ascii is a hack - svg contains lots of non-ascii in <text> tags. Fix this!
        import re
        svg = ''.join(i for i in data['svg']
                      if ord(i) < 128)  # strip non-ascii chars like €
        del data['svg']

        import os
        name, _ = os.path.splitext(data['gcode'])

        filename = target + "/temp.svg"

        class Wrapper(object):
            def __init__(self, filename, content):
                self.filename = filename
                self.content = content

            def save(self, absolute_dest_path):
                with open(absolute_dest_path, "w") as d:
                    d.write(self.content)
                    d.close()

        fileObj = Wrapper(filename, svg)
        fileManager.add_file(target,
                             filename,
                             fileObj,
                             links=None,
                             allow_overwrite=True)

        slicer = "svgtogcode"
        slicer_instance = slicingManager.get_slicer(slicer)
        if slicer_instance.get_slicer_properties()["same_device"] and (
                printer.is_printing() or printer.is_paused()):
            # slicer runs on same device as OctoPrint, slicing while printing is hence disabled
            return make_response(
                "Cannot convert while lasering due to performance reasons".
                format(**locals()), 409)

        if "gcode" in data.keys() and data["gcode"]:
            gcode_name = data["gcode"]
            del data["gcode"]
        else:
            import os
            name, _ = os.path.splitext(filename)
            gcode_name = name + ".gco"

        # append number if file exists
        name, ext = os.path.splitext(gcode_name)
        i = 1
        while (fileManager.file_exists(target, gcode_name)):
            gcode_name = name + '.' + str(i) + ext
            i += 1

        # prohibit overwriting the file that is currently being printed
        currentOrigin, currentFilename = _getCurrentFile()
        if currentFilename == gcode_name and currentOrigin == target and (
                printer.is_printing() or printer.is_paused()):
            make_response(
                "Trying to slice into file that is currently being printed: %s"
                % gcode_name, 409)

        if "profile" in data.keys() and data["profile"]:
            profile = data["profile"]
            del data["profile"]
        else:
            profile = None


##
        if "printerProfile" in data.keys() and data["printerProfile"]:
            printerProfile = data["printerProfile"]
            del data["printerProfile"]
        else:
            printerProfile = None

        if "position" in data.keys() and data["position"] and isinstance(
                data["position"],
                dict) and "x" in data["position"] and "y" in data["position"]:
            position = data["position"]
            del data["position"]
        else:
            position = None

        select_after_slicing = False
        if "select" in data.keys() and data["select"] in valid_boolean_trues:
            if not printer.is_operational():
                return make_response(
                    "Printer is not operational, cannot directly select for printing",
                    409)
            select_after_slicing = True

        print_after_slicing = False
        if "print" in data.keys() and data["print"] in valid_boolean_trues:
            if not printer.is_operational():
                return make_response(
                    "Printer is not operational, cannot directly start printing",
                    409)
            select_after_slicing = print_after_slicing = True

        override_keys = [
            k for k in data if k.startswith("profile.") and data[k] is not None
        ]
        overrides = dict()
        for key in override_keys:
            overrides[key[len("profile."):]] = data[key]

        def slicing_done(target, gcode_name, select_after_slicing,
                         print_after_slicing, append_these_files):
            # append additioal gcodes
            output_path = fileManager.path_on_disk(target, gcode_name)
            with open(output_path, 'ab') as wfd:
                for f in append_these_files:
                    path = fileManager.path_on_disk(f['origin'], f['name'])
                    wfd.write("\n; " + f['name'] + "\n")

                    with open(path, 'rb') as fd:
                        shutil.copyfileobj(fd, wfd, 1024 * 1024 * 10)

                    wfd.write("\nM05\n")  # ensure that the laser is off.

            if select_after_slicing or print_after_slicing:
                sd = False
                filenameToSelect = fileManager.path_on_disk(target, gcode_name)
                printer.select_file(filenameToSelect, sd, True)

        try:
            fileManager.slice(slicer,
                              target,
                              filename,
                              target,
                              gcode_name,
                              profile=profile,
                              printer_profile_id=printerProfile,
                              position=position,
                              overrides=overrides,
                              callback=slicing_done,
                              callback_args=[
                                  target, gcode_name, select_after_slicing,
                                  print_after_slicing, appendGcodeFiles
                              ])
        except octoprint.slicing.UnknownProfile:
            return make_response(
                "Profile {profile} doesn't exist".format(**locals()), 400)

        files = {}
        location = url_for(".readGcodeFile",
                           target=target,
                           filename=gcode_name,
                           _external=True)
        result = {
            "name": gcode_name,
            "origin": FileDestinations.LOCAL,
            "refs": {
                "resource":
                location,
                "download":
                url_for("index", _external=True) + "downloads/files/" +
                target + "/" + gcode_name
            }
        }

        r = make_response(jsonify(result), 202)
        r.headers["Location"] = location
        return r

    return NO_CONTENT
Ejemplo n.º 6
0
def gcodeFileCommand(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)

    # valid file commands, dict mapping command name to mandatory parameters
    valid_commands = {"select": [], "slice": []}
    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    if command == "select":
        # selects/loads a file
        printAfterLoading = False
        if "print" in data.keys() and data["print"] in valid_boolean_trues:
            if not printer.is_operational():
                return make_response(
                    "Printer is not operational, cannot directly start printing",
                    409)
            printAfterLoading = True

        sd = False
        if target == FileDestinations.SDCARD:
            filenameToSelect = filename
            sd = True
        else:
            filenameToSelect = fileManager.path_on_disk(target, filename)
        printer.select_file(filenameToSelect, sd, printAfterLoading)

    elif command == "slice":
        try:
            if "slicer" in data:
                slicer = data["slicer"]
                del data["slicer"]
                slicer_instance = slicingManager.get_slicer(slicer)

            elif "cura" in slicingManager.registered_slicers:
                slicer = "cura"
                slicer_instance = slicingManager.get_slicer("cura")

            else:
                return make_response(
                    "Cannot slice {filename}, no slicer available".format(
                        **locals()), 415)
        except octoprint.slicing.UnknownSlicer as e:
            return make_response(
                "Slicer {slicer} is not available".format(slicer=e.slicer),
                400)

        if not octoprint.filemanager.valid_file_type(filename, type="stl"):
            return make_response(
                "Cannot slice {filename}, not an STL file".format(**locals()),
                415)

        if slicer_instance.get_slicer_properties()["same_device"] and (
                printer.is_printing() or printer.is_paused()):
            # slicer runs on same device as OctoPrint, slicing while printing is hence disabled
            return make_response(
                "Cannot slice on {slicer} while printing due to performance reasons"
                .format(**locals()), 409)

        if "gcode" in data and data["gcode"]:
            gcode_name = data["gcode"]
            del data["gcode"]
        else:
            import os
            name, _ = os.path.splitext(filename)
            gcode_name = name + ".gco"

        # prohibit overwriting the file that is currently being printed
        currentOrigin, currentFilename = _getCurrentFile()
        if currentFilename == gcode_name and currentOrigin == target and (
                printer.is_printing() or printer.is_paused()):
            make_response(
                "Trying to slice into file that is currently being printed: %s"
                % gcode_name, 409)

        if "profile" in data.keys() and data["profile"]:
            profile = data["profile"]
            del data["profile"]
        else:
            profile = None


##
        if "printerProfile" in data.keys() and data["printerProfile"]:
            printerProfile = data["printerProfile"]
            del data["printerProfile"]
        else:
            printerProfile = None

        if "position" in data.keys() and data["position"] and isinstance(
                data["position"],
                dict) and "x" in data["position"] and "y" in data["position"]:
            position = data["position"]
            del data["position"]
        else:
            position = None

        select_after_slicing = False
        if "select" in data.keys() and data["select"] in valid_boolean_trues:
            if not printer.is_operational():
                return make_response(
                    "Printer is not operational, cannot directly select for printing",
                    409)
            select_after_slicing = True

        print_after_slicing = False
        if "print" in data.keys() and data["print"] in valid_boolean_trues:
            if not printer.is_operational():
                return make_response(
                    "Printer is not operational, cannot directly start printing",
                    409)
            select_after_slicing = print_after_slicing = True

        override_keys = [
            k for k in data if k.startswith("profile.") and data[k] is not None
        ]
        overrides = dict()
        for key in override_keys:
            overrides[key[len("profile."):]] = data[key]

        def slicing_done(target, gcode_name, select_after_slicing,
                         print_after_slicing):
            if select_after_slicing or print_after_slicing:
                sd = False
                if target == FileDestinations.SDCARD:
                    filenameToSelect = gcode_name
                    sd = True
                else:
                    filenameToSelect = fileManager.path_on_disk(
                        target, gcode_name)
                printer.select_file(filenameToSelect, sd, print_after_slicing)

        try:
            fileManager.slice(slicer,
                              target,
                              filename,
                              target,
                              gcode_name,
                              profile=profile,
                              printer_profile_id=printerProfile,
                              position=position,
                              overrides=overrides,
                              callback=slicing_done,
                              callback_args=(target, gcode_name,
                                             select_after_slicing,
                                             print_after_slicing))
        except octoprint.slicing.UnknownProfile:
            return make_response(
                "Profile {profile} doesn't exist".format(**locals()), 400)

        files = {}
        location = url_for(".readGcodeFile",
                           target=target,
                           filename=gcode_name,
                           _external=True)
        result = {
            "name": gcode_name,
            "origin": FileDestinations.LOCAL,
            "refs": {
                "resource":
                location,
                "download":
                url_for("index", _external=True) + "downloads/files/" +
                target + "/" + gcode_name
            }
        }

        r = make_response(jsonify(result), 202)
        r.headers["Location"] = location
        return r

    return NO_CONTENT