Slackbot api can't receive messages - node.js

I'm building a SlackBot with NodeJS.
I'm currently using this library slackbots, but the problem is that after the initialization, the bot does not appear in the Apps category, but it's inside SlackBot and every time I type a message it returns an error message:
I'm sorry, I don't understand! Sometimes I have an easier time with a few simple keywords. Or you can head to our wonderful Help Center for more assistance!
On the other side, when I send a message to a user I can see the bot I have set up:
How can I make the bot Hugo separated from the SlackBot inside Slack?
That's how I set it up:
var SlackBot = require('slackbots');
var bot = new SlackBot({
token: process.env.SLACK_TOKEN,
name: 'Hugo'
});
function get() {
return bot;
}
exports.get = function() {
return bot;
}
exports.send_message = function(user_ref, message) {
bot.postMessage(user_ref, message).then((data) => {
return data;
});
}
exports.get_users = function() {
var user_list = get().getUsers();
return user_list;
}
And this is how I send the test message:
var bot = require('./modules/bot.js');
bot.get().on('message', function(data) {
console.log("#######################################"); // -> debug only
console.log(data);
console.log("#######################################");
bot.send_message('USER_ID', 'test response');
});

Related

Currently I am facing challenge in sending proactive 1 to 1 messages to a large number of users in parallel without delay

Solution illustration:
Currently, i am facing challenge in sending proactive 1 to 1 messages to a large number of users in parallel without delay.
Right now I am trying these approaches:
For an array of conversationID’s we use .map() to call our async/await function that sends a proactive messages, then Promise.all() to gather them back up again.
I am also trying to create workers using cluster module and distributing split of conversationid’s to each worker.
What is the recommended approach to overcome this issue?
Can I improve the solution by integrating with Microsoft graph API?
// Listen for incoming notifications and send proactive messages to users.
server.get('/api/notify', async (req, res) => {
// map through the agents list
const promises = userslist.map(async agent => {
var sendmsg = sendUserMessage(user.conversationid);
return sendmsg;
})
const results = await Promise.all(promises)
console.log(results);
res.json(results);
res.end();
});
// function to send message
const sendUserMessage = async function (userConversationReference) {
try{
MicrosoftAppCredentials.trustServiceUrl(serviceUrl);
var credentials = new MicrosoftAppCredentials(process.env.BotId, process.env.BotPassword);
var connectorClient = new ConnectorClient(credentials, { baseUri: serviceUrl });
var message = MessageFactory.text("Hello this is a test notification!");
// User Scope
const conversationParameters = {
isGroup: false,
channelData: {
tenant: {
id: process.env.TENANT_ID
}
},
bot: {
id: process.env.BotId,
name: process.env.BotName
},
members: [
{
id: userConversationReference
}
]
};
var conversationResponse = await connectorClient.conversations.createConversation(conversationParameters);
var response = await connectorClient.conversations.sendToConversation(conversationResponse.id, message);
return response;
} catch (error) {
return error.statusCode;
console.error(error);
}
}
Here is documentation on how to Optimize your bot with rate limiting in Teams.
Sharing code snippet from the doc for your reference:
try
{
// Perform Bot Framework operation
// for example, await connector.Conversations.UpdateActivityAsync(reply);
}
catch (HttpOperationException ex)
{
if (ex.Response != null && (uint)ex.Response.StatusCode == 429)
{
//Perform retry of the above operation/Action method
}
}
Sample code references:
Teams Proactive Messaging Samples
Company Communicator App Template

msg.content not being defined

Okay so I am trying to make an announcement command for my server, but when I try to run this it says: ReferenceError: msg is not defined
I am not sure on what it is that I am doing incorrectly.
Here is the code in question:
'use strict';
//require discord.js package
const Discord = require("discord.js");
const config = require("./config.json")
//Create an instance of a Discord client
const client = new Discord.Client();
//The ready event is vital, only after this will your bot start reacting and responding
client.on('ready', () => {
console.log('I am ready!');
});
//create an event listener for messages
client.on('message', message => {
if (message.content === 'ping') {
message.channel.send('pong');
}
});
if (msg.content === "^ann"){
let channel = client.channels.cache.get('channel id');
msg.channel.send("What is your announcement? (^cancel to cancel)");
const collector = msg.channel.createMessageCollector(m => m.author.id === msg.author.id, { time: 100000000 });
collector.once('collect', m => {
if (m.content == "^cancel") {
m.author.send("Announcement cancelled.");
return;
} else {
var announcement = m.content;
channel.send(announcement);
msg.channel.send("Announcement made!");
return;
}
});
//Do stuff
client.on("message", function (msg) {
if (msg.content.indexOf("^mirror") === 0) {
let item = new Discord.MessageEmbed()
.setImage(msg.author.displayAvatarURL())
.setColor("#E6E6FA")
.setFooter("OMG! WHEW~");
msg.channel.send(item);
}
})
//Bot Token
client.login('token')}
This is what i have for the code that I am working on
The error appears because you have your code outside the message event. So all the code about the message etc. has to be in the message event.
The second thing, I suggest to create 1 message event. I see you have created 2 message events. That is not a big problem, but it will clean your code en is more effective. Now, if someone sends a message, he will check this message 2 times. I hope I made it a little bit clear!

How to send MQTT "message" event back to REST body?

I'm currently having problems figuring out how to capture my MQTT message event back to my REST API body which is written in NodeJS. My current setup is App -> NodeJS REST API -> MQTT broker inside RPi 3.
This is my MQTTHandler.js class where I have put all my reusable MQTT functions
const mqtt = require('mqtt')
class MQTTHandler {
constructor (host) {
this.client = null
this.host = host
}
connect () {
this.client = mqtt.connect(this.host)
this.client.on('error', function (err) {
console.log(err)
this.client.end()
})
this.client.on('connect', function () {
console.log('MQTT client connected...')
})
// I need this to send message back to app.js
this.client.on('message', function (topic, message) {
if (!message.toString()) message = 'null'
console.log(JSON.parse(message.toString()))
})
this.client.on('close', function () {
console.log('MQTT client disconnected...')
})
}
subscribeTopic (topic) {
this.client.subscribe(topic)
}
unsubscribeTopic (topic) {
this.client.unsubscribe(topic)
}
sendMessage (topic, message) {
this.client.publish(topic, message)
}
}
module.exports = MQTTHandler
And below is a short snippet of my app.js
const MQTTHandler = require('./mqtt.handler')
...
var mqttClient = new MQTTHandler('mqtt://127.0.0.1')
mqttClient.connect()
app.get('/hello', function (req, res) {
mqttClient.subscribeTopic('topic')
mqttClient.sendMessage('topic', 'hello world')
// I need to return the MQTT message event here
// res.json(<mqtt message here>)
res.end()
})
I have already tried using NodeJS' event emitter but it doesn't seem to work. Any help or suggestions would be much appreciated, thank you!
You are trying to mix a synchronous protocol (HTTP) with and asynchronous protocol (MQTT). These 2 paradigm don't easily mix.
When you publish an MQTT message you have no idea how many clients may be subscribed to that topic, it could be zero, it could be many. There is also no guarantee that any of them will send a reply so you need to include a timeout. (You also need to include a request id in the payload so you can coordinate any response with the request as you can't say anything about what order responses may come in.)
Your example code is only using 1 topic, this is very bad as you will end up needing to filter out request messages from response messages. Better to use 2 different topics (MQTT v5 even has a msg header to specify the topic the response should be sent on).
Having said all that it is possible to build something that will work (I will use request and reply topics.
var inflightRequests = {};
// interval to clear out requests waiting for a response
// after 3 seconds
var timer = setInterval(function() {
var now = new Date.now();
var keys = Object.keys(inflightRequests);
for (var key in keys) {
var waiting = inflightRequests[keys[key]];
var diff = now = waiting.timestamp;
// 3 second timeout
if (diff > 3000) {
waiting.resp.status(408).send({});
delete(inflightRequests[keys[key]]);
}
}
},500);
// on message handler to reply to the HTTP request
client.on('message', function(topic, msg){
if (topic.equals('reply')) {
var payload = JSON.parse(msg);
var waiting = inflightRequest[payload.requestId];
if (waiting) {
waiting.res.send(payload.body);
delete(inflightRequests[payload.requestId]);
} else {
// response arrived too late
}
}
});
// HTTP route handler.
app.get('/hello', function(req, res) {
//using timestamp as request Id as don't have anything better in this example.
var reqId = Date.now();
var waiting = {
timeStamp: reqId,
res: res
}
inflightRequests[reqId] = waiting;
var message = {
requestId: reqId,
payload: 'hello world'
}
client.publish('request',JSON.stringify(message));
});

How to make Slack bot dynamically reply at the same channel using node.js

I want to make my slackbot app to answer at the channel that the user mentioned, without manually writing the channel name inside the code.
-example-
problem : I invited my bot into channel #hello, #hi.I mentioned my bot at Channel #hello writing #mybot hi there, but it only replies to channel #hi which I manually wrote down in my code.
I want my bot to automatically find which channel the message came from, and answer back at the same channel that user mentioned.
Not like the code I wrote bot.postMessageToChannel('everyone', `Chuck Norris: ${joke}`,params);
Here is the link of the module that I used and my code
https://github.com/mishk0/slack-bot-api
const SlackBot = require('slackbots');
const axios = require('axios');
const bot = new SlackBot({
token : "",
name : ""
});
// Start Handler
bot.on('start', () =>{
const params = {
icon_emoji: ':)'
};
bot.postMessageToChannel('everyone', 'Feeling tired??? Have some fun with #Joker!'
, params);
});
// Error Handler
bot.on('error', (err) => console.log(err));
//Message Handler
bot.on('message', (data) => {
if(data.type !== 'message'){
return;
}
console.log(data);
handleMessage(data.text);
});
// Responding to Data
function handleMessage(message){
if(message.includes('chucknorris')){
chuckJoke();
}
else if(message.includes(' yomama')){
yoMamaJoke();
}
else if(message.includes(' random')){
randomJoke();
}
else if(message.includes(' help')){
runHelp();
}
}
// Tell a Chuck Norris Joke
function chuckJoke(){
axios.get('http://api.icndb.com/jokes/random/')
.then(res =>{
const joke = res.data.value.joke;
const params = {
icon_emoji: ':laughing:'
};
bot.postMessageToChannel('everyone', `Chuck Norris: ${joke}`,params);
});
}
From here you will find on message it returns you the data object whith channel id
then
you can use postMessage() from the api you have used
postMessage(id, text, params) (return: promise) - posts a message to channel | group | user by ID,
bot.on('message', (data) => {
bot.postMessage(data.channel, 'Feeling tired??? Have some fun with #Joker!'
, params);
console.log(data);
handleMessage(data.text);
});

Socket.io - React : How to retrieve saved socket.io data (MongoDB) in React?

I followed few tutorials on how to display messages sent in the chatroom before joining in, but I don't know how to display them in React and I have few questions below in the server side.
Client side, in constructor :
this.state = {
msg: "",
messages: []
};
Client side, I have a form which clicked button will send the message to the server by this function :
sendMessage(e) {
e.preventDefault();
let msg = this.state.msg;
this.socket.emit("sendMessage", msg);
this.setState({ msg: "" });
}
Server side, I have a mongoose Schema for the message, named Message and the collection in the database is messages.
const Message = new mongoose.Schema({
sender: {
type: "string"
},
message: {
type: "string"
}
});
var messages = [];
io.on("connection", (socket, user) => {
var user = socket.request.session.user;
Message.find({}).exec((err, messages) => {
if (err) throw err;
console.log(messages);
io.emit("showingPastMessages", messages);
});
console.log(messages) shows in PowerShell all the messages (entries) saved in Mongo in an array of javascript objects ?
[{id_ : 4qxxx, sender : 'user123', message : 'hello!'}, {id_ : 5exxx, sender : 'user456', message : 'hi!'}]
I would like to know if it is possible to access only to sender and message properties to send it to the client ? Something like messages.sender + messages.message because when I console.log(messages.message) it shows undefined
Here is where the server receives the message sent then saves it in Mongo.
socket.on("sendMessage", function(msg) {
var newMsg = new Message({ message: msg, sender: user });
newMsg.save(function(err) {
if (err) {
console.log(err);
} else {
messages.push(newMsg);
console.log(newMsg);
console.log(messages);
}
});
});
console.log(newMsg) shows the latest msg sent, but the console.log(messages) doesn't show the previous messages but only the latest one, why ?
then in React, I should have something like this in constructor, in ComponentDidMount() ? If should it be with prevState
this.socket.on("showingPastMessages", function(messages){
this.setState({ ...this.state.messages, messages})
});
Could you could give me some advices ?
Here my client side code to retrieve the data:
class Chat extends Component {
constructor(props) {
super(props);
this.state = {
msg: "",
messages: []
};
var socket = io('http://localhost:3000');
this.socket.on("history", function(messages) {
console.log(messages);
});
}
That's a good start. What I would suggest doing is making this a little more event driven. To do that, you'll want to add the sockets to a room when they connect. How many rooms and how to split up the rooms will depend on your app, but I'll demonstrate the basic idea.
First, when a socket connects to your server, add that socket to a room and emit your chat history immediately.
io.on('connection', async (socket) => {
socket.user = socket.request.session.user;
socket.join('chat');
try {
const messages = await Message.find({});
socket.emit('history', messages);
} catch (err) {
// Handle this error properly.
console.error(err);
}
});
Then, later on, when you receive a message, you'll want to save that message and emit it to all of the sockets in your chat room.
socket.on("sendMessage", (msg, callback) => {
const message = new Message({ message: msg, sender: socket.user });
message.save(function(err) {
if (err) {
return callback(err);
}
io.to('chat').emit('message', message);
});
});
Finally, on the client side, you'll want to listen for the history event. When you receive it, you'll want to clear the chat history you currently have and replace it with what the server is telling you. Maybe this would look something like
socket.on('history', (messages) => {
this.setState({ messages });
});
You'll also want to listen for this message event, but with this event, you'll only append the message to your history. This might look something like
socket.on('message', (message) => {
this.setState({ messages: [ ...messages, message ] });
});
A word of warning, if when you tell the server about a new message, do not add it to your messages state array until you receive the message event. If you do so, you will notice double messages. For example, this might look something like
onSendMessage(evnt) {
evnt.preventDefault();
socket.emit("sendMessage", msg);
this.setState({ msg: "" });
}
Note: After receiving some feedback from the OP, I wanted to add a section on where to put the event handlers attached to the socket (i.e. all the socket.ons). My suggestion would be to add this code in the file that defines the Message schema at the bottom of the file in the io.on('connection') callback. For example,
const Message = new mongoose.Schema({/*...*/});
io.on('connection', (socket) => {
// Everything else I wrote above...
socket.on('sendMessage', (msg, callback) => {
// ...
});
});
On the client side, the event handlers would probably be registered when the chat component is mounted. For example,
class ChatComponent extends React.Component {
componentDidMount() {
this.socket = io('https://your-server-or-localhost/');
this.socket.on('history', (messages) => {
// See above...
});
}
}

Resources