timklge / node-teamspeak

TeamSpeak (R)-ServerQuery-Library for node.js
Other
43 stars 16 forks source link

Functions not synchronous #34

Open muuvmuuv opened 8 years ago

muuvmuuv commented 8 years ago

Hey I#m currectly working on an MEAN-Stack project and using node-teamspeak for pulling some information about specific clients. The problem is I cant return a valid result, because the function are asyncronous.

Maybe some one knows a better solution or add this functionality to the repo.

Here the code:

function CompareTeamspeakClients(forumUsers) {
  var deferred = Q.defer();
  var cl = new TeamSpeakClient("127.0.0.1");

  cl.send("login", {client_login_name: "serveradmin", client_login_password: "M+h8YzUA"}, function(err, response, rawResponse){
    if (err) deferred.reject(err);

    cl.send("use", {port: 9987}, function(err, response, rawResponse){
      if (err) deferred.reject(err);

      forumUsers.forEach(function(user, index){
        cl.send("clientdbfind", ["uid"], {pattern: user.tsid}, function(err, response, rawResponse){
          if (err) {
            deferred.reject(err);
          } else {
            cl.send("clientdbinfo", {cldbid: response.cldbid}, function(err, response, rawResponse){
              if (err) deferred.reject(err);

              forumUsers[index]['tsdbid'] = response.client_database_id;
              forumUsers[index]['tsnickname'] = response.client_nickname;
              forumUsers[index]['tslastconnected'] = response.client_lastconnected;
            });
          }
        });
      });
    });
  });

  deferred.resolve(forumUsers);

  return deferred.promise;
}

Thanks

starwolfy commented 8 years ago

Your function is returning a value while at the same time it is still executing the TeamSpeak queries.

function CompareTeamspeakClients(forumUsers) {
  var deferred = Q.defer();
  var cl = new TeamSpeakClient("127.0.0.1");

  cl.send("login", {client_login_name: "serveradmin", client_login_password: "M+h8YzUA"}, function(err, response, rawResponse){
    if (err) deferred.reject(err);

    cl.send("use", {port: 9987}, function(err, response, rawResponse){
      if (err) deferred.reject(err);

      forumUsers.forEach(function(user, index){
        cl.send("clientdbfind", ["uid"], {pattern: user.tsid}, function(err, response, rawResponse){
          if (err) {
            deferred.reject(err);
          } else {
            cl.send("clientdbinfo", {cldbid: response.cldbid}, function(err, response, rawResponse){
              if (err) deferred.reject(err);

              forumUsers[index]['tsdbid'] = response.client_database_id;
              forumUsers[index]['tsnickname'] = response.client_nickname;
              forumUsers[index]['tslastconnected'] = response.client_lastconnected;

              // I have no clue what deffered.resolve does but I'm assuming it has to be moved here too.
              deferred.resolve(forumUsers);
              return deferred.promise;

            });
          }
        });
      });
    });
  });
}
muuvmuuv commented 8 years ago

@nikitavondel but this will return the result many times (depending of the database). Can I not just use is syncronous?

// foreach..
var response = cl.send("clientdbfind", ["uid"], {pattern: user.tsid});
// other code...
// endforeach
console.log(response);
starwolfy commented 8 years ago

@muuvmuuv Sorry I did not see you were performing a foreach loop, as far as I am concerned you cannot execute this synchronously unless you really want to rewrite the code. I recommend keeping track of when you are in the last foreach loop and then returning a large object or array which has the results of all loops stored. (I am just brainstorming with you here, it might not make perfect sense in your scenario)

iglosiggio commented 7 years ago

You can promisify the send function to make your life easier, then you can resolve to a promise generated from Promise.all

Example (i'm using v8 native promises, arrow functions and varargs):

function CompareTeamspeakClients(forumUsers) {
    const cl = new TeamSpeakClient("127.0.0.1");
    /* Promisified send */
    function send(...args) {
        return new Promise((accept, reject) =>
            cl.send(...args,  (err, response) => {
                if(err) reject(err);
                else accept(response);
            }));
    }
    return send("login", {client_login_name: "serveradmin", client_login_password: "M+h8YzUA"})
        .then(() => send("use", {port: 9987}))
        .then(() => Promise.all(forumUsers.map((user) =>
            send("clientdbfind", ["uid"], {pattern: user.tsid})
                .then((response) => ({
                    tsdbid: response.client_database_id,
                    tsnickname: response.client_nickname,
                    tslastconnected: response.client_lastconnected
                })
            )
        );
}
antoine-pous commented 6 years ago

You can use my client which is more advanced and implement promises.

https://github.com/antoine-pous/node-teamspeak3-client