Question

My stack is Node/Express/Mongo/Jade running on Heroku. I am trying to save a canvas as a png in my filesystem using writeFile.

app.post('/savePlaylist', ensureAuthenticated, function(req, res){

var pl = new Playlist({
  name: req.body.playlistName,
  creatorID: req.user.oauthID,
  creatorName: req.user.name,
  description: req.body.desc,
  songs: []
});

var img = req.body.imgBase64;
var data = img.replace(/^data:image\/\w+;base64,/, "");
var buf = new Buffer(data, 'base64');
//console.log("Buffer:  " + buf);
fs.writeFile('./public/img/coverpics/image-' + pl._id + '.png', buf, function(err){
    if(err){
        console.log(err);
        res.send(500,"Something went wrong...");
    }
    else {

        pl.save(function(error){
          if(error) console.log(error);
          else console.log("PLAYLIST ADDED");
        });
        //console.log(req.body.creatorName + " --- " + req.body.playlistName);
        var redirectURI = '/playlist/' + pl._id;
        //res.send({redirect: redirectURI});
        res.send("success");
    }
});
});

The problem is that I see no error running this and get success in return. But once I try to access/link /img/coverpics/image-<id>.png from my HTML I get a 404. Also I cannot see any image on my Heroku directory.

p.s. CORS is enabled and I am getting the buffer properly but the problem seems to exist while writing. The coverpics directory exists.

EDIT: Changed title for relevance.

Was it helpful?

Solution

Ok so Heroku provides a Read-only file system and doesn't have any form of persistent/writeable file storage. So I switched to Amazon S3 for static storage. Also because it seemed to be a good practice. It was surprisingly easy to setup.

I used knox for posting the data to AWS.

//create knox AWS client.
var AWSclient = knox.createClient({
  key: config.AWS.key,
  secret: config.AWS.secret,
  bucket: config.AWS.bucket
});

//on post save to S3
app.post('/savePlaylist', ensureAuthenticated, function(req, res){
    var pl = new Playlist({
      name: req.body.playlistName,
      creatorID: req.user.oauthID,
      creatorName: req.user.name,
      description: req.body.desc,
      songs: []
    });
    var img = req.body.imgBase64;
    var data = img.replace(/^data:image\/\w+;base64,/, "");
    var buf = new Buffer(data, 'base64');

    var re = AWSclient.put(pl._id+'.png', {
      'Content-Length': buf.length,
      'Content-Type': 'img/png'
    });
    re.on('response', function(resp){
      if(200 == resp.statusCode) {
        console.log("Uploaded to" + re.url);
        pl.coverImg = re.url; //prepare to save image url in the database
        pl.save(function(error){
          if(error) console.log(error);
          else{
             var ruri = '/playlist?id=' + pl._id;
             res.send({redirect: ruri});
          }
        });
      }
      else
        console.log("ERROR");
    });
    re.end(buf);
});

To be complete, here is how I post the canvas data from the frontend -

var form = $('#createPLForm').serializeArray();
var canvas = document.getElementById('myCanvas');
var dataURL = canvas.toDataURL();
$.ajax({
  type: "POST",
  url: "/savePlaylist",
  data: { 
     imgBase64: dataURL,
     playlistName: form[0].value,
     desc: form[1].value
        },
  dataType: 'json',
  success: function(data, textStatus, jqXHR){
    if(jQuery.type(data.redirect) == 'string')
        window.location = data.redirect;
    }
});

Note: Make sure CORS is enabled if canvas has images from other domains to prevent tainting.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top