尝试使用内联编辑器将 mongoDB 集成到 Dialogflow
Trying to integrate mongoDB to Dialogflow with inline editor
我正在尝试将 mongoDB 集成到 Dialogflow。更具体地说,我正在尝试使用 DialogFlow 更改安装在 AWS EC2 实例中的 MongoDB 数据库中名为 'lightState' 的特定数据字段的值。当我说 'Turn the light on' 时,数据 'lightState' 必须更新为值 1,相反则更新为 0。
在开始真正的问题之前,我将post我的代码如下:
var tunnel = require('tunnel-ssh');
var mongoLib = require('mongodb');
var config = {
username: 'ubuntu',
host: <my-host-ip-address>,
port: 22,
privateKey: <my-aws-instance-private-key>
dstHost: '127.0.0.1',
dstPort: 27017,
localPort: 24800
};
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({request, response});
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
var server = tunnel(config, function(error, server){
if(error) throw error;
else {
if(server != null){
var Client = mongoLib.MongoClient('mongodb://127.0.0.1:24601/',{useUnifiedTopology:true, auto_reconnect: true});
var conn = Client.connect(function(error, client){
if(error) console.log(error);
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function handleOn(agent)
{
const state = agent.parameters.on;
var doc = {};
client.db('test_db').collection('light').find().toArray(function(err,docs){
doc = docs; //retrieve the data format
});
if(state == 1) client.db('test_db').collection('light').update(doc, {$set: {lightState: 1}}); //set lightState to 1 if 'on' state equals 1.
}
function handleOff(agent)
{
const state = agent.parameters.off;
var doc = {};
client.db('test_db').collection('light').find().toArray(function(err,docs){
doc = docs;
});
if(state == 1) client.db('test_db').collection('light').update(doc, {$set: {lightState: 0}}); //set lightState to 0 if 'off' state equals 1.
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('light_On', handleOn);
intentMap.set('light_Off', handleOff);
agent.handleRequest(intentMap);
});
}
}
});
});
以上是 DialogFlow 的内联编辑器中的代码。在内联编辑器中部署代码后,我第一次要求 DialogFlow 打开或关闭灯,一切正常,AWS EC2 mongoDB 数据库中的数据字段更改成功。但是,当我再次尝试让 Dialogflow 打开灯 on/off 时,Google Cloud Console 上的日志查看器显示以下错误:
"Error: listen EADDRINUSE 127.0.0.1:24800
at Server.setupListenHandle [as _listen2] (net.js:1360:14)
at listenInCluster (net.js:1401:12)
at doListen (net.js:1510:7)
at _combinedTickCallback (internal/process/next_tick.js:142:11)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)"
我知道这意味着我在端口 24800 上有多个进程 运行。但是我不知道如何在同一个端口 24800 上连续重用这个 MongoDB 服务器,这样我就可以多次询问 DialogFlow 以更改 MongoDB 中的数据。有什么办法吗?
我试图在 onRequest 函数运行之前启动 ssh 服务器。下面是一小段代码来展示我修改过的内容:
var server = tunnel(config, function(error, server){
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request,
response) => {
...
然而,内联编辑器似乎无法识别与事件处理函数 onRequest 关联的函数 'dialogflowFirebaseFulfillment'。错误日志显示如下:
2020-05-24 18:44:49.459 JST
dialogflowFirebaseFulfillment
Node.js module defined by file index.js is expected to export function
named dialogflowFirebaseFulfillment
尝试了上面的方法后,我萌生了端口繁忙时动态分配端口的想法。但是我找不到任何有用的东西。所以我被困了几个小时试图找出可能是错误的原因。
问题是您要在 onRequest
处理程序内重新建立到服务器的隧道。每次调用您的 webhook 时都会执行此操作而不将其关闭,因此该地址仍在使用中并抛出错误。
更好的方法可能是在函数初始化时设置 server
- 所以在 onRequest
处理程序之外。
[尝试在 onRequest
之外设置 server
后更新
它告诉您找不到函数的原因是因为您在 tunnel()
调用的回调函数中有 export
语句。必须在加载时导出,而不是在执行脚本时导出
最简单的解决方案是在设置隧道时不要回调(或者只用它来记录成功或错误)。所以像
const server = tunnel(config, function(error){
if( error ){
console.error( "Tunnel not created: ", error );
} else {
console.log( "Tunnel ready" );
}
});
exports.dialogflowFirebaseFulfillment = ...
应在函数初始化时设置隧道。
[原始旁注]
您还可以选择 运行 您的 webhook 在内联编辑器之外的其他地方。如果您已经有一个主机运行正在MongoDB,并且该主机有一个带有有效证书的 HTTPS 服务器,您可以 运行 您的 webhook 代码在那里。
我正在尝试将 mongoDB 集成到 Dialogflow。更具体地说,我正在尝试使用 DialogFlow 更改安装在 AWS EC2 实例中的 MongoDB 数据库中名为 'lightState' 的特定数据字段的值。当我说 'Turn the light on' 时,数据 'lightState' 必须更新为值 1,相反则更新为 0。
在开始真正的问题之前,我将post我的代码如下:
var tunnel = require('tunnel-ssh');
var mongoLib = require('mongodb');
var config = {
username: 'ubuntu',
host: <my-host-ip-address>,
port: 22,
privateKey: <my-aws-instance-private-key>
dstHost: '127.0.0.1',
dstPort: 27017,
localPort: 24800
};
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({request, response});
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
var server = tunnel(config, function(error, server){
if(error) throw error;
else {
if(server != null){
var Client = mongoLib.MongoClient('mongodb://127.0.0.1:24601/',{useUnifiedTopology:true, auto_reconnect: true});
var conn = Client.connect(function(error, client){
if(error) console.log(error);
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function handleOn(agent)
{
const state = agent.parameters.on;
var doc = {};
client.db('test_db').collection('light').find().toArray(function(err,docs){
doc = docs; //retrieve the data format
});
if(state == 1) client.db('test_db').collection('light').update(doc, {$set: {lightState: 1}}); //set lightState to 1 if 'on' state equals 1.
}
function handleOff(agent)
{
const state = agent.parameters.off;
var doc = {};
client.db('test_db').collection('light').find().toArray(function(err,docs){
doc = docs;
});
if(state == 1) client.db('test_db').collection('light').update(doc, {$set: {lightState: 0}}); //set lightState to 0 if 'off' state equals 1.
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('light_On', handleOn);
intentMap.set('light_Off', handleOff);
agent.handleRequest(intentMap);
});
}
}
});
});
以上是 DialogFlow 的内联编辑器中的代码。在内联编辑器中部署代码后,我第一次要求 DialogFlow 打开或关闭灯,一切正常,AWS EC2 mongoDB 数据库中的数据字段更改成功。但是,当我再次尝试让 Dialogflow 打开灯 on/off 时,Google Cloud Console 上的日志查看器显示以下错误:
"Error: listen EADDRINUSE 127.0.0.1:24800
at Server.setupListenHandle [as _listen2] (net.js:1360:14)
at listenInCluster (net.js:1401:12)
at doListen (net.js:1510:7)
at _combinedTickCallback (internal/process/next_tick.js:142:11)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)"
我知道这意味着我在端口 24800 上有多个进程 运行。但是我不知道如何在同一个端口 24800 上连续重用这个 MongoDB 服务器,这样我就可以多次询问 DialogFlow 以更改 MongoDB 中的数据。有什么办法吗?
我试图在 onRequest 函数运行之前启动 ssh 服务器。下面是一小段代码来展示我修改过的内容:
var server = tunnel(config, function(error, server){
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request,
response) => {
...
然而,内联编辑器似乎无法识别与事件处理函数 onRequest 关联的函数 'dialogflowFirebaseFulfillment'。错误日志显示如下:
2020-05-24 18:44:49.459 JST
dialogflowFirebaseFulfillment
Node.js module defined by file index.js is expected to export function
named dialogflowFirebaseFulfillment
尝试了上面的方法后,我萌生了端口繁忙时动态分配端口的想法。但是我找不到任何有用的东西。所以我被困了几个小时试图找出可能是错误的原因。
问题是您要在 onRequest
处理程序内重新建立到服务器的隧道。每次调用您的 webhook 时都会执行此操作而不将其关闭,因此该地址仍在使用中并抛出错误。
更好的方法可能是在函数初始化时设置 server
- 所以在 onRequest
处理程序之外。
[尝试在 onRequest
之外设置 server
后更新
它告诉您找不到函数的原因是因为您在 tunnel()
调用的回调函数中有 export
语句。必须在加载时导出,而不是在执行脚本时导出
最简单的解决方案是在设置隧道时不要回调(或者只用它来记录成功或错误)。所以像
const server = tunnel(config, function(error){
if( error ){
console.error( "Tunnel not created: ", error );
} else {
console.log( "Tunnel ready" );
}
});
exports.dialogflowFirebaseFulfillment = ...
应在函数初始化时设置隧道。
[原始旁注] 您还可以选择 运行 您的 webhook 在内联编辑器之外的其他地方。如果您已经有一个主机运行正在MongoDB,并且该主机有一个带有有效证书的 HTTPS 服务器,您可以 运行 您的 webhook 代码在那里。