Reputation: 1538
This is the relevant code :
This sends a request to the server, takes an userName as an argument.
function send_CLIENT_LOOKUP(userName)
{
send(
auth.AOCP.CLIENT_LOOKUP,
[ [ 'S', userName.toString() ]
]
)
}
This part handles the response from the server.
handle[auth.AOCP.CLIENT_LOOKUP] = function (data, u)
{
console.log('CLIENT_LOOKUP')
var userId = u.I()
var userName = u.S()
u.done()
console.log({ userId : userId, userName : userName }) // this works properly
var idResult = userId; // I can actually use the userID but I just assigned it to idResult to make the code easier to understand.
}
The above 2 functions work how they are supposed to, nothing to change/fix there.
Now I have a function that receives a request from one user and sends a request to another user, it takes 2 arguments: first arg is the userId of the user that sends the request and the second is the userName of user the request will be sent to however the server/game only works with userIds so the userName has to be converted:
var commands = {
invite: function(userId, userName) {
send_CLIENT_LOOKUP(userName); // send a request to the server to find out the userId of the userName
send_PRIVGRP_INVITE(idResult);
}
}
The problem is that idResult == undefined, unless I call cmd.invite() again then idResult == 'with the previous response like this:
cmd.invite(user1);
cmd.invite(user2);
cmd.invite(user3);
And the output of idResult is:
idResult == undefined
idResult == 'info for user1'
idResult == 'info for user2'
I tried defining idResult outside response handler and update it inside, to make sure its not some sort of delay from the server I just did a massive invite spam and the result was the same, 1 step behind no matter how fast I sent the invites. Any suggestions are welcome :)
Upvotes: 0
Views: 52
Reputation: 13677
The problem is rather hard to solve, as sending and collecting replies are isolated. It seems that send()
sends a packet and handle()
receives a reply, and there can be many possible unrelated packets between sending and receiving.
If it's the case then a special global map should be created to link requests and responses. For cases when there are 2 concurrent requests for the same username, EventEmitter
from events
module is a good fit, as it's essentially a multimap of strings to callbacks:
var events = require('events')
var outstandingLookups = new events.EventEmitter()
So when you send a lookup you register a one time listener, so there's no need for manual cleanup:
var commands = {
invite: function(userName) {
outstandingLookups.once(userName, function (idResult)
{
send_PRIVGRP_INVITE(idResult);
})
// send a request to the server to find out the userId of the userName
send_CLIENT_LOOKUP(userName);
}
}
In response handler emit
conveniently calls for you all the callbacks expecting userId
for the received userName
:
handle[auth.AOCP.CLIENT_LOOKUP] = function (data, u)
{
console.log('CLIENT_LOOKUP')
var userId = u.I()
var userName = u.S()
u.done()
console.log({ userId : userId, userName : userName }) // this works properly
// I can actually use the userID but I just assigned it to idResult
// to make the code easier to understand.
var idResult = userId;
// this is the only addition to original handler code
outstandingLookups.emit(userName, idResult)
}
The need to use outstandingLookups.once
is actually an implementation detail and it should be properly encapsulated/hidden if you want to lookup userIds in more than one place in the code.
I will use promises from q
npm library as I remember the interface, but similar ES6 promises should be used in production code as they are a modern standard.
var Q = require('q')
var commands = {
lookupUserName: function (userName)
{
var result = Q.defer()
outstandingLookups.once(userName, function (idResult)
{
result.resolve(idResult);
})
// send a request to the server to find out the userId of the userName
send_CLIENT_LOOKUP(userName);
return result.promise
},
invite: function(userName) {
commands.lookupUserName(userName).then(function (idResult)
{
send_PRIVGRP_INVITE(idResult);
})
}
}
The code for commands.invite
is much cleaner now.
Upvotes: 1
Reputation: 6953
It looks like you're doing an async-request but updating the var idResult
synchronously.
So you should put the call to send_PRIVGRP_INVITE(idResult)
into the callback or response handler of send_CLIENT_LOOKUP(userName)
Upvotes: 0