0

I have the following code:

Meteor.methods({
  saveFile: function(blob, name, path, encoding) {
    var path = cleanPath(path), fs = __meteor_bootstrap__.require('fs'),
      name = cleanName(name || 'file'), encoding = encoding || 'binary',
      chroot = Meteor.chroot || 'public';
    // Clean up the path. Remove any initial and final '/' -we prefix them-,
    // any sort of attempt to go to the parent directory '..' and any empty directories in
    // between '/////' - which may happen after removing '..'
    path = chroot + (path ? '/' + path + '/' : '/');

    // TODO Add file existance checks, etc...
    fs.writeFile(path + name, blob, encoding, function(err) {
      if (err) {
        throw (new Meteor.Error(500, 'Failed to save file.', err));
      } else {
        console.log('The file ' + name + ' (' + encoding + ') was saved to ' + path);
      }
    }); 

    function cleanPath(str) {
      if (str) {
        return str.replace(/\.\./g,'').replace(/\/+/g,'').
          replace(/^\/+/,'').replace(/\/+$/,'');
      }
    }
    function cleanName(str) {
      return str.replace(/\.\./g,'').replace(/\//g,'');
    }
  }
});

Which I took from this project https://gist.github.com/dariocravero/3922137

The code works fine, and it saves the file, however it repeats the call several time and each time it causes meteor to reset using windows version 0.5.4. The F12 console ends up looking like this: enter image description here. The meteor console loops over the startup code each time the 503 happens and repeats the console logs in the saveFile function.

Furthermore in the target directory the image thumbnail keeps displaying and then display as broken, then a valid thumbnail again, as if the fs is writing it multiple times.

Here is the code that calls the function:

"click .savePhoto":function(e, template){
    e.preventDefault();
     var MAX_WIDTH = 400;
    var MAX_HEIGHT = 300;
    var id = e.srcElement.id;
    var item = Session.get("employeeItem");
    var file = template.find('input[name='+id+']').files[0];
  // $(template).append("Loading...");
  var dataURL = '/.bgimages/'+file.name;
    Meteor.saveFile(file, file.name, "/.bgimages/", function(){
        if(id=="goodPhoto"){
            EmployeeCollection.update(item._id, { $set: { good_photo: dataURL }});
        }else{
            EmployeeCollection.update(item._id, { $set: { bad_photo: dataURL }});
        }
        // Update an image on the page with the data
        $(template.find('img.'+id)).delay(1000).attr('src', dataURL);
    });     



},

What's causing the server to reset?

tshepang
  • 12,111
  • 21
  • 91
  • 136
rickyduck
  • 4,030
  • 14
  • 58
  • 93

1 Answers1

3

My guess would be that since Meteor has a built-in "automatic directories scanning in search for file changes", in order to implement auto relaunching of the application to newest code-base, the file you are creating is actually causing the server reset.

Meteor doesn't scan directories beginning with a dot (so called "hidden" directories) such as .git for example, so you could use this behaviour to your advantage by setting the path of your files to a .directory of your own.

You should also consider using writeFileSync insofar as Meteor methods are intended to run synchronously (inside node fibers) contrary to the usual node way of asynchronous calls, in this code it's no big deal but for example you couldn't use any Meteor mechanics inside the writeFile callback.

asynchronousCall(function(error,result){
    if(error){
        // handle error
    }
    else{
        // do something with result
        Collection.update(id,result);// error ! Meteor code must run inside fiber
    }
});

var result=synchronousCall();
Collection.update(id,result);// good to go !

Of course there is a way to turn any asynchronous call inside a synchronous one using fibers/future, but that's beyond the point of this question : I recommend reading this EventedMind episode on node future to understand this specific area.

saimeunt
  • 22,666
  • 2
  • 56
  • 61
  • @saimeunit thanks for the answer. The bgimages folder resides in public, so shouldn't that be ignored by the change poll anyways? Anyhow, I changed the folder name to `.bgimages` but to no avail, the same thing happens – rickyduck Jul 16 '13 at 12:25
  • I also tried: http://stackoverflow.com/questions/13201723/generating-and-serving-static-files-with-meteor but changed the `NPM.require` to the 0.5.4 `__meteor_bootstrap__.require` - but I get an exited with code: 1 – rickyduck Jul 16 '13 at 12:34
  • @saimeunit is right, and unfortunately, `public` folder is not ignored by Meteor due to some caching, or whatever is done there. Using a folder name starting by dot should have helped, though, if that were the only problem. If that failed, try to store files in a directory outside of Meteor application - you'll probably get permission issues, but it may be worth a shot. – Hubert OG Jul 16 '13 at 12:37
  • @HubertOG it is in fact appending the folder with `~` that makes it ignored (`bgimages~`) but this leads to the obvious problem that it's ignored - so the uploaded file doesn't get put into the app. – rickyduck Jul 16 '13 at 12:41
  • @HubertOG I have tried outside of the directory to no avail. It seems a shame that such promising software like meteor can't even handle basic image upload. – rickyduck Jul 16 '13 at 13:05
  • It works, I've achieved similar behaviour within my own app ;) Try removing the beginning "/" from your path (".bgimages/"), the folder should reside at the root of your meteor app, ie "myapp/.bgimages". Also, are you sure that relative paths are handled correctly ? The Current Working Directory inside meteor server side code should be the app directory, but you better check that too. – saimeunt Jul 16 '13 at 13:40
  • Yes, it's too bad it's not as simple as it should be. But there are few things to note. 1) Meteor is still in beta stage, and this is not the only one functionality that will be added later. 2) It's no longer a basic task - these days most files are not hosted on the application server, but somewhere else - like S3 cloud. 3) You can put the files in the ignored directory and then serve them yourself with a node.js middleware - it's actually pretty easy task. – Hubert OG Jul 16 '13 at 18:30