openscad-remote/openscad_remote.py

112 lines
2.8 KiB
Python

from flask import (
Flask,
request,
abort,
Response
)
from flask_cors import cross_origin
import os
from uuid import uuid4
import subprocess
import shutil
import io
from werkzeug.wsgi import FileWrapper
app = Flask(__name__)
@app.route("/", methods=['POST'])
@cross_origin(expose_headers=["content-disposition"])
def upload_files():
project_id = str(uuid4())
main_file = get_and_save_file(request, "main-file", project_id)
if main_file is False:
abort(400)
project_folder = f"/data/build/{project_id}"
if not os.path.exists(project_folder):
os.makedirs(project_folder)
file_name = ".".join(main_file.split("/")[-1].split(".")[:-1])
result_file_path = f"{project_folder}/{file_name}.stl"
command = [
"openscad",
"-o", result_file_path
]
param_file = get_and_save_file(request, "param-file", project_id)
if param_file is not False:
command.extend(["-p", param_file])
keys = list(request.files.keys())
keys.remove("main-file")
try:
keys.remove("param-file")
except ValueError:
print("List does not contain value")
# Add other files
for key in keys:
get_and_save_file(request, key, project_id)
# Add main file at the end of the command and run it!
command.append(main_file)
subprocess.run(command, cwd=project_folder)
# Store the file in memory so it can be removed but still served
return_data = io.BytesIO()
with open(result_file_path, 'rb') as fo:
return_data.write(fo.read())
# (after writing, cursor will be at last byte, so move it to start)
return_data.seek(0)
# Remove the files
shutil.rmtree(f"/data/upload/{project_id}")
os.remove(result_file_path)
# Wrap the data in a FileWrapper for uWSGI and set its headers
w = FileWrapper(return_data)
headers = {
'Content-Disposition': f"attachment; filename='{file_name}.stl'"
}
# Send the generated file
return Response(w, mimetype="application/stl",
direct_passthrough=True, headers=headers)
def get_and_save_file(request, fileId, projectId):
# Check if the file we're requesting is in the request
if fileId not in request.files:
return False
project_path = os.path.join("/data/upload", projectId)
# Check if folder for project exist, create it if it doesn't exist
if not os.path.exists(project_path):
os.makedirs(project_path)
f = request.files[fileId]
# Check if the uploaded file is a file or an empty field
if f.filename == "":
return False
file_path = os.path.join(project_path, f.filename)
# Check if the file exists already
if os.path.exists(file_path):
return False
f.save(file_path)
return file_path
if __name__ == "__main__":
app.run()