Runtime application - node.js

Can I use heroku for nodejs application, which must be running always? Now I want create telegram bot without webhook and it must be running always.
const TelegramBot = require('node-telegram-bot-api');
const token = 'MY TELEGRAM BOT KEY';
const bot = new TelegramBot(token, {polling: true});
bot.on('message', (msg) => {
const chatId = msg.chat.id;
// send a message to the chat acknowledging receipt of their message
bot.sendMessage(chatId, 'Received your message');
});

Yes, Deploying and running Node.js apps on Heroku is much easier than we think. You can find a guide about realtime Node.js app on Heroku here
You have to use a paid plan to run realtime apps. As we know the free Heroku Dyno will sleep after 30 mins of inactivity. While we access our app after being inactive we have to wait for a couple of seconds to get back to the active stage. More details about Heroku plans and pricing can be found here
PS: As I am a beginner please don't stop with my answer. You can wait for answers from expert StackOverflow users they are yet to come. Or if you would like, open a ticket on Heroku support and ask your queries there

Related

Why does my Discord.js bot take more than five minutes to respond on a server with less than 500 users?

I've just developed a bot for adding roles to a user who starts streaming on my server. When I tested the bot on a isolated server with only a few channels and users the bot responded instantly. But now I have set up my bot on my primary Discord server with roughly 25 channels and about ~500 users and now the response time is more than five minutes before I see it add or remove a role.
I am connecting via FIOS gigabit and running on a I9 with DDR4 4266MHz RAM.
When I first start the node server I notice the delay is much less, however still very slow responses of around a minute or two before it adds or removes the roles. If I allow the server to run for ten minutes then the response time is around five minutes before it adds a role. I do not know if it continues to get worse over time. But what could be causing this delay? I see my user status change to streaming (purple dot) in the online users list immediately, but my discord bot is not aware of this for a very long time!
This is my code, I have tried my best to optimize it but I've only been learning Discord.js for about a week and am still very unfamiliar with it:
// require the discord.js module
const Discord = require('discord.js');
// create a new Discord client
const client = new Discord.Client();
let role = '';
client.once('ready', () => {
const myGuild = client.guilds.cache.get('123456789123456789');
role = myGuild.roles.cache.find(role => role.name === 'streaming');
console.log('Ready!');
});
client.on("presenceUpdate", (oldPresence, newPresence) => {
if (!newPresence.activities){ return false; }
newPresence.activities.forEach(activity => {
if (activity.type == "STREAMING") {
//console.log(`${newPresence.user.tag} is streaming at ${activity.url}.`);
newPresence.member.roles.add(role)
} else {
newPresence.member.roles.remove(role)
};
});
});
// login to Discord with your app's token
client.login('123456789123456789.123456789.123456789123456789');
Can someone please explain why my bot is becoming so sluggish? It is almost unusable and kind of discouraging.
The default maxListeners is set to 10 and it may be worth exploring setting that value higher.
Additionally, I am curious if there is a memory leak on your application.
It sounds like it from the sluggishness that is experienced over time.
Try using a profiling tool like Clinic.js to monitor the state of the application over time.

How to get all non bot users in discord js using a discord bot in nodejs

I have created a discord bot by taking reference from this digital ocean link.
Now I can send message to any channel using the bot but my requirement is to send dm to user of that server.
For that I have tried many SO answers and followed other links, but all the solutions end up to be same.
I have tried this two way to get the users of a guild and send dm to any one selected user.
1st way - Get all users of guild (server)
const client_notification = new Discord.Client();
client_notification.on('ready', () => {
console.log("Notification manager ready");
let guild = client_notification.guilds.cache.get("Server ID");
guild.members.cache.forEach(member => console.log("===>>>", member.user.username));
});
client_notification.login("login");
Output
Notification manager ready
===>>> discord notification
By this way it only returns me the bot name itself. Although the membersCount is 6.
2nd way - send dm to user directly (server)
client.users.cache.get('<id>').send('<message>');
It gives me undefined in output.
My configs,
Node version: 10.16.3
discord.js version: 12.5.1
My question is how to get all the guild members in discord.js?
Discord added privileged gateway intents recently. So to fetch all member data you need to enable that in the developer portal. After that you need to fetch all the members available, for that we can use the fetchAllMembers client option, and then we need to filter out bot users, so that we don't message them.
const client_notification = new Discord.Client({fetchAllMembers:true}); //Fetches all members available on startup.
client_notification.on('ready', () => {
console.log("Notification manager ready");
let guild = client_notification.guilds.cache.get("Server ID");
guild.members.cache.filter(member => !member.user.bot).forEach(member => console.log("===>>>", member.user.username));
});
client_notification.login("login");
The .filter() method filters out all the bots and gives only the real users.
You should avoid using fetchAllMembers when your bot gets larger though, as it could slow down your bot and use lots of memory.
I think the problem is related to updating the bot policy for discord. Do you have this checkbox checked in the bot settings?
https://discord.com/developers/applications
Some info about client.users.cache:
Its a cache collection, so if you restart bot, or bot never handle user message or actions before, this collection will be empty. Better use guild.members.cache.get('')

How can I deploy a discord.js bot to Cloud Functions?

I want to deploy a Discord bot running on discord.js to Firebase Cloud Functions but I can't get the bot to run in Firebase. If I use nodemon it runs perfectly but if I use firebase deploy it will not start the bot.
Here is my current code:
const functions = require('firebase-functions');
require('dotenv').config();
const token = process.env.TOKEN
const Discord = require('discord.js')
const Client = new Discord.Client();
Client.on('ready', () => {
Client.channels.find(x => x.name === 'main-cannel').send('bot is deployed')
Client.user.setGame(`The Cult | ${Client.guilds.size} servers`)
Console.log('test')
});
Client.login(token);
//is is not working but de basic
//export.App = functions.... {Client}
exports.app = functions.https.onRequest((request, response) => {
response.send("Test");
});
This may not be the best combination of google cloud platform services, since cloud functions where not designed with this in mind. You can just host your Discord bot on a compute engine machine.
If you want to use the dynamic scaling have a look at Discord Microservice Bots where DasWolke describes what microservices are. Hey also included his javascript code to split up the different services for Discord.
What you can do on Google cloud platform specifically, is creating a VM with the Gateway running. This needs to run 24/7 and should be lightweight. You can use an f1-micro (which is free) for this though google recommends a g1-small for the task.
The gateway should filter the events you are looking for (because Discord sends a lot of events and you don't need most) and send the data to cloud function or cloud run (you can send the data via pub/sub). In my experience, a cloud run has much shorter startup times so I went with that.
Inside your function, you receive the data do with it what you want. If you want something in Discord (send a message, manage channels, ...) you can use SnowTransfer for that. SnowTransfer just calls the rest API on discord.
Put client.login(token) into where response.send("Test"); is. This will prompt your bot's code to execute upon an HTTP request.
In https://us-central1-<your project ID>.cloudfunctions.net/app, replace <your project ID> with your project's ID.
If Firebase Hosting gives you the URL example-123.web.app, your project ID is example-123. You can also get your project ID through the console: open the Firebase console, select your project, click the settings icon, go to "Project settings," and its ID is on the second line of the table.
For this to work, you have to move your token straight into the code. You can't use a shell file like .env.
In the end, your code will be:
const functions = require('firebase-functions');
const token = 'whatever the token is';
const Discord = require('discord.js')
const Client = new Discord.Client();
Client.on('ready', () => {
Client.channels.find(x => x.name === 'main-cannel').send('bot is deployed')
Client.user.setGame(`The Cult | ${Client.guilds.size} servers`)
Console.log('test')
});
exports.app = functions.https.onRequest((request, response) => {
response.send("Test"); // Do not delete this! Your request will time out if you do.
Client.login(token);
});
As Gabber235 noted, this is probably not the best Google Cloud Platform service to use for this, and you should probably use Compute Engine.

How can I get my bot to post a message to a Microsoft Teams channel?

I have a bot that is identical to the one demonstrated in the docs quickstart. It repeats back whatever the user says (for now).
It is currently running locally and exposed with ngrok. I've registered the bot with the Microsoft Bot Framework.
I have configured the Microsoft Teams channel in the Microsoft Bot Framework, and I've sideloaded my bot into Teams. My bot can receive messages from Teams users.
At present, the bot just repeats whatever it receives back to the user, but what I want it to do is post to a Microsoft Teams channel. I want it to post to a Teams channel - not a user - without being prompted first by a user. So for example given a certain condition (eg. triggered by some event such as time of day, a pull request, etc.) it posts a message in a channel.
I've read the documentation about sending proactive messages, and I gather that in order to send a message to a teams channel, the bot needs to know the "address" of the user. This information is stored in the session.message.address object, and it gets this from the current conversation. However, in my case I don't have a 'current conservation', because I don't want to just respond to a user, I want to post in a channel proactively.
So, how do I permanently set the necessary credentials/address/session-data for the Teams channel?
Things I've looked into:
Webhooks. I've configured a webhook in my Teams channel, and I can send it a message easily enough (using the webhook url) using curl. So I can send the Teams channel a simple message with just a url (no authentication required), but I'm not sure how I'd get this url into my bot.
How do we maintain different session for different users in Microsoft Bot Framework? I'm not sure that the answer here answers my question. My problem is that the bot is initiating the 'conversation', not a Teams user, so I need to be able to set the session data myself so the bot knows where to go.
App.js:
require('dotenv').config();
var restify = require('restify');
var builder = require('botbuilder');
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with the Bot Framework Service
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
// Listen for messages from users
server.post('/api/messages', connector.listen());
// Receive messages from the user and respond by echoing each message back (prefixed with 'You said:')
var bot = new builder.UniversalBot(connector, function (session) {
session.send("You said: %s", session.message.text);
});
For anyone who is wondering about the same for c#, here is the solution that worked for me:
var channelData = context.Activity.GetChannelData<TeamsChannelData>();
var message = Activity.CreateMessageActivity();
message.Text = "Hello World";
var conversationParameters = new ConversationParameters
{
IsGroup = true,
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(channelData.Channel.Id),
},
Activity = (Activity) message
};
var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = await
connectorClient.Conversations.CreateConversationAsync(conversationParameters);
Note: If you are calling this outside Bot's controller code then you need to call TrustServiceUrl on serviceUrl as shown here:
MicrosoftAppCredentials.TrustServiceUrl(serviceUrl, DateTime.MaxValue);
var connectorClient = new ConnectorClient(new Uri(serviceUrl));
Source of answer: https://github.com/OfficeDev/BotBuilder-MicrosoftTeams/issues/162
It is definitely possible. We call these proactive messages and it’s possible to proactively message both users and channels.
For the latter, see the sample at https://github.com/OfficeDev/microsoft-teams-sample-complete-node, specifically this file, ProactiveMsgToChannelDialog.ts.
To send proactive messages to channels, you need to use the Microsoft Teams SDK (as these samples do).
Last but not least, you need to add the bot to a team in order to send a message to one of the channels in the team, which requires a manifest.
Hope this works for you.. below code proactively sends the message to session before initiating the chat.
bot.on('conversationUpdate', function (message) {
if (message.membersAdded[0].id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Hello"");
bot.send(reply);
}
});

How can I deploy firebase queue to app engine and have it observe Firebase nodes?

I am trying to send device-to-device notification via FCM which is not so trivial. I use Firebase as the database and by reading the documentation have learned that I need to have an app server to communicate between clients and FCM. Also, I have found that Firebase queue can be used to observe the Firebase nodes and upon any change e.g, ChildAdded, send a notification to other related users on other devices via FCM.
Unfortunately, I can't figure out how to deploy Firebase queue to app engine; as I'm not that experienced with node.js and it seems that Firebase queue documents are all written with node.js.
Any help would be appreciated.
So for someone who is new to node.js it was a bit of confusing cycle to understand whats going on , but I was able to upload a simple job which is pretty much the "sanichat" example of firebase-queue and it seems to be working.
Here's the job for anyone who might be struggling with the same issue:
// chat_message_sanitization.js
var Queue = require('firebase-queue');
var firebase = require('firebase');
firebase.initializeApp({
serviceAccount: 'path to the json file downloaded when setting up google services account',
databaseURL: 'https://***your firebase***.firebaseio.com/'
});
var db = firebase.database();
var
queueRef = db.ref('queue');
var messagesRef = db.ref('queue_messgs');
var options = {
'specId': 'sanitize_message'
};
var sanitizeQueue = new Queue(queueRef, options, function(data, progress, resolve, reject) {
// sanitize input message
data.message = sanitize(data.message);
// pass sanitized message and username along to be fanned out
resolve(data);
});
I have been able to run it locally "node app.js" and deploying using "gcloud app deploy"
Cheers!

Resources