Reputation: 45
I am working on a DialogFlow project using Firebase Cloud function. I send a GET request to my API and I receive back data from the server, then display it on fulfillment text property. That's fine.
Now I need to store in a sort of "application variable" the cookie session id from the server, in order to keep track of the interactions between client and server. I try to save the cookie session in a Context object, in doing so I get the error :
Agent.getContext is not a function at IncomingMessage.resp
Here is the code:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest( ( req, resp ) =>{
const agent = new WebhookClient( {request: req, response: resp} );
//SET CONTEXT HERE
const context = {
'name': 'sessione',
'lifespan': 2,
'parameters': {'idSessione': c.sessionID}
};
agent.setContext( context );
if( context ){
console.log( '*--*****************-- name context =' + context.name );
}
//...some stuff etc-
//call my function to consume API
callAVA( strRicerca ).then( ( strOutput ) =>{
return resp.json( {'fulfillmentText': strOutput} );
} ).catch( ( error ) =>{
return resp.json( {'fulfillmentText': 'error error'} );
} );
} );
// added parameter Agent-
function callAVA( agent, strRicerca ){
return new Promise( ( resolve, reject ) =>{
https.get( options, ( resp ) =>{
//variable options contains set cookies values , host name etc-
let data = '';
// A chunk of data has been recieved.
resp.on( 'data', ( chunk ) =>{
data += chunk;
} );
// The whole response has been received. Print out the result.
resp.on( 'end', () =>{
let c = JSON.parse( data );
let strOutput = c.output[0].output;
console.log( '----- ID DELLA SESSIONE : ' + c.sessionID );
if( c.sessionID ){
// I NEED TO SAVE IDSESSION FROM SERVER -
let context = agent.getContext( 'sessione' );
// GOT ERROR: agent.getContext is not a function at IncomingMessage.resp (????)
context.parameters.idSessione = c.sessionID;
}
resolve( strOutput );
//DO OTHER STUFF...
} );
resp.on( "error", ( err ) =>{
console.log( "Error: " + err.message );
reject( err.message );
} );
} );
} );
}
Is there any other way to keep track of the user who is sending request to the server? I would prefer to keep things simple without accessing databases...Thanks a lot, any help would be really appreciated. :)
__________________________________EDIT________________________________ Putting context aside for a moment, I realize I am missing some points, so I've modify my code as follows according to your suggestions:
const functions = require('firebase-functions');
const querystring = require('querystring');
const {WebhookClient} = require('dialogflow-fulfillment');
const https = require('http');
postData = querystring.stringify({
'searchText': 'ciao',
'user':'',
'pwd':'',
'ava':'FarmaInfoBot'
});
const options = {
hostname: '86.107.98.69',
port: 8080,
path: ‘/mypath/search_2?searchText=',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
'Cookie':'JSESSIONID=' // -> this comes from the server, store it in context, conv.data or what else-> to do
}
};
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((req, resp) => {
const agent = new WebhookClient({ request: req, response: resp});
let strRicerca='';
if (req.body.queryResult.parameters['searchText']) {
strRicerca=req.body.queryResult.parameters['searchText'];
options.path+=strRicerca+'&user=&pwd=&ava=FarmaInfoBot';
}
/* IS THIS OK NOW TO INVOKE FUNCTION LIKE THIS, NOW THAT I ADDED AGENT ? */
callAVA(agent, strRicerca).then((strOutput)=> {
return resp.json({ 'fulfillmentText': strOutput });
}).catch((error) => {
return resp.json({ 'fulfillmentText': 'error!!!!!!!!!!'});
});
function callAVA(agent, strRicerca) {
return new Promise((resolve, reject) => {
https.get(options, (resp) => {
let data = '';
console.log(`STATUS RESPONSE: ${resp.statusCode}`);
console.log(`HEADERS RESPONSE: ${JSON.stringify(resp.headers)}`);
resp.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
var c=JSON.parse(chunk);
});
resp.on('end', () => {
let c=JSON.parse(data);
let strOutput= agent.add('Static response from Agent'); // c.output[0].output;
console.log(strOutput);
resolve(strOutput);
});
resp.on("error", (err) => {
console.log("Error: " + err.message);
reject(err.message);
});
});
});
}
let intentMap = new Map();
intentMap.set('test_fb', callAVA);
agent.handleRequest(intentMap);
});
Now the program is running but I receive an empty response, the crash happens in the end event, parsing Json data. My aim at last is to find a way to save cookie from server in a global variable and keep it across conversation.
Upvotes: 3
Views: 1681
Reputation: 50741
It looks like there are a few problems here.
The immediate cause if your error is that you have defined the callAVA()
function as
function callAVA( agent, strRicerca )
but when you're calling it a few lines earlier, you are omitting the agent
parameter:
callAVA( strRicerca )
However, there are other problems with how you're using it that will cause you problems in the long-run.
While what you're doing may be valid, and may work, it is also different than how processing typically works, and it may be that you may be causing some problems with this.
Typically, you create the agent
, as you have, and then register Intent Handlers against it. Something like
let intentMap = new Map();
intentMap.set('intent.name.1', intentHandlerFunction1);
intentMap.set('intent.name.2', intentHandlerFunction2);
agent.handleRequest(intentMap);
which will call the matching function for the Intent name with a single parameter, the agent
. (As an aside - good job returning a Promise! You have that part correct.)
As part of an Intent handler, you'll want to call agent.setContext(context)
before your Promise finishes. In a later Intent handler, when you want to know the value, you need to call agent.getContext('context-name')
which should return the entire Context object, including the remaining lifespan and the parameters for it..
Update
The change you made in your first edit isn't enough. The problem is that you're mixing two different ways to call the Intent Handler:
In one way, you're calling it directly with the second parameter. As part of the results, it is sending JSON to the resp
object.
In the other way, you've registered it with intentMap.set()
which is causing it to get called (with just the agent
parameter) when handleRequest()
is called and it is setting a response through the agent
object.
In general, unless you want to manipulate all the JSON yourself, you should rely on method (2). You should not call the Intent Handler function directly yourself, but instead let handleRequest()
handle it for you.
Since you need the strRicerca
object, you can make that available in the same scope the function runs in, which it already seems to be. So you probably don't need to include it as a parameter.
Upvotes: 2