我正在尝试将mongoDB整合到Dialogflow中。更具体地说,我试图通过使用DialogFlow来改变安装在AWS EC2实例中的MongoDB数据库中一个名为'lightState'的特定数据字段的值。当我说'打开灯'时,数据'lightState'必须更新为1的值,反之则为0。
在进入真正的问题之前,我先把我的代码贴在下面。
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的Inline Editor中的代码。在Inline Editor中部署代码后,第一次要求DialogFlow打开或关闭灯光时,一切都很正常,AWS EC2的mongoDB数据库中的数据字段变化成功。但当我再次尝试要求Dialogflow开灯或关灯时,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) => {
...
然而,Inline Editor似乎无法识别函数'dialogflowFirebaseFulfillment',它与事件处理函数onRequest相关联。错误日志显示如下。
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
处理人:
[更新,一旦你尝试设置 server
外面 onRequest
]它告诉你找不到函数的原因是因为你有了 export
回调函数中的语句 tunnel()
调用。输出必须在加载时进行,而不是在脚本执行时进行。
最简单的解决办法是 不 有一个回调,当你设置隧道时(或只是用它来记录成功或错误)。所以类似于
const server = tunnel(config, function(error){
if( error ){
console.error( "Tunnel not created: ", error );
} else {
console.log( "Tunnel ready" );
}
});
exports.dialogflowFirebaseFulfillment = ...
应该在函数初始化时设置隧道。
[原注]你也可以选择在Inline Editor以外的地方运行你的webhook。如果你已经有一个运行MongoDB的主机,而且该主机有一个HTTPS服务器,并有有效的证书,你可以在那里运行你的webhook代码。