FirstOfMany FirstOfMany - 4 months ago 15
Javascript Question

Node.js Promise function freezing execution before returning

A node.js app needs to use a Promise to ensure that results from one function have been returned before subsequent commands are run. However, the code below is freezing at the point inside the

getUser(theToken)
promise function is supposed to return its value. What specific changes need to be made to the code below in order for the
getUser(theToken)
promise function to be able to return the valid value that it is generating internally?


app.get('/auth/provider/callback', function(req, res) {
var queryData = url.parse(req.url, true).query;
//This is the end of Step C in the flow
// code was in the GET request, ex: http://localhost:8080/login?code=w6zGJO&state=IuaO63
console.log('Finished Step C of Authorization Code Flow. Welcome back from authserver');
console.log('queryData.code is: ' + queryData.code);
//Now start Step D in the flow
console.log('About to start Step D of Authorization Code Flow. ');
var tokenUrl = oAuthConfig.tokenUrl + '?grant_type=' + oAuthConfig.grantType + '&code='+queryData.code+'&client_id=' + oAuthConfig.clientID + '&redirect_uri=' + oAuthConfig.callbackUrl;
request.post(tokenUrl, function(err, response, body){
if(err){console.log('ERROR with token request.')}
// Step E is the response received as follows:
var data = JSON.parse(body);
console.log('JSON data response is: ' + data);
getUser(data.access_token).then(function(message) {
console.log('in callback, jwtJSON is: ');console.log(message);
res.redirect(somewhere);
});
});
console.log('The POST is finished. Waiting for response.');
console.log('Step D. Token Request Sent To AuthServer.');
});


Then the
getUser(theToken)
function below in the same file is:

function getUser(theToken) {//returns JWT
return new Promise(function(resolve, reject) {
console.log('in getUser, theToken is: ');console.log(theToken);
var jwtJSON = { "token" : "anonymous" };
request({
method: 'GET', url: authServer + '/uaa/user', json: true,
auth: { user: null, password: null, sendImmediately: true, bearer: theToken }
}, function (error, response, body) {
if(error){
console.log('in getUser, ERROR with user request.');console.log(error);
jwtJSON = { "token" : "error" };
return jwtJSON;//
}
else {
var uname = '';var jwtUser = 'empty';
console.log('in getUser, response.statusCode is: ');console.log(response.statusCode);
if(body['name'] && body['name'].length > 0 ){
uname = body['name'];console.log('uname is: ');console.log(uname);
client.exists(uname, function(err, reply) {//Check to see if a Redis key for the user already exists
if (reply === 1) {//a redis key DOES exist
console.log('\"'+uname+'\" exists');
client.expire(uname, 10);//set the key to expire in 10 seconds. use this to manage session length
client.hgetall(uname, function(err, object) {
if(object && object["jwt"]) {
jwtJSON = { "token" : object["jwt"] };
console.log('in getUser, jwtJSON is: ');console.log(jwtJSON);
return jwtJSON;
} else { return jwtJSON; }
});
} else {//a redis key DOES NOT exist
console.log('\"'+uname+'\" doesn\'t exist');
jwtUser = generateJwt(uname, authoritiesLocal);
client.hmset(uname, {//store a hash/object
'jwt' : jwtUser
});
jwtJSON = { "token" : jwtUser };console.log('in getUser, jwtJSON is: ');console.log(jwtJSON);
client.expire(uname, 10);//set the key to expire in 10 seconds. use this to manage session length
return jwtJSON;
}
});//end of Redis conditional block
console.log('jwtJSON is: ');console.log(jwtJSON);
} else { return jwtJSON; }
};
});
});
};


The console printout is:

Finished Step C of Authorization Code Flow. Welcome back from authserver
queryData.code is: 0oxzu6
About to start Step D of Authorization Code Flow.
The POST is finished. Waiting for response.
Step D. Token Request Sent To AuthServer.
JSON data response is: [object Object]
in getUser, theToken is:
eyJ_SomeLongToken_hbG
in getUser, response.statusCode is:
200
uname is:
user
jwtJSON is:
{ token: 'anonymous' }
"user" doesn't exist
in getUser, jwtJSON is:
{ token: 'eyJ_TheSameLongToken_hbG' }


And then the program execution halts for several seconds before the sequence is run a second time, with the second time producing an error because none of the variables remain populated the second time.

Answer

You need to use the resolve and reject arguments instead of returning the value. I've replaced your return statements with resolve and reject. You then pass in the data which should be available in the callback function of then

function getUser(theToken) { //returns JWT
    return new Promise(function(resolve, reject) {
        console.log('in getUser, theToken is: ');
        console.log(theToken);
        var jwtJSON = {
            "token": "anonymous"
        };
        request({
            method: 'GET',
            url: authServer + '/uaa/user',
            json: true,
            auth: {
                user: null,
                password: null,
                sendImmediately: true,
                bearer: theToken
            }
        }, function(error, response, body) {
            if (error) {
                console.log('in getUser, ERROR with user request.');
                console.log(error);
                jwtJSON = {
                    "token": "error"
                };

                /* REJECT INSTEAD OF RETURN */
                reject(jwtJSON);
            } else {
                var uname = '';
                var jwtUser = 'empty';
                console.log('in getUser, response.statusCode is: ');
                console.log(response.statusCode);
                if (body.name && body.name.length > 0) {
                    uname = body.name;
                    console.log('uname is: ');
                    console.log(uname);
                    client.exists(uname, function(err, reply) { //Check to see if a Redis key for the user already exists
                        if (reply === 1) { //a redis key DOES exist
                            console.log('\"' + uname + '\" exists');
                            client.expire(uname, 10); //set the key to expire in 10 seconds.  use this to manage session length
                            client.hgetall(uname, function(err, object) {
                                if (object && object.jwt) {
                                    jwtJSON = {
                                        "token": object.jwt
                                    };
                                    console.log('in getUser, jwtJSON is: ');
                                    console.log(jwtJSON);
                                    /* RESOLVE INSTEAD OF RETURN */
                                    resolve(jwtJSON);
                                } else {
                                    /* RESOLVE INSTEAD OF RETURN */
                                    resolve(jwtJSON);
                                }
                            });
                        } else { //a redis key DOES NOT exist
                            console.log('\"' + uname + '\" doesn\'t exist');
                            jwtUser = generateJwt(uname, authoritiesLocal);
                            client.hmset(uname, { //store a hash/object
                                'jwt': jwtUser
                            });
                            jwtJSON = {
                                "token": jwtUser
                            };
                            console.log('in getUser, jwtJSON is: ');
                            console.log(jwtJSON);
                            client.expire(uname, 10); //set the key to expire in 10 seconds.  use this to manage session length

                            /* RESOLVE INSTEAD OF RETURN */
                            resolve(jwtJSON);
                        }
                    }); //end of Redis conditional block
                    console.log('jwtJSON is: ');
                    console.log(jwtJSON);
                } else {
                    /* RESOLVE INSTEAD OF RETURN */
                    resolve(jwtJSON);
                }
            }
        });
    });
}
Comments