SlackBot repeat the event without control - node.js

I am trying to create a bot in Slack called "Chochon", the problem is that when I receive the event "app_mention", chochon responds more than once several times in a row, instead of sending 1 message and stopping until they mention it again.
This is my code, chochon function:
socketModeClient.on('app_mention', async ({ event }) => {
try {
console.log(event);
let userBox = await Chochon.users.info({ user: event.user });
let userProfile = userBox.user.profile;
console.log(cli.green(`Event received : [ ${event.type} ] from [ ${userProfile.display_name} ]`));
// Respond to the event
Chochon.chat.postMessage({
channel: event.channel,
text: `Hello <#${event.user}>, I'm Chochon!, I'm a bot that can help you to manage your team.`
});
} catch (error) {
console.error(error);
}
});
The slack client:
Full code:
// Dependencies :
const dotenv = require('dotenv').config();
const path = require('path');
const cli = require('cli-color');
// Web client [CLI]
const { WebClient } = require('#slack/web-api');
const Chochon = new WebClient(process.env.SLACK_BOT_TOKEN.trim());
// Socket IO
const { SocketModeClient } = require('#slack/socket-mode');
const appToken = process.env.SLACK_APP_TOKEN;
const socketModeClient = new SocketModeClient({ appToken });
socketModeClient.start();
// Internal functions
//const eventManager = require(path.resolve(__dirname, './utils/events/manager'));
socketModeClient.on('app_mention', async ({ event }) => {
try {
console.log(event);
let userBox = await Chochon.users.info({ user: event.user });
let userProfile = userBox.user.profile;
console.log(cli.green(`Event received : [ ${event.type} ] from [ ${userProfile.display_name} ]`));
// Respond to the event
Chochon.chat.postMessage({
channel: event.channel,
text: `Hello <#${event.user}>, I'm Chochon!, I'm a bot that can help you to manage your team.`
});
} catch (error) {
console.error(error);
}
});
socketModeClient.on('slash_commands', async ({ body, ack }) => {
if (body.command === "/ping") {
console.log(cli.green(`Event received : [ ${body.command} ]`));
await ack({"text": "I got it, pong!"});
}
});

Related

wrong behavior of messages socket.io

I use socket.io and socket.io-client to create chat user - operator. I've made connections, all works good, but message sending has weird behavior.
Like I send message from first client to room in socket and don't see it, but other client can
When I send second message, the first sent msg just changes for the second one
I see this all messages in my Map on backend(I don't use DB yet) but can't see it on client side.
server
app.get("/rooms/:id", (req, res) => {
const roomId = req.params.id;
const obj = rooms.has(roomId)
? { messages: [...rooms.get(roomId).get("messages").values()] }
: { messages: [] };
res.send(obj);
});
app.post("/rooms", (req, res) => {
const { roomId, name } = req.body;
if (!rooms.has(roomId)) {
rooms.set(
roomId,
new Map([
["users", new Map()],
["messages", []],
])
);
}
res.json([...rooms.values()]);
});
io.on("connection", (socket) => {
socket.on("ROOM:JOIN", ({ roomId, name }) => {
socket.join(roomId);
rooms.get(roomId).get("users").set(socket.id, name);
const users = rooms && [...rooms.get(roomId).get("users").values()];
socket.to(roomId).emit("ROOM:JOINED", users);
});
socket.on("ROOM:NEW_MESSAGE", ({ roomId, name, text }) => {
const obj = { name, text };
console.log(rooms.get(roomId).get("messages"));
rooms.get(roomId).get("messages").push(obj);
socket.to(roomId).emit("ROOM:NEW_MESSAGE", obj);
});
socket.on("disconnect", () => {
rooms.forEach((value, roomId) => {
if (value.get("users").delete(socket.id)) {
const users = [...value.get("users").values()];
socket.to(roomId).emit("ROOM:JOINED", users);
}
});
});
});
client side
const [messageValue, setMessageValue] = useState<string>("");
const [freshData, setFreshData] = useState<Message[]>([]);
console.log(freshData);
const onSendMessage = () => {
socket.emit("ROOM:NEW_MESSAGE", {
roomId: socketData.roomId,
text: messageValue,
name: socketData.name,
});
setMessageValue("");
};
const getFreshData = async () => {
const { data } = await axios.get(
`http://localhost:4444/rooms/${socketData.roomId}`
);
setFreshData(data.messages);
};
useEffect(() => {
if (join) {
socket.emit("ROOM:JOIN", socketData);
getFreshData();
socket.on("ROOM:JOINED", (users) => {
console.log("new user", users);
});
}
}, [join]);
useEffect(() => {
socket.on("ROOM:NEW_MESSAGE", (message) =>
setFreshData([...freshData, message])
);
socket.on("ROOM:JOINED", (users) => {
console.log("new user", users);
});
}, []);
and just map through all messages, that I should get from server
Where I could make a mistake ? Thank you
So I had a mistake on client, I need to call socket function in other useEffect with dependency onSendMessage like this:
useEffect(() => {
socket.on("ROOM:NEW_MESSAGE", (message) =>
setFreshData([...freshData, message])
);
}, [onSendMessage]);
and to show your sent messages I need to make onSendMessage update state with messages like this:
const onSendMessage = () => {
socket.emit("ROOM:NEW_MESSAGE", {
roomId: socketData.roomId,
text: messageValue,
name: socketData.name,
});
setFreshData([...freshData, { text: messageValue, name: socketData.name }]);
setMessageValue("");
};
And it works !

Why am I not receiving emitted messages sent to socket server?

I'm trying to receive a message from a post request and forward it to a socket id.
I defined the socket logic so that when a user connects, they get a socket id matched with their phone number in a Map global variable called users
Socket logic
const socket = (io) => {
global.users = new Map()
io.on("connection", (socket) => {
global.rooms = [socket.id]
socket.join(global.rooms)
socket.on("introduce", function (phone) {
io.emit("new_connection", phone)
global.users.set(phone, socket.id)
console.log("users map --> ", global.users)
})
socket.on("disconnect", async () => {
console.log("user has disconnected")
})
})
}
API POST requests
messageHandler = async (req,res) => {
const receiver = global.users.get(req.body.To)
const sender = global.users.get(req.body.From)
const io: Server = req.app.get("io")
const message = {
body: req.body.Body,
from: req.body.From,
to: req.body.To,
dateCreated: new Date(),
}
if (receiver) {
const receiverRoom = global.users.get(receiver)
io.to(receiverRoom).emit("message-receive", message)
res.status(200).send("Message recieved")
}
}
according to my logic, I should be able to listen on "message-receive" in the client and receive the messages, but nothing happens when I do so.
Client side
import io from "socket.io-client"
import { domain, socketBase } from "../config"
const socket = io.connect(domain, { path: socketBase })
export class socketService {
static onSmsMessage(message) {
socket.on("message-receive", message)
}
static removeListeners() {
socket.removeAllListeners()
}
}
const testing = useCallback(
(message) => {
console.log(message)
},
[]
)
// Refresh when a new sms message received
useEffect(() => {
// socketService.onSmsMessage(SmsReceived)
socketService.onSmsMessage(testing)
return () => {
socketService.removeListeners()
}
}, [testing])

switching bot.on listeners for different modules

I'm creating the telegram bot, and I have question.
In app.js
const { admin } = require('./admin');
require('dotenv').config();
const token = process.env.token;
const bot = new TelegramBot(token, { polling: true });
let chatId = [];
async function startApp() {
let restTime = await moment.tz('America/Chicago').format('hh:mm A');
let weekend = await moment.tz('America/Chicago').day();
console.log("start bot " + restTime);
const nowHours = new Date().getHours()
const restMessage = {
text: process.env.restText
}
const weekendMessage = {
text: process.env.weekendText
}
function startBot() {
return bot.on('message', async(msg) => {
if (msg.text === '/admin'){
return admin(msg);
}
...
and I have:
admin.js:
require('dotenv').config();
const pass = process.env.passwordAdmin
function admin(bot,msg) {
bot.sendMessage(msg.from.id, 'Enter admin password')
bot.onText(`${pass}`,()=>{
bot.sendMessage(msg.from.id, "Good")
})
}
module.exports = {admin}
error: [polling_error] {}
How I can pause the bot.on listener in app.js when I start bot.onText listener or other listener, and then, when admin end they work, return to app.js listener?
Me helps my friend,
const pass = new RegExp(process.env.passwordAdmin)
...
bot.onText (pass, () => {
but listener bot.on('message'..) is still working.

TypeError: Cannot read property 'user' of undefined discord.js

So I was trying to fix this thing for a few hours now, and I have no idea what I'm doing wrong.
This thing should execute itself when member joins the guild
const { Discord, MessageEmbed } = require("discord.js")
module.exports = {
name: "guildMemberAdd",
run: async ({bot, member}) => {
const welcome = new MessageEmbed()
.setDescription(`
<:nezuko_peek:974066160108732517> — New friend just showed up: <#${member.user.id}>
Welcome fellow adventurer in **Jasmine Dragon**! What brings you in these sides? <:girl_love:973968823449436190> Here, go to <#972618593294512128> to introduce yourself and talk with us in <#971800237507248158>!
`)
.setImage("https://64.media.tumblr.com/01a9f72f062feaafa60cdbf80f9ba729/tumblr_inline_orgoyznIM51sd5e91_500.gif")
.setColor("#F7DF79")
.setFooter({ text: "Thank you for joining and enjoy your stay!" })
member.guild.channels.cache.get("971800237507248158").send({ content: `<#&974343947105206382>`, embeds: [welcome] })
}
}
Here's my event handler
const { getFiles } = require("../util/functions")
module.exports = (bot, reload) => {
const {client} = bot
let events = getFiles("./events/", ".js")
if (events.length === 0){
console.log("No events to load")
}
events.forEach((f, i) => {
if (reload)
delete require.cache[require.resolve(`../events/${f}`)]
const event = require(`../events/${f}`)
client.events.set(event.name, event)
if (!reload)
console.log (`${i + 1}. ${f} loaded`)
})
if (!reload)
initEvents(bot)
}
function triggerEventHandler(bot, event, ...args){
const {client} = bot
try {
if (client.events.has(event))
client.events.get(event).run(bot, ...args)
else
throw new Error(`Event ${event} does not exist`)
}
catch(err){
console.error(err)
}
}
function initEvents(bot) {
const {client} = bot
client.on("ready", () => {
triggerEventHandler(bot, "ready")
})
client.on("messageCreate", (message) => {
triggerEventHandler(bot, "messageCreate", message)
})
client.on("guildMemberAdd", () => {
triggerEventHandler(bot, "guildMemberAdd")
})
}
And here's my index.js
const Discord = require("discord.js")
require("dotenv").config()
const { MessageEmbed, MessageActionRow, MessageSelectMenu } = require("discord.js")
const slashcommands = require("./handlers/slashcommands")
const client = new Discord.Client({
intents: [
"GUILDS",
"GUILD_MESSAGES",
"GUILD_MEMBERS"
]
})
// Bot config
let bot = {
client,
prefix: "i?",
owners: ["511889215672287242"]
}
// Handlers
client.commands = new Discord.Collection()
client.events = new Discord.Collection()
client.slashcommands = new Discord.Collection()
client.loadEvents = (bot, reload) => require("./handlers/events")(bot, reload)
client.loadCommands = (bot, reload) => require("./handlers/commands")(bot, reload)
client.loadSlashCommands = (bot, reload) => require("./handlers/slashcommands")(bot, reload)
client.loadEvents(bot, false)
client.loadCommands(bot, false)
client.loadSlashCommands(bot, false)
// Slash commands handler
client.on("interactionCreate", (interaction) => {
if (!interaction.isCommand()) return
if (!interaction.inGuild()) return interaction.reply("This command can only be used in a server")
const slashcmd = client.slashcommands.get(interaction.commandName)
if (!slashcmd) return interaction.reply("Invalid slash command")
if (slashcmd.perm && !interaction.member.permissions.has(slashcmd.perm))
return interaction.reply("You don not have permission for this command")
slashcmd.run(client, interaction)
})
module.exports = bot
client.login(process.env.TOKEN)
Other events like "ready" and "messageCreate" are working just fine so I'm not sure why it's not working.

NodeJS WebRTC app using DataChannel isn't working in production server

I created a simple peer-to-peer app using NodeJS and WebRTC for something like a one-to-many livestreaming application.
So far it is working on my localhost but when I deployed the app on a production VM server on Google Cloud Platform, I can't create a DataChannel using peer.createDataChannel(). Or at least that is the issue that I see because it is not throwing any errors.
server.js
const port = process.env.PORT || 80;
const express = require('express');
const bodyParser = require('body-parser');
const webrtc = require('wrtc');
const app = express();
const status = {
offline: 'offline',
online: 'online',
streaming: 'streaming'
};
let hostStream;
let hostChannel;
let channelData = {
status: status.offline,
message: null
};
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/broadcast', async ({ body }, res) => {
try {
let peer = new webrtc.RTCPeerConnection({
iceServers: [
{
urls: "stun:stun.stunprotocol.org"
}
]
});
peer.ontrack = (e) => handleTrackEvent(e, peer);
peer.ondatachannel = (e) => handleHostDataChannelEvent(e);
let desc = new webrtc.RTCSessionDescription(body.sdp);
await peer.setRemoteDescription(desc);
let answer = await peer.createAnswer();
await peer.setLocalDescription(answer);
let payload = {
sdp: peer.localDescription,
status: channelData.status
};
res.json(payload);
} catch (e) {
console.log(e);
}
});
function handleTrackEvent(e, peer) {
hostStream = e.streams[0];
}
function handleHostDataChannelEvent(e) {
let channel = e.channel;
channel.onopen = function(event) {
channelData.message = '[ SERVER ]: Peer-to-peer data channel has been created.';
channel.send(JSON.stringify(channelData));
channelData.message = null;
}
channel.onmessage = function(event) {
console.log(event.data);
}
hostChannel = channel;
}
app.listen(port, () => console.log('[ SERVER ]: Started'));
streamer.js
function createPeer() {
let peer = new RTCPeerConnection({
iceServers: [
{
urls: "stun:stun.stunprotocol.org"
}
]
});
let channel = peer.createDataChannel('host-server');
channel.onopen = function(event) {
channel.send('Host: Data Channel Opened');
}
channel.onmessage = function(event) {
let data = JSON.parse(event.data);
if('status' in data) {
$('body').removeClass().addClass(data.status);
}
if('message' in data && data.message != null) {
$.toast({
heading: 'Data Channel',
text: data.message,
showHideTransition: 'slide',
icon: 'info',
position: 'top-center',
stack: false
})
}
}
peer.onnegotiationneeded = () => handleNegotiationNeededEvent(peer);
return peer;
}
On my localhost, when the host (streamer.js) starts streaming media, the server outputs Host: Data Channel Opened on the console and on the host's browser, I see the toast with a message Server: Peer-to-peer data channel has been created.. However when I try the application on my production server the server doesn't log that on the console and the host's browser doesn't open a toast with the message saying the data channel has been created.
There are no errors on both the browser console nor the server console so I don't really know where the problem is.
I do not see the gathering of ice candidates in your code - so it is no surprise your peers cannot establish a connection with each other. Here is the working sample of what your code should look like.
streamer.js:
async function createPeer(configuration) {
const localCandidates = [];
// Step 1. Create new RTCPeerConnection
const peer = new RTCPeerConnection(configuration);
peer.onconnectionstatechange = (event) => {
console.log('Connection state:', peer.connectionState);
};
peer.onsignalingstatechange = (event) => {
console.log('Signaling state:', peer.signalingState);
};
peer.oniceconnectionstatechange = (event) => {
console.log('ICE connection state:', peer.iceConnectionState);
};
peer.onicegatheringstatechange = (event) => {
console.log('ICE gathering state:', peer.iceGatheringState);
};
// Step 5. Gathering local ICE candidates
peer.onicecandidate = async (event) => {
if (event.candidate) {
localCandidates.push(event.candidate);
return;
}
// Step 6. Send Offer and client candidates to server
const response = await fetch('/broadcast', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
offer: offer,
candidates: localCandidates,
}),
});
const {answer, candidates} = await response.json();
// Step 7. Set remote description with Answer from server
await peer.setRemoteDescription(answer);
// Step 8. Add ICE candidates from server
for (let candidate of candidates) {
await peer.addIceCandidate(candidate);
}
};
// Step 2. Create new Data channel
const dataChannel = peer.createDataChannel('host-server');
dataChannel.onopen = (event) => {
dataChannel.send('Hello from client!');
};
dataChannel.onclose = (event) => {
console.log('Data channel closed');
};
dataChannel.onmessage = (event) => {
console.log('Data channel message:', event.data);
};
// Step 3. Create Offer
const offer = await peer.createOffer();
// Step 4. Set local description with Offer from step 3
await peer.setLocalDescription(offer);
return peer;
}
const configuration = {
iceServers: [
{
urls: 'stun:global.stun.twilio.com:3478?transport=udp',
},
],
};
// Add turn server to `configuration.iceServers` if needed.
// See more at https://www.twilio.com/docs/stun-turn
createPeer(configuration);
server.js:
const express = require('express');
const bodyParser = require('body-parser');
const webrtc = require('wrtc');
const port = process.env.PORT || 80;
const configuration = {
iceServers: [
{
urls: 'stun:global.stun.twilio.com:3478?transport=udp',
},
],
};
// Add turn server to `configuration.iceServers` if needed.
const app = express();
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post('/broadcast', async (req, res) => {
const {offer, candidates} = req.body;
const localCandidates = [];
let dataChannel;
// Step 1. Create new RTCPeerConnection
const peer = new webrtc.RTCPeerConnection(configuration);
peer.ondatachannel = (event) => {
dataChannel = event.channel;
dataChannel.onopen = (event) => {
dataChannel.send('Hello from server!');
};
dataChannel.onclose = (event) => {
console.log('Data channel closed');
};
dataChannel.onmessage = (event) => {
console.log('Data channel message:', event.data);
};
};
peer.onconnectionstatechange = (event) => {
console.log('Connection state:', peer.connectionState);
};
peer.onsignalingstatechange = (event) => {
console.log('Signaling state:', peer.signalingState);
};
peer.oniceconnectionstatechange = (event) => {
console.log('ICE connection state:', peer.iceConnectionState);
};
peer.onicegatheringstatechange = (event) => {
console.log('ICE gathering state:', peer.iceGatheringState);
};
peer.onicecandidate = (event) => {
// Step 6. Gathering local ICE candidates
if (event.candidate) {
localCandidates.push(event.candidate);
return;
}
// Step 7. Response with Answer and server candidates
let payload = {
answer: peer.localDescription,
candidates: localCandidates,
};
res.json(payload);
};
// Step 2. Set remote description with Offer from client
await peer.setRemoteDescription(offer);
// Step 3. Create Answer
let answer = await peer.createAnswer();
// Step 4. Set local description with Answer from step 3
await peer.setLocalDescription(answer);
// Step 5. Add ICE candidates from client
for (let candidate of candidates) {
await peer.addIceCandidate(candidate);
}
});
app.listen(port, () => console.log('Server started on port ' + port));
I found your stun server not fully functional, so I replaced it with another one from Twillio. Also, I added event handlers with which it is easy to track the state of the WebRTC session. You would do well to learn more about WebRTC connection flow, really.

Resources