Error when deploying DialogFlow CX webhook on Google Cloud Functions: "Error: listen EADDRINUSE: address already in use :::8080" - google-cloud-functions

I desperately try to implement a simple Webhook for my DialogFlow CX agent. Never done this before so I just copy paste the index.js and package.json code I found on the following page to my Google Cloud Function: DialogFlow CX calculate values
But it seems this is not working. When trying to deploy the Cloud Function I get the error "Error: listen EADDRINUSE: address already in use :::8080".
Same happens if I take this sample code: Dialogflow CX webhook for fulfilment to reply user using nodejs
What am I doing wrong? I am editing the code and trying to deploy it directly in the Google Cloude web console and not via a command prompt tool.
HERE SOME MORE DETAILS:
Setup of Google Cloud Function: I set up a new Google Cloud Function via Google Cloud Console by clicking Create Function. I set Region to us-east1, Trigger type to HTTP and Allow unauthenticated invocations. Then I save, update the index.js and package.json as described below and click Deploy. The result is that deployment could not be done because of Error: listen EADDRINUSE: address already in use :::8080.
Here the code I put into to index.js:
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
var port = process.env.PORT || 8080;
app.use(
bodyParser.urlencoded({
extended: true
})
);
app.use(bodyParser.json());
app.post('/BMI', (req, res) => processWebhook4(req, res));
var processWebhook4 = function(request, response ){
const params = request.body.sessionInfo.parameters;
var heightnumber = params["height.number"];
var weightnumber = params["weight.number"];
var heightunit = params["height.unit-height"]
var weightunit = params["weight.unit-weight"]
var computedBMI;
if (heightunit == "cm" && weightunit == "kg") { //using metric units
computedBMI = ((weightnumber/heightnumber/heightnumber )) * 10000;
} else if (heightunit == "in" && weightunit == "lb") { //using standard metrics
computedBMI = ((weightnumber/heightnumber/heightnumber )) * 703;
}
const replyBMI = {
'fulfillmentResponse': {
'messages': [
{
'text': {
'text': [
'This is a response from webhook! BMI is ' + computedBMI
]
}
}
]
}
}
response.send(replyBMI);
}
app.listen(port, function() {
console.log('Our app is running on http://localhost:' + port);
});
And here the code I put into package.json:
{
"name": "cx-test-functions",
"version": "0.0.1",
"author": "Google Inc.",
"main": "index.js",
"engines": {
"node": "8.9.4"
},
"scripts": {
"start": "node index.js"
},
"dependencies": {
"body-parser": "^1.18.2",
"express": "^4.16.2"
}
}

The code in the StackOverflow posts you’ve shared is working on other platforms such as Heroku.
The error you encountered “Error: listen EADDRINUSE: address already in use :::8080” is because of the code function listening to port 8080. Note that you will need to check and edit the sample code you’ve provided, and see if the libraries used are supported (for example: express js) in Google Cloud Functions and if the libraries are compatible in order to use it in Google Cloud Functions.
Here’s a working code for Cloud Functions from this StackOverflow Post:
exports.helloWorld = (req, res) => {
const params = req.body.sessionInfo.parameters;
var heightnumber = params.height.number;
var weightnumber = params.weight.number;
var heightunit = params.height.heightUnit;
var weightunit = params.weight.weightUnit;
var computedBMI;
if (heightunit == "cm" && weightunit == "kg") { //using metric units
computedBMI = ((weightnumber/heightnumber/heightnumber )) * 10000;
} else if (heightunit == "in" && weightunit == "lb") { //using standard metrics
computedBMI = ((weightnumber/heightnumber/heightnumber )) * 703;
}
const replyBMI = {
'fulfillmentResponse': {
'messages': [
{
'text': {
'text': [
'This is a response from webhook! BMI is ' + computedBMI
]
}
}
]
}
}
res.status(200).send(replyBMI);
};
Here’s the result:
Moreover, here’s a sample code you can also use for deploying in Cloud Function:
index.js
exports.helloWorld = (req, res) => {
let fulfillmentResponse = {
"fulfillmentResponse": {
"messages": [{
"text": {
"text": [
"This is a sample response"
]
}
}]
}
};
res.status(200).send(fulfillmentResponse);
};
package.json
{
"name": "sample-http",
"version": "0.0.1"
}
Once you deployed the sample code, you can do the following to be able to use the webhook:
Go to Manage > Webhooks > Create
Add Display Name and Webhook URL(Trigger URL in Cloud Functions)
Click Save
Go to Build > Flow > Start Page
Select any Route and add the webhook
Test in Simulator
Result should be like this:

Related

Firebase Cloud Function with Swagger: Error: could not handle the request

I have this code in a function called docs:
const functions = require("firebase-functions");
const express = require("express");
const swaggerUi = require("swagger-ui-express");
const swaggerJsdoc = require("swagger-jsdoc");
const options = {
definition: {
openapi: "3.0.0",
info: {
title: "API",
version: "1.0.0",
},
},
apis: ["../**/*.function.js"],
};
const openapiSpecification = swaggerJsdoc(options);
console.log("🚀 ", openapiSpecification);
const app = express();
app.use(
"/",
swaggerUi.serve,
swaggerUi.setup(openapiSpecification, {
swaggerOptions: {
supportedSubmitMethods: [], //to disable the "Try it out" button
},
})
);
module.exports = functions.https.onRequest(app);
But every time I hit the URL, this error gets returned:
Error: could not handle the request
URL:
https://REGION-PROJECT.cloudfunctions.net/docs
The deps above are all installed.
Any idea what is causing this issue?
Or better yet, how can I serve an endpoint for Swagger docs?
Please keep in mind that all other functions don't use express; most are callable. Just this one function uses it, so not sure if the mixing not supported.
Here's the folder structure:
package.json
index.js
app
auth
login.function.js
users
createUser.function.js
Inside index.js, the functions get loaded and added to the exports dynamically. This setup works fine and deploys well, so no issues there.

React, Hardhat frontend smart contract method calling, how to do so?

I'm using hardhat locally and have a react frontend up and running but I can't call the methods without errors.
I've tried both ethers.js and web3.
Here's my code and attempts. Please let me know if you see what I'm doing wrong.
I'm trying to interact with contracts that are deployed in the local hardhat env through web3
I'm unable to get back the data from the contract, here's the info
I have:
var list = await contract.methods.getList();
console.log("list ", list );
which gets me
list {arguments: Array(0), call: ƒ, send: ƒ, encodeABI: ƒ, estimateGas: ƒ, …}
When I do
var list = await contract.methods.getList().call();
console.log("list ", list );
I get this error in the browser:
Returned values aren't valid, did it run Out of Gas? You might also see this error if you are not using the correct ABI for the contract you are retrieving data from, requesting data from a block number that does not exist, or querying a node which is not fully synced.
I do:
Setup in console:
npx hardhat node
>Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
>Accounts
>========
>...
npx hardhat compile
> Nothing to compile
npx hardhat run scripts/deploy.js --network hardhat
Note: In the deploy.js file, I do a
const list = await contract.getList();
console.log("list", list ); // correctly outputs ["string", "string"]
The method:
mapping(uint256 => address) internal list;
uint256 internal listCount;
function getList() public override view returns (address[] memory) {
address[] memory assets = new address[](listCount);
for (uint256 i = 0; i < listCount; i++) {
assets[i] = list[i];
}
return assets;
}
In react App.js:
import Contract_from './data/abi/Contract_.json'; // Contract_ is a placer
var contract = new web3.eth.Contract(Contract_, address_given_on_deploy);
var contractAddress = await contract .options.address; // correctly outputs
var list= await contract.methods.getList().call();
console.log("list", list);
As you see, this doesn't return the values from the method. What am I doing wrong here?
For any reason and may be likely the issue, here's my config:
require("#nomiclabs/hardhat-waffle");
// openzeppelin adds
require("#nomiclabs/hardhat-ethers");
require('#openzeppelin/hardhat-upgrades');
//abi
require('hardhat-abi-exporter');
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async () => {
const accounts = await ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**
* #type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
networks: {
hardhat: {
gas: 12000000,
blockGasLimit: 0x1fffffffffffff,
allowUnlimitedContractSize: true,
timeout: 1800000,
chainId: 1337
}
},
solidity: {
compilers: [
{
version: "0.8.0",
settings: {
optimizer: {
enabled: true,
runs: 1000
}
}
},
{
version: "0.8.2",
settings: {
optimizer: {
enabled: true,
runs: 1000
}
}
},
],
},
abiExporter: {
path: './frontend/src/data/abi',
clear: true,
flat: true,
only: [],
spacing: 2
}
}
__
I thought maybe i would try ethers.js since that is what i do my testing in but same issue.
For whatever reason, I can "get" the contracts, print the methods that belong to them, but I can't actually call the methods.
Here's my ethers.js brevity:
provider = new ethers.providers.Web3Provider(window.ethereum);
if(provider != null){
const _contract = new ethers.Contract(address, _Contract, provider);
var list= await _contract.getList().call();
console.log("list", list);
}
The error i get from this is:
Error: call revert exception (method="getList()", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.4.0)
I've tried numerous contracts in the protocol and same thing for each

Why Chrome DevTools Network shows no response?

I've been trying to fetch some url using Devtools 'copy as fetch' but I can see no response. If I try replay xhr, it will work. It's strange since it doesn't work for this particular site, but if I try 'copy as fetch' on some others it does bring a result.
What I'm trying to do is grab the response body and display it some other way (it's a schedling software, and I'm trying to modify the way it displays the calendar view since it displays everything together).
I have an extension that enables me to modify XMLHttpRequest so I can get the response of any XHR, but since the first async executes before I inject the script, then I'm always missing the first one.
I plan on using chrome webRequest to stop the first one and fetch it again.
manifest.json
{
"name": "jobber",
"version": "2.0",
"description": "Build an Extension!",
"manifest_version": 2,
"permissions": [
"webNavigation",
"webRequest",
"*://secure.name.com/*"
],
"content_scripts": [{
"matches": ["*://secure.name.com/calendar*"],
"js": ["contents.js"],
"run-at": "document_start"
}],
"externally_connectable": {
"matches": ["*://secure.name.com/calendar*"]
},
"background": {
"scripts": ["background.js"]
}
}
contents.js
(function () {
'use strict';
let s = document.createElement("script");
s.textContent = overloadXHR();
document.head.insertBefore(s, document.head.children[0]);
s = document.createElement("script");
s.textContent = displayCalendar;
document.head.insertBefore(s, document.head.children[0]);
})();
function overloadXHR() {
const text = `
console.log(\`overriding: \${Date.now()}\`);
const rawOpen = XMLHttpRequest.prototype.open;
let json = [];
(function(){
XMLHttpRequest.prototype.open = function () {
this.addEventListener("readystatechange", e => {
if (/secure.name.com.calendar.*?calendar=true/i.test(this.responseURL)) {
if ((this.status == 200) && (this.readyState == 4)) {
console.log(this.readyState);
try {
json = JSON.parse(this.response);
window.setTimeout(() => (window.displayCalendar({json}))({json}), 1000);
}
catch (e) { console.log(e); }
}
}
});
rawOpen.apply(this, arguments);
}
}())
`;
return text;
}
function displayCalendar({ json }) {
// do something
}
I tried POST requests too. I could see that they would work, but no response given tho.
original request:
copy as fetch
copy as fetch response
copy as fetch timing

Error: No handler for requested intent at WebhookClient.handleRequest

Default intent calling a cloud function gives error
Error: No handler for requested intent
at WebhookClient.handleRequest (/user_code/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:287:29)
at exports.dialogflowFirebaseFulfillment.functions.https.onRequest (/user_code/index.js:73:11)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /var/tmp/worker/worker.js:783:7
at /var/tmp/worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
as my webresponse in diagnostic info log shows this.
{
"responseId": "86043a10-8bc2-4ee7-8e8b-1e997289ad7c",
"queryResult": {
"queryText": "hi",
"action": "input.welcome",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentText": "Hi. Am Uma. Kindly let me know your experience facing an issue.",
"fulfillmentMessages": [
{
"text": {
"text": [
"Hi. Am Uma and welcome to support. Kindly let me know your experience facing an issue."
]
}
}
],
"outputContexts": [
{
"name": "projects/handymanticketagent/agent/sessions/e416a522-da87-ebd1-348e-9fdea1efbf65/contexts/defaultwelcomeintent-followup",
"lifespanCount": 2
}
],
"intent": {
"name": "projects/handymanticketagent/agent/intents/c58f706f-6cb6-499d-9ce2-459e8054ddc1",
"displayName": "Default Welcome Intent"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"webhook_latency_ms": 10001
},
"languageCode": "en"
},
"webhookStatus": {
"code": 4,
"message": "Webhook call failed. Error: Request timeout."
}
}
Based on the stack overflow answers here, Have added an intent mapped to function but am still getting error and could progress further. Where and how the cloud function console says am missing a handler for my request?
Update : As #prisoner said, including my cloud function code.
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { WebhookClient } = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
console.log(request.body.queryResult.fulfillmentText);
console.log(request);
console.log(response);
const agent = new WebhookClient({ request, response });
console.log(agent);
function writeToDb(agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
console.log(databaseEntry);
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
console.log(dialogflowAgentRef);
return db.runTransaction(t => {
t.set(dialogflowAgentRef, { entry: databaseEntry });
console.log(Promise.resolve('Write complete'));
return Promise.resolve('Write complete');
}).then(doc => {
agent.add('Wrote "${databaseEntry}" to the Firestore database.');
return null;
}).catch(err => {
if (err) {
console.log(err.stack);
}
console.log('Error writing to Firestore: ${err}');
agent.add('Failed to write "${databaseEntry}" to the Firestore database.');
});
}
function readFromDb(agent) {
console.log(agent);
// Get the database collection 'dialogflow' and document 'agent'
const dialogflowAgentDoc = db.collection('dialogflow').doc('agent');
console.log(dialogflowAgentDoc);
// Get the value of 'entry' in the document and send it to the user
return dialogflowAgentDoc.get()
.then(doc => {
if (!doc.exists) {
agent.add('No data found in the database!');
} else {
agent.add(doc.data().entry);
}
return Promise.resolve('Read complete');
}).catch(() => {
agent.add('Error reading entry from the Firestore database.');
agent.add('Please add a entry to the database first by saying, "Write <your phrase> to the database"');
});
}
function defaultwelcomeintent_function(agent) {
console.log(agent);
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('defaultwelcomeintent-followup', defaultwelcomeintent_function);
intentMap.set('ReadFromFirestore', readFromDb);
intentMap.set('WriteToFirestore', writeToDb);
console.log(intentMap);
agent.handleRequest(intentMap);
});
The diagnostic info says that the intent's display name for that fulfillment is "Default Welcome Intent":
"intent": {
"name": "projects/handymanticketagent/agent/intents/c58f706f-6cb6-499d-9ce2-459e8054ddc1",
"displayName": "Default Welcome Intent"
},
So you'd need to create a mapping for it like this:
intentMap.set('Default Welcome Intent', defaultwelcomeintent_function);
Where defaultwelcomeintent_function is the handler you have defined within your cloud function.
I had the same issue with the exact error from Dialogflow : Error: No handler for requested intent, in my case I'm using async/await in order to make synchronous calls through a cloud function in dialogflow fulfillement.
I noticed that in one of my main function mapped to an agent, I wasn't returning anything. Since the function was using async I added a return statment with the promise that I was waiting for at the beggining.
async function getInfo(agent) {
var hh = await getUserInfos(request.body.originalDetectIntentRequest.payload.uuid);
// Do what you want here
var yy = hh.aa[0].zz.yy;
agent.setFollowupEvent({ "name": "xxx", "parameters": { "xxx": yy } });
// Return your promise
return hh;
}

feathers.js -> Authentication token missing

I have a feathters.js application and now I want to secure the create and update hooks. I use a socket.io client and currently am going for JWT. I have added what I think I needed to add but am getting Error: Authentication token missing and Error Authenticating. The later I understand for that is from my code. I have a backend / frontend situation
So this is what I've implemented so far.
File: backend\backend.js (called in backend\index.js for the configuration of the app)
'use strict';
const path = require('path');
const serveStatic = require('feathers').static;
const favicon = require('serve-favicon');
const compress = require('compression');
const cors = require('cors');
const feathers = require('feathers');
const configuration = require('feathers-configuration');
const authentication = require('feathers-authentication');
const hooks = require('feathers-hooks');
const rest = require('feathers-rest');
const bodyParser = require('body-parser');
const socketio = require('feathers-socketio');
const middleware = require('./middleware/index');
const services = require('./services/index');
const appFeathers = feathers();
appFeathers.configure(configuration(path.join(__dirname, '..')));
appFeathers.use(compress())
.options('*', cors())
.use(cors())
.use(favicon(path.join(appFeathers.get('public'), 'favicon.ico')))
.use('/', serveStatic(appFeathers.get('public')))
.use(bodyParser.json())
.use(bodyParser.urlencoded({extended: true}))
.configure(hooks())
.configure(rest())
.configure(socketio())
.configure(services)
.configure(middleware)
.configure(authentication());
module.exports = appFeathers;
File: backend\config\default.json
{
"host": "localhost",
"port": 3001,
"mysql_connection": "mysql://CONNECTION_STRING",
"public": "../public/",
"auth": {
"idField": "id",
"token": {
"secret": "SECRET_KEY"
},
"local": {}
}
}
In a working component of the frontend:
<template>
<div class="vttIndex">
idnex.vue
todo: eagle.js slideshow
todo: first info
<ul>
<li v-for="message in listMessages">
{{ message }}
</li>
</ul>
</div>
</template>
<script>
import feathers from 'feathers/client';
import socketio from 'feathers-socketio/client';
import hooks from 'feathers-hooks';
import io from 'socket.io-client';
import authentication from 'feathers-authentication/client';
import * as process from "../nuxt.config";
const vttSocket = io(process.env.backendUrl);
const vttFeathers = feathers()
.configure(socketio(vttSocket))
.configure(hooks())
.configure(authentication());
const serviceMessage = vttFeathers.service('messages');
vttFeathers.authenticate({
type: 'token',
'token ': 'SECRET_KEY'
}).then(function(result){
console.log('Authenticated!', result);
}).catch(function(error){
console.error('Error authenticating!', error);
});
export default {
layout: 'default',
data: function() {
return {
listMessages: []
}
},
mounted: function() {
serviceMessage.find().then(page => {
this.listMessages = page.data;
});
serviceMessage.on('created', (serviceMessage) => {
this.listMessages.push(serviceMessage);
});
}
}
</script>
As token, I have the secret key of the backend json file. As you see, now I only try to log console messages. It is doing something for my error message is coming from there.
Question
Where am I missing what to have this functioning?
Goal
Just in case it's needed. My goal is for all 'public' data to be select with a token in my client and then an admin section maybe with 0auth. So the general 'SELECT' stuff is secured through a token instead of no authentication at all.
Solution
Okay I solved it, sort of. I first needed to create a user. Then I needed to do a local login with the user. That returns a token. If I use that, then there is no problem at all.
To use a token, you must first make sure it is generated. I was using the secret key as token what isn't correct. When you first athenticate with the 'local' type (default email and password) it will create a token and that is what you could then use with the method 'token'