How to return a sdtout from a server to a client i

2020-05-08 07:48发布

问题:

I'm trying to return the stdout of my method but on the client I always have undefined despite the server says it's a string with content.

I do that:

'getExistingFiles': function () {
      var list = "";
      return new Promise(Meteor.bindEnvironment(function(resolve) {
        child = exec_tool("ls -al",
          function (error, stdout, stderr) {
            if (error !== null) {
              console.error('exec error: ' + error);
              list = "error: " + error;
              resolve(list);
              return list;
            }else{
              list = stdout;
              console.log(typeof list);
              console.log("LIST:------------");
              console.log(list);
              resolve(list);
              return list;
            }
          });
      }));
}

On my terminal I have the logs:

But on the client when I try to access the value it's undefined:

Meteor.call("getExistingFiles",function(list){
       console.log(list);
       console.log(typeof list);
});

So my question is, how could I send this list to the client ?

[EDIT] I tried like this to test if it was my client who was wrong but no it's on the server I think

//server      
var et = Meteor.wrapAsync(exec_tool);
 try {
  child = et('ls -al');
  console.log("LIST:------------");
  console.log(child);
  console.log(typeof child);
  return child;
 } catch (err) {
  throw new Meteor.Error(err, err.stack);
}

[EDIT2] even like this it send a undefined WHY ?!

var et = Meteor.wrapAsync(exec_tool);
      try {
       var proc = exec_tool("ls -al")
       proc.stdout.on('data', function (data) {
         //do something with data
         console.log(data);
         list = list + data;
       });
       proc.stdout.on('end', function() {
         console.log("end");
         console.log(list);
         return list;
       });
      } catch (err) {
       throw new Meteor.Error(err, err.stack);
      }

回答1:

On the server (promises from the server are evaluated and then sent to the client when they're done):

getExistingFiles: function () {
      return new Promise((resolve, reject) => {
        child = exec_tool("ls -al",
          function (error, stdout, stderr) {
            if (error) {
              reject(error);
            } else {
              resolve(stdout);
            }
          });
      }));
}

And on the client:

Meteor.call("getExistingFiles", function(err, list) {
    if(err) {
        // handle your error
        throw err;
    }
    console.log(list);
});

Promises don't have return. Callbacks from async functions usually have the function (error, result) argument list. So, the wanted result should be in the second argument. Try it like this.



回答2:

Looks like this is a dupe question of this

See if this works for you. Async function using fiber/future. Let's tweak this in case you run into issues.

Server.js

  // 
  // Load future from fibers
  var Future = Npm.require("fibers/future");
  // Load exec
  var exec = Npm.require("child_process").exec;

  Meteor.methods({
    runListCommand: function () {
      // This method call won't return immediately, it will wait for the
      // asynchronous code to finish, so we call unblock to allow this client
      // to queue other method calls (see Meteor docs)
      this.unblock();
      var future=new Future();
      var command="cd /home/me/files/; ls *.svg";
      exec(command,function(error,stdout,stderr){
        if(error){
          console.log(error);
          throw new Meteor.Error(500,command+" failed");
        }
        future.return(stdout.toString());
      });
      return future.wait();
    }
  });

Client.js:

  Meteor.call('runListCommand', function (err, response) {
  console.log(response);
});