diff --git a/package-lock.json b/package-lock.json index 3dd092c..a255b75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bbctrl", - "version": "1.0.10b4", + "version": "1.0.10b5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bbctrl", - "version": "1.0.10b4", + "version": "1.0.10b5", "license": "GPL-3.0+", "dependencies": { "browserify": "^17.0.0", diff --git a/package.json b/package.json index 0610ea7..df02d86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bbctrl", - "version": "1.0.10b4", + "version": "1.0.10b5", "homepage": "https://onefinitycnc.com/", "repository": "https://github.com/OneFinityCNC/onefinity", "license": "GPL-3.0+", diff --git a/src/js/control-view.js b/src/js/control-view.js index 856a263..d3a65d3 100644 --- a/src/js/control-view.js +++ b/src/js/control-view.js @@ -398,18 +398,13 @@ module.exports = { return; } - const fd = new FormData(); - - fd.append('gcode', file); - - try { - await api.upload('file', fd); - - this.last_file_time = undefined; // Force reload - this.$broadcast('gcode-reload', file.name); - } catch (err) { - api.alert('Upload failed', err) - } + SvelteComponents.showDialog("Upload", { + file, + onComplete: () => { + this.last_file_time = undefined; // Force reload + this.$broadcast('gcode-reload', file.name); + } + }); }, delete_current: function () { @@ -530,7 +525,7 @@ module.exports = { this.send(JSON.stringify(data)); }, - showProbeDialog: function(probeType) { + showProbeDialog: function (probeType) { SvelteComponents.showDialog("Probe", { probeType }); } }, diff --git a/src/py/bbctrl/FileHandler.py b/src/py/bbctrl/FileHandler.py index ad6a24e..33d5eb3 100644 --- a/src/py/bbctrl/FileHandler.py +++ b/src/py/bbctrl/FileHandler.py @@ -1,34 +1,8 @@ -################################################################################ -# # -# This file is part of the Buildbotics firmware. # -# # -# Copyright (c) 2015 - 2018, Buildbotics LLC # -# All rights reserved. # -# # -# This file ("the software") is free software: you can redistribute it # -# and/or modify it under the terms of the GNU General Public License, # -# version 2 as published by the Free Software Foundation. You should # -# have received a copy of the GNU General Public License, version 2 # -# along with the software. If not, see . # -# # -# The software is distributed in the hope that it will be useful, but # -# WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # -# Lesser General Public License for more details. # -# # -# You should have received a copy of the GNU Lesser General Public # -# License along with the software. If not, see # -# . # -# # -# For information regarding this software email: # -# "Joseph Coffland" # -# # -################################################################################ - import os +import tempfile import bbctrl import glob -import html +import tornado from tornado import gen from tornado.web import HTTPError @@ -36,17 +10,32 @@ from tornado.web import HTTPError def safe_remove(path): try: os.unlink(path) - except OSError: pass + except OSError: + pass +@tornado.web.stream_request_body class FileHandler(bbctrl.APIHandler): - def prepare(self): pass + def prepare(self): + if self.request.method == 'PUT': + self.request.connection.set_max_body_size(2 ** 30) + self.uploadFilename = self.request.path.split('/')[-1] \ + .replace('\\', '/') \ + .replace('#', '-') \ + .replace('?', '-') + + self.uploadFile = tempfile.NamedTemporaryFile("wb") + + def data_received(self, data): + if self.request.method == 'PUT': + self.uploadFile.write(data) def delete_ok(self, filename): if not filename: # Delete everything - for path in glob.glob(self.get_upload('*')): safe_remove(path) + for path in glob.glob(self.get_upload('*')): + safe_remove(path) self.get_ctrl().preplanner.delete_all_plans() self.get_ctrl().state.clear_files() @@ -57,26 +46,29 @@ class FileHandler(bbctrl.APIHandler): self.get_ctrl().preplanner.delete_plans(filename) self.get_ctrl().state.remove_file(filename) - def put_ok(self, *args): - gcode = self.request.files['gcode'][0] - filename = os.path.basename(gcode['filename'].replace('\\', '/')) - filename = filename.replace('#', '-').replace('?', '-') + if not os.path.exists(self.get_upload()): + os.mkdir(self.get_upload()) - if not os.path.exists(self.get_upload()): os.mkdir(self.get_upload()) + filename = self.get_upload(self.uploadFilename).encode('utf8') + safe_remove(filename) + os.link(self.uploadFile.name, filename) - with open(self.get_upload(filename).encode('utf8'), 'wb') as f: - f.write(gcode['body']) - os.sync() + self.uploadFile.close() - self.get_ctrl().preplanner.invalidate(filename) - self.get_ctrl().state.add_file(filename) - self.get_log('FileHandler').info('GCode received: ' + filename) + del(self.uploadFile) + self.get_ctrl().preplanner.invalidate(self.uploadFilename) + self.get_ctrl().state.add_file(self.uploadFilename) + self.get_log('FileHandler').info( + 'GCode received: ' + self.uploadFilename) + + del(self.uploadFilename) @gen.coroutine def get(self, filename): - if not filename: raise HTTPError(400, 'Missing filename') + if not filename: + raise HTTPError(400, 'Missing filename') filename = os.path.basename(filename) try: @@ -84,6 +76,7 @@ class FileHandler(bbctrl.APIHandler): self.write(f.read()) except Exception: self.get_ctrl().state.select_file('') - raise HTTPError(400, "Unable to read file - doesn't appear to be GCode.") + raise HTTPError( + 400, "Unable to read file - doesn't appear to be GCode.") self.get_ctrl().state.select_file(filename) diff --git a/src/svelte-components/src/dialogs/DialogHost.svelte b/src/svelte-components/src/dialogs/DialogHost.svelte index 1a03f68..fdf7cd9 100644 --- a/src/svelte-components/src/dialogs/DialogHost.svelte +++ b/src/svelte-components/src/dialogs/DialogHost.svelte @@ -3,6 +3,7 @@ import HomeMachineDialog from "$dialogs/HomeMachineDialog.svelte"; import ProbeDialog from "$dialogs/ProbeDialog.svelte"; import ScreenRotationDialog from "$dialogs/ScreenRotationDialog.svelte"; + import UploadDialog from "$dialogs/UploadDialog.svelte"; const HomeMachineDialogProps = writable(); type HomeMachineDialogPropsType = { @@ -16,11 +17,17 @@ probeType: "xyz" | "z"; }; - const ScreenRotationDialogProps = writable(); + const ScreenRotationDialogProps = writable(); type ScreenRotationDialogPropsType = { open: boolean; }; + const UploadDialogProps = writable(); + type UploadDialogPropsType = { + open: boolean; + file: File; + }; + export function showDialog( dialog: "HomeMachine", props: Omit @@ -31,6 +38,16 @@ props: Omit ); + export function showDialog( + dialog: "ScreenRotation", + props: Omit + ); + + export function showDialog( + dialog: "Upload", + props: Omit + ); + export function showDialog(dialog: string, props: any) { switch (dialog) { case "HomeMachine": @@ -45,6 +62,10 @@ ScreenRotationDialogProps.set({ ...props, open: true }); break; + case "Upload": + UploadDialogProps.set({ ...props, open: true }); + break; + default: throw new Error(`Unknown dialog '${dialog}`); } @@ -54,3 +75,4 @@ + diff --git a/src/svelte-components/src/dialogs/UploadDialog.svelte b/src/svelte-components/src/dialogs/UploadDialog.svelte new file mode 100644 index 0000000..2849ff4 --- /dev/null +++ b/src/svelte-components/src/dialogs/UploadDialog.svelte @@ -0,0 +1,74 @@ + + + + + Uploading {#if file}{file.name}...{/if} + + + + + + + + + +