Some error occures after send request to the function url - node.js

I set up a one firebase function to send messages to my bot. But when firebase gets request I can see that some error occurred.
FetchError: request to https://api.telegram.org/bot<BOT-TOKEN>/getMe failed, reason: getaddrinfo EAI_AGAIN api.telegram.org:443
at ClientRequest.<anonymous> (/srv/node_modules/node-fetch/lib/index.js:1453:11)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at TLSSocket.socketErrorListener (_http_client.js:401:9)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at emitErrorNT (internal/streams/destroy.js:66:8)
at _combinedTickCallback (internal/process/next_tick.js:139:11)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
and
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (/worker/node_modules/express/lib/response.js:767:10)
at ServerResponse.contentType (/worker/node_modules/express/lib/response.js:595:15)
at ServerResponse.sendStatus (/worker/node_modules/express/lib/response.js:357:8)
at /srv/index.js:30:13
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
But secound one I suppose does not influence on the result.
As a result, I don't get any message to my to Bot.
The next script that i use:
const functions = require('firebase-functions');
const telegraf = require('telegraf');
const axios = require('axios');
const bot = new telegraf('<BOT-TOKEN>')
bot.start((ctx) => ctx.reply('Welcome!'))
bot.help((ctx) => ctx.reply('Send me a sticker'))
bot.on('sticker', (ctx) => ctx.reply('👍'))
bot.hears('hi', (ctx) => ctx.reply('Hey there'))
bot.launch()
exports.helloWorld = functions.https.onRequest((request, res) => {
const token = '<BOT-TOKEN>';
const url = `https://api.telegram.org/bot${token}/sendMessage`;
axios.post(url, {
chat_id: '154866113',
text: "just do it!"
})
.then(function (response) {
console.log(response);
res.send({ status: "O"});
return 'ok';
})
.catch(function (error) {
console.log(error);
res.sendStatus(500);
});
res.send("Hello from Firebase!");
});

The getaddrinfo EAI_AGAIN error means that you need to switch to the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)
The telegram API is not a Google-owned service, so you need to switch to the "Flame" or "Blaze" plan.

I'm guessing the answer to the EAI_AGAIN error is due to a malformed URI. Are you sure https://api.telegram.org/bot<BOT-TOKEN>/getMe is the correct URI and is accessible from where ever this script is being run from?
The second error is due to you calling the res.send() method more than once. Express res objects wrap Node's ServerResponse object, and once the connection is closed via write or end, it cannot be sent again. Try removing the res.send("Hello from Firebase!"); section of your code and coming back.

Related

Send/Reply direct message using Twitter API v2

I have a nodejs application, I need to add a feature were I can send a survey using direct messaging on twitter to the user and when the user replies, the application will send the next question and so on (preferably if I can add options for the replies expected).
What I'm stuck in currently is sending the direct message, the examples that I found seem to work with the old version and not working with Twitter API v2.
One sample code that I tried but also not working is below:
const Twit = require('twit');
const config = require('./config.js');
const T = new Twit(config);
const stream = T.stream('user');
const SendMessage = user => {
const { screen_name, name } = user.source;
const obj = {
screen_name: screen_name,
text: "Hi there!"
};
timeout = 5000;
setTimeout(() => {
T.post("direct_messages/new", obj)
.catch(err => {
console.error("error", err.stack);
})
.then(result => {
console.log(`Message sent successfully To ${screen_name}!`);
});
}, timeout);
};
user = new Object;
user.source = { screen_name: 'name', name: 'userDisplayedName' };
SendMessage(user);
Output Error:
throw er; // Unhandled 'error' event
^
Error: Bad Twitter streaming request: 404
at Object.exports.makeTwitError (/../node_modules/twit/lib/helpers.js:74:13)
at Request.<anonymous> (/../node_modules/twit/lib/streaming-api-connection.js:96:29)
at Request.emit (events.js:327:22)
at IncomingMessage.<anonymous> (/../node_modules/request/request.js:1083:12)
at Object.onceWrapper (events.js:421:28)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (_stream_readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
Emitted 'error' event on StreamingAPIConnection instance at:
at Request.<anonymous> (/../node_modules/twit/lib/streaming-api-connection.js:99:14)
at Request.emit (events.js:327:22)
[... lines matching original stack trace ...]
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
code: null,
allErrors: [],
twitterReply: '',
statusCode: 404
}
does anyone know how to send a direct message using Twitter API v2 with Nodejs?
At the time of writing this answer, the Direct Message APIs have not been migrated to v2, so you will need to continue to use Twitter API v1.1 for Direct Messages.
The error here is not in sending, but in receiving -> Bad Twitter streaming request -> 404. This is because the code you have found is trying to use the Twitter user streams API, which was removed in 2018. These have been replaced with the Account Activity API (webhooks). You will need to build an app that receives webhook events for Direct Messages, and then post replies. This is all in v1.1 of the API.

Connect ETIMEDOUT on Azure App Service when calling HTTP endpoint without specify maxSockets

I have some timeout problems when calling multiple times an HTTP[S] endpoint from node.js inside an Azure App Service.
Here my code to demostrate the problem.
const fetch = require('node-fetch');
const https = require("https");
const agent = new https.Agent();
function doWork() {
const works = [];
for (let i = 0; i < 50; i++) {
const wk = fetch('https://www.microsoft.com/robots.txt', { agent })
.then(res => res.text())
.then(body => console.log("OK", i))
.catch((err) => console.log("ERROR", i, err));
works.push(wk);
}
return Promise.all(works);
}
doWork()
.catch((err) => {
console.log(err);
});
When running this app 3 or 4 times inside a Standard Medium App Service (I'm running it using Kudu but I discover this error inside a standard web app) I get the following error for every requests:
{ FetchError: request to https://www.microsoft.com/robots.txt failed, reason: connect ETIMEDOUT 23.206.106.109:443
at ClientRequest.<anonymous> (D:\home\site\test\test-forge-calls\node_modules\node-fetch\lib\index.js:1393:11)
at emitOne (events.js:96:13)
at ClientRequest.emit (events.js:188:7)
at TLSSocket.socketErrorListener (_http_client.js:310:9)
at emitOne (events.js:96:13)
at TLSSocket.emit (events.js:188:7)
at emitErrorNT (net.js:1276:8)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9)
message: 'request to https://www.microsoft.com/robots.txt failed, reason: connect ETIMEDOUT 23.206.106.109:443',
type: 'system',
errno: 'ETIMEDOUT',
code: 'ETIMEDOUT' }
After some minutes (5/6) without performing requests the above code works again.
I have tried with both node-fetch (https://www.npmjs.com/package/node-fetch) and request (https://www.npmjs.com/package/request). Same results.
The same problem occurs if I not specify an agent and is not related to the destination endpoint, I have tried with many different endpoints (private or public).
According to Microsoft Best Practices node.js applications should use a keep alive agent with the following configuration:
var keepaliveAgent = new Agent({
maxSockets: 40,
maxFreeSockets: 10,
timeout: 60000,
keepAliveTimeout: 300000
});
In fact when creating the agent with:
const agent = new https.Agent({ maxSockets: 100 });
everything works as expected.
Is this behavior expected? What is the best practice for node.js? It is fine to always specify an agent with maxSockets also outside Azure?
UPDATE:
The other strange behavior is that if I run the above code using node index 3 or 4 times I expect that connections are closed when node process exit, but seems that the connections remain open for some minutes. This can be the effect of the TIME_WAIT state?

Avoid ESOCKETTIMEDOUT from Google/Firebase Cloud Functions

I have a Firebase cloud function, that is looping through users in a database and sends an email to each one. It uses the Campaign Monitor API for Transactional/Smart Emails, but the request results in an ESOCKETTIMEDOUT error. Campaign Monitor receives and processes each request just fine, but I would like to avoid the error of course.
How can I do this? I've read elsewhere about a setting, 'agent: false, pool: {maxSockets: 100}', but I am not sure if this is the right approach - and I don't know where to set it on a Firebase og Google Cloud Function.
This is the request snippet, that is called by the loop.
api.transactional.sendSmartEmail(details, function (err, res) {
if (err) {
console.log('error sending mail, err);
/*Throws:
{ Error: ESOCKETTIMEDOUT
at ClientRequest.<anonymous> (/user_code/node_modules/createsend-node/node_modules/request/request.js:813:19)
at ClientRequest.g (events.js:292:16)
at emitNone (events.js:86:13)
at ClientRequest.emit (events.js:185:7)
at TLSSocket.emitTimeout (_http_client.js:630:10)
at TLSSocket.g (events.js:292:16)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket.Socket._onTimeout (net.js:338:8)
at ontimeout (timers.js:386:11) code: 'ESOCKETTIMEDOUT', connect: false }
*/
} else {
console.log('sent mail');
}
});

Unable to load default credentials in node.js google translate

I need to translate some text in node.js using google translate. I end up getting the following Error: Could not load the default credentials. Browse to here to get more details. This problem has costed me more than 48 hours. I have followed all the instructions in that link but problem still persists. Please someone point what is it that I've missed.
Error log:
ERROR: Error: Could not load the default credentials. Browse to
https://developers.google.com/accounts/docs/application-default-credentials
for more information.
at /user_code/node_modules/#google-cloud/translate/node_modules/google-auth-library/lib/auth/googleauth.js:316:21
at /user_code/node_modules/#google-cloud/translate/node_modules/google-auth-library/lib/auth/googleauth.js:346:7
at Request._callback (/user_code/node_modules/#google-cloud/translate/node_modules/google-auth-library/lib/transporters.js:70:30)
at self.callback (/user_code/node_modules/#google-cloud/translate/node_modules/request/request.js:186:22)
at emitOne (events.js:96:13)
at Request.emit (events.js:188:7)
at Request.onRequestError (/user_code/node_modules/#google-cloud/translate/node_modules/request/request.js:878:8)
at emitOne (events.js:96:13)
at ClientRequest.emit (events.js:188:7)
at Socket.socketErrorListener (_http_client.js:309:9)
function translateText(Text, Target) {
// [START translate_translate_text]
// Imports the Google Cloud client library
const Translate = require('#google-cloud/translate');
// Your Google Cloud Platform project ID
const projectId = 'xxxxxxxxxx';
// Instantiates a client
const translate = new Translate({
projectId: projectId,
});
// Translates some text into Russian
translate
.translate(Text, Target)
.then(results => {
const translation = results[0];
console.log(`Text: ${text}`);
console.log(`Translation: ${translation}`);
return translation;
})
.catch(err => {
console.error('ERROR:', err);
});
}

Cloud Functions for Firebase Image download function Error

I am building a web application using Firebase and the new feature Cloud Functions for Firebase. I have created a function that takes a URL and downloads the image into a 64-bit encoded string as below using the node modules request and request-promise-native:
module.exports = {
downloadImageFromUrl: function (url) {
var options = {
method: 'GET',
uri: url,
resolveWithFullResponse: true,
simple: false,
family: 4
};
return rp.get(options)
.then(function (res) {
return "data:" + res.headers["content-type"] + ";base64," + new Buffer(res.body).toString('base64');
})
.catch(function (error) {
console.log("ERROR GETTING image", error);
return error;
});
}
};
The top function works perfectly running locally but once on firebase it gives the error:
RequestError: Error: getaddrinfo EAI_AGAIN lh6.googleusercontent.com:443
at new RequestError (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/errors.js:14:15)
at Request.plumbing.callback (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/plumbing.js:87:29)
at Request.RP$callback [as _callback] (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/plumbing.js:46:31)
at self.callback (/user_code/node_modules/request/request.js:188:22)
at emitOne (events.js:96:13)
at Request.emit (events.js:188:7)
at Request.onRequestError (/user_code/node_modules/request/request.js:884:8)
at emitOne (events.js:96:13)
at ClientRequest.emit (events.js:188:7)
at TLSSocket.socketErrorListener (_http_client.js:310:9)
at emitOne (events.js:96:13)
at TLSSocket.emit (events.js:188:7)
at connectErrorNT (net.js:1020:8)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickDomainCallback (internal/process/next_tick.js:122:9)
I am calling the function in the firebase auth trigger when a user is created as below:
exports.createUser = functions.auth.user().onCreate(event => {
if (event.data.photoURL) {
utils.downloadImageFromUrl(event.data.photoURL)
.then(function(res){
console.log("User Photo", res);
})
.catch(function(error){
console.log("Error", error);
})
}
});
Any help would be greatly appreciated.
Not entirely sure yet if this is the answer, but after reading the documentation, I read their free plan which says you cannot make any out bound requests. So I guess getting an image from a Url counts as an outbound request. After I start paying for their service, I will come back to verify if this was the problem.

Resources