Search code examples
node.jsdialogflow-esfacebook-messenger-botapi-aifacebook-webhooks

Webhook Global Variable


I have created a node.js webhook for my facebook messenger bot. The bot is built in dialog flow and the database is connected to firebase. My question when a function is invoked in the webhook to log in, after logging in, I get a userID from the database, which I want to store it somewhere in the code so that userID info is available throughout the user session. I am storing it in a global variable. However, this works fine if only one user is using the bot. If another user is using the bot at the same time, this userID info is shared between users since this is stored in a global variable. How do I solve this? Please help.

var loggedIn = true;
        for (i = 0; i < contexts.length; i++) {
            console.log("Inside contexts for loop");
            //Check for login details context. 
            if (contexts[i].name == "logindetails") {
                if (contexts[0].parameters.loggedIn == "true") {
                    //set this true if found.
                    loggedIn = true;
                }
            }
        }
        if (loggedIn) {
            showUserAccountOptions(sender);
        }   //else start the login flow and once logged in create the 'logindetails' contexts and set the loggedIn parameter as true.
        else {
            //Login 
            login(email, password);

            //Post the logindetails contexts 
            console.log("Not found");
            let url = "https://api.dialogflow.com/v1/contexts?sessionId=" + response.sessionId;
            console.log("URL", url);
            var con = {
                method: 'POST',
                url: url,
                qs: { access_token: '****' },
                headers: {
                    'content-type': 'application/json',
                    'Authorization': 'Bearer' + ' ****'
                },
                body:
                    [
                        {
                            "lifespan": 25,
                            "name": "logindetails",
                            "parameters": {
                                "loggedIn": "true"
                            }
                        }
                    ],
                json: true
            };

            request(con, function (error, response, body) {
                console.log("Inside api request");
                if (error) {
                    console.log("Inside Error", error);
                }
                else{
                    //show user options
                    showUserAccountOptions(sender);
                }

            });

        }

Sending contexts updates to dialogflow:

    let apirespone = let apirespone = {
                "contexts": [
                    {
                      "name": "logindetails",
                      "parameters": {},
                      "lifespan": 5
                    }
                  ]
                }
                    sendToApiAi(sender,apirespone);

function sendToApiAi(sender, text) {

    sendTypingOn(sender);
    let apiaiRequest = apiAiService.textRequest(text, {
        sessionId: sessionIds.get(sender)
    });

    apiaiRequest.on('response', (response) => {
        if (isDefined(response.result)) {
            handleApiAiResponse(sender, response);
        }
    });



    apiaiRequest.on('error', (error) => console.error(error));
    apiaiRequest.end();
}

Solution

  • Good call! You definitely don't want to store it in a global variable.

    Fortunately, Dialogflow offers a good solution for this.

    In your webhook, you can save the userID and any other session information you want as part of a Context parameter. You can set this as an Outgoing Context in your fulfillment code with a long lifespan and/or re-save this Context each time your webhook is called. You don't provide anything about the code you're currently using in your webhook, but you can see the documentation for how the Context can be part of your response JSON or using libraries.

    To be clear - you can return the Context as part of the JSON in the response. You don't need to make a REST call to set it. Contexts live as long as their lifetime, so once you have set one, it will live for "lifetime" calls during the session, or you can set new ones (or update their lifespan) each time as part of the JSON you return.

    On the next call, you'll be passed all the Contexts that are currently valid. You can find the one that stores the state you've previously saved and get the values from the parameters.

    Update to respond to your code

    You do not need the REST call you're making.

    You can return and update the context in your JSON. You don't show it, but I assume you're creating a response, and adding the context might look something like this:

    {
      "displayText": "Show something",
      "contextOut":[
        "name": "logindetails",
        "lifespan": 25,
        "parameters": {
          "loggedIn": "true"
        }
      ]
    }
    

    At a later point in the conversation, you can resend this in your response to update the information. You might do it like this:

    In your loop where you get the info, you might save the entire context:

            var logindetails;
            if (contexts[i].name == "logindetails") {
                logindetails = contexts[i];
                if (logindetails.parameters.loggedIn == "true") {
                    //set this true if found.
                    loggedIn = true;
                }
            }
    

    You can then change whatever you want in logindetails and when you create the response, do something like this:

    {
      "displayText": "Show something",
      "contextOut":[
        loginDetails
      ]
    }