Upload file from JavaScript Client Library


#1

What is the problem?
I can't seem to get to Octoprint from the js-client when uploading a file. It works just fine for other commands like reading printhead temperature.

I am trying:

          var octoClient = new OctoPrintClient({
            baseurl: "http://pi.local", 
            apikey: "key"
          });
          octoClient.files.upload("local", robot.selected_file.content, {
            "filename": robot.selected_file.name,
            "select": true,
            "print": true
          }).done(function(response) {
            console.log(response);
          });

Where robot.selected_file.content is the raw gcode file.

It does not succeed. I get:

angular.js:15567 Error: Syntax error, unrecognized expression: M155 S5
... // The "unrecognized expression" is my gcode file.
G1 X65.126 Y-125.55
jquery.js:1541)
    at Sizzle.tokenize (jquery.js:2193)
    at Sizzle.select (jquery.js:2620)
    at Function.Sizzle [as find] (jquery.js:845)
    at jQuery.fn.init.find (jquery.js:2873)
    at new jQuery.fn.init (jquery.js:2983)
    at jQuery (jquery.js:139)
    at OctoPrintClient.upload (base.js:214)
    at OctoPrintFilesClient.upload (files.js:129)
    at ChildScope.scope.print (bot.js:74)

What did you already try to solve it?
I tried a few things to resolve, but no luck yet. I'm on jQuery 3.3.1 and AngularJS.

Additional information about your setup (OctoPrint version, OctoPi version, printer, firmware, octoprint.log, serial.log or output on terminal tab, ...)
I copied the octoprint js files directly from github, as I am communicating with multiple printers, so I don't want to pull the js files from each individual printer as I switch printers.

EDIT
I tweaked the octoprint base.js a bit to allow my raw gcode file to be sent, which fixed the above error. I changed:

if (typeof file == "string") {
            fileData = $(file)[0].files[0];
}

to:

if (typeof file == "string") {
            fileData = file;
}

This allowed the files to be sent, but I am getting a CORS error now. Not because I didn't enable CORS. CORS is enabled and I have confirmed by seeing the header returned from printer.getFullState().

I think I get the CORS error because there is still some issue in trying to send a raw gcode file to http://pi.local/api/files/

I get:

Access to XMLHttpRequest at 'http://south.local/api/files/' from origin 'http://localhost:9900' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
base.js:283 POST http://south.local/api/files/ net::ERR_FAILED
OctoPrintClient.upload @ base.js:283
OctoPrintFilesClient.upload @ files.js:129
scope.print @ bot.js:78
fn @ VM7620:4
callback @ angular.js:28951
$eval @ angular.js:19393
$apply @ angular.js:19492
(anonymous) @ angular.js:28955
dispatch @ jquery.js:5183
elemData.handle @ jquery.js:4991

When I view the request, it shows the form data is properly sending file, filename, select, and print form data attributes properly.


#2

Regarding your first problem, let's take a look at the documentation:

You gave it a string, which makes it think you are providing it with a selector for an upload element. Give it a File instance that contains your data instead and things should work just fine without any modifications.

About your CORS problem, have you enabled CORS in Settings > API?


#3

Thank you!

I misread the docs. I didn't realize they were referring to the Javascript File() object.

I added:

          var parts = [
            new Blob([robot.selected_file.content], {type: 'text/plain'}),
          ];

          var file = new File(
            parts,
            robot.selected_file.name
          );

          octoClient.files.upload("local", file, {
            "filename": robot.selected_file.name,
            "select": true,
            "print": true
          }).done(function(response) {
            console.log(response);
          });

And it works just fine, without any modifications to base.js.

The CORS problem was due to the failed request. It succeeds all the way through now. :slight_smile: