Search code examples
imagemagickmeteornode-fibers

imagemagick in meteorjs (with the help of meteor-router and fibers)


I am unable to use imagemagick in meteorjs. I am working on a small svg->png converter which contains a rest api to provide the converted images. I implemented the rest api with meteor-router. The imagemagick convertion works. But, I am not able to write the result of the convertion into the http response. I tried to fix this by getting rid of the asynchronisity by using fiber. But this still doesn't work. Basically, all request.write calls are ignored after the yield execution. Here is my code:

Meteor.Router.add({
  '/image/:hash' : function(hash) {

    var svg = Images.findOne({'hash' : hash}).svg;

    var request = this.request;
    var response = this.response;

    Fiber(function() {
      var fiber = Fiber.current;

      response.writeHead(200, {'Content-Type':'image/png'});

      var convert = imagemagick.convert(['svg:-', 'png:-']);

      convert.on('data', function(data) {
        response.write("doesn't work");
        //response.write(data);
      });

      convert.on('end', function() {
        response.write("doesn't work");
        //response.end();
        fiber.run({});
      });

      convert.stdin.write(svg);
      convert.stdin.end();

      response.write("works");
      Fiber.yield();
      response.write("doesn't work");
    }).run();

  }
});

I am pretty new to meteorjs. Therefore, I might use Fiber completely wrong. Or I should not use fiber at all. Can someone help?


Solution

  • Thanks to the author from meteor-router, I was able to fix the problem. I was using fiber the wrong way. As described at https://github.com/laverdet/node-fibers#futures, it's not recommended to use fiber without an abstraction between your code and the raw API.

    Fortunately, fiber provides one abstraction called future which can be used for my use case! Here is the working code:

    var require = __meteor_bootstrap__.require,
    Future  = require('fibers/future');
    
    Meteor.startup(function() {
      Meteor.Router.add('/image/:hash', function(hash) {
        var response = this.response;
        var fut = new Future();
    
        response.writeHead(200, {'Content-Type':'text/plain'});
    
        setTimeout(function(){ 
          response.write("hello hello");
          fut.ret();
        }, 1); 
    
        fut.wait();
      });
    });