Creating a pdf on digital ocean errno: 34, ENOENT


#1

Hey guys!

I am trying to render a pdf on the server and then attach it to an email.
My code so far:

Meteor.methods({
  'generate_invoice_pdf': function(id) {
    // SETUP
    // Grab required packages
    var webshot = Meteor.npmRequire('webshot');
    var fs = Npm.require('fs');
    var Future = Npm.require('fibers/future');

    var fut = new Future();

    // TODO on server this file can't be created
    // { [Error: ENOENT, open 'invoice.pdf'] errno: 34, code: 'ENOENT', path: 'invoice.pdf' }
    console.log(process.cwd()); // /opt/myAppName/app/programs/server
    var fileName = 'invoice.pdf';


    // PREPARE DATA
    var data = Invoices.findOne(id);
    if (!data) {
      throw new Meteor.Error('Invoice does not exist');
    }
    var template;
    'card' in data ? template = 'invoice_credit_card' : template = 'invoice_on_account';

    // GENERATE HTML STRING
    var css = Assets.getText('invoice_style.css');
    SSR.compileTemplate('layout', Assets.getText('pdf_layout.html'));

    SSR.compileTemplate('invoice_comp_tmpl', Assets.getText(template + '.html'));

    var html_string = SSR.render('layout', {
      css: css,
      template: "invoice_comp_tmpl",
      data: data
    });

    // Setup Webshot options
    var options = {
      "paperSize": {
        "format": "Letter",
        "orientation": "portrait",
        "margin": "1cm"
      },
      siteType: 'html'
    };

    // Commence Webshot
    webshot(html_string, fileName, options, function(err) {
      fs.readFile(fileName, function(err, data) {
        if (err) {
          return console.log(err);
        }
        fs.unlinkSync(fileName);
        fut.return(data);
      });
    });

    // Convert to base64
    var pdfData = fut.wait();
    var b = new Buffer(pdfData).toString('base64');

    return b;
  }
});

The error I’m getting:

{ [Error: ENOENT, open 'invoice.pdf'] errno: 34, code: 'ENOENT', path: 'invoice.pdf' }

On my local machine this works fine.
Do I have to create the file in the public folder?
How would I do that?
Or where can I let server code create new files?

cheers
godo


#2

Sounds like a path/permissions issue; as a quick test, try changing your fileName to include /tmp (which is a wide open writable by all directory):

var fileName = '/tmp/invoice.pdf';

#3

nope ;(
does not work


#4

Not sure that it’s a permission error - if that was the case, webshot should’ve bombed out upon trying to create the file.

ENOENT means that it can’t find the file.


#5

why should it look for the file?
it does not exist…
and why are there permission issues? can’t I just allow my app to create/edit files as it wishes? maybe via ssh and chmod?


#6

@rhywden Right and thanks - “error no entry” - must be Sunday.

@godo15 Looks like there is an open issue for this reported here:

and it looks like the solutions mentioned in the following might help:


#7

I don’t use digital ocean but have seen this error before

Try increasing the delay of webshot

    var options = {
      "renderDelay": 10000,
      "paperSize": {
        "format": "Letter",
        "orientation": "portrait",
        "margin": "1cm"
      },
      siteType: 'html'
    };

#8

fixed it:

added
phantomPath: '/usr/bin/phantomjs'
to the webshot options.

in case somebody else stumbles across this…
packages I use:

npm-container
meteorhacks:npm
dfischer:phantomjs

package.json:

{
  "webshot":"0.15.4"
}
```

route:

this.route(‘invoice’, {
path: ‘/invoice/:_id’,
template: ‘home’,
waitOn: function() {
return Meteor.subscribe(‘invoice’, this.params._id);
},
onAfterAction: function() {
if (Meteor.isServer) {
return;
}

  Meteor.call('generate_invoice_pdf', this.params._id, function(err, res) {
    if (err) {
      console.error(err);
      sAlert.error(err.error);
    } else if (res) {
      window.open("data:application/pdf;base64, " + res);
    }
  });
}

#9

and:

    // Setup Webshot options
    var options = {
      "paperSize": {
        "format": "Letter",
        "orientation": "portrait",
        "margin": "1cm"
      },
      siteType: "html"
    };

    if (process.env.NODE_ENV === "production") {
      options.phantomPath = "/usr/bin/phantomjs";
    } else {
      // process.env.NODE_ENV === "development"
    }