I'm very new to JavaScript and Socket.io, I'm trying to create a space for the admins and the regular users.
only catch is I want the regular users chat to output to the admin chat.
How could I go about doing something like this? I've read the get started part and I'm still a bit lost.
I will explain User flow, This may help to solve your problem.
let adminSockets = []; // Here I'm considering multiple admin
let userSocketMap = {};
When user Login you want to connect socket to server with identical(admin) handshake
io.of('/').on('connect', socket => {
let { isAdmin, userId } = socket.handshake.headers
if(isAdmin) {
adminSockets.push(socket)
} else {
userSocketMap[userId] = socket;
}
});
While user send message to one another(User 1 send message to User 2)
socket.on('send', (data) => {
let fromUserId = socket.handshake.headers.userId // User 1
let toUser = data.toUserId // User 2 ( This is the user to whom you want to send message)
let message = data.message
let toSocket = userSocketMap[toUser];
toSocket.emit({form: fromUserId, message: message})
adminSockets.forEach(adminSocket => {
adminSocket.emit({form: fromUserId, to: toUser, message: message})
});
})
Related
I'm trying to code a discord bot that send a message to all users in a list. I am having problems using the client.users.fetch(); method on discord.js. The error message says something about DiscordAPIError: Unknown user, Unhandled promise rejection, and DiscordAPIError: Cannot send messages to this user, even though I am in the same guild as the bot.
Here is the code I have so far:
const Discord = require('discord.js');
const client = new Discord.Client();
const ownerId = 'YOUR-ID'
const users = ['YOUR-ID']
client.on('ready', () => {
console.log('Bot is online!');
});
client.on('message', async message => {
if (message.content.includes("test")) {
if (message.author.id == ownerId) {
message.channel.send("ok!")
var userID
var user
for (let i = 0; i < users.length; i++) {
userID = users[i];
user = client.users.fetch(userID.toString(), true);
client.user.send('works');
}
}
}
});
client.login('YOUR-TOKEN');
There are several issues in your code.
Firstly, client.users.fetch(...) is an asynchronous function therefore it requires an await.
Secondly, client.user.send(...) will actually send a message to the bot which is impossible. So you'll want to replace it with either message.channel.send(...) which will send the message in the same channel the message was received in or message.author.send(...) which will send a message to the author of the message.
Below is an example fix:
const Discord = require('discord.js'); // Define Discord
const client = new Discord.Client(); // Define client
const ownerId = 'your-discord-user-id';
const users = [] // Array of user ID's
client.on('ready', () => { // Ready event listener
console.log('Bot is online!'); // Log that the bot is online
});
client.on('message', async message => { // Message event listener
if (message.content.includes("test")) { // If the message includes "test"
if (message.author.id == ownerId) { // If the author of the message is the bot owner
message.channel.send("ok!"); // Send a message
// Define variables
let userID;
let user;
for (let i = 0; i < users.length; i++) { // Loop through the users array
userID = users[i]; // Get the user ID from the array
user = await client.users.fetch(userID.toString()); // Await for the user to be fetched
message.channel.send('works'); // Send a message to tell the message author the command worked
}
}
}
});
client.login('YOUR-TOKEN'); // Login your bot
bot.on('channelCreate', async channel => {
if (!channel.guild) return;
const fetchedLogs = await channel.guild.fetchAuditLogs({
limit: 1,
type: 'CHANNEL_CREATE',
});
const logbook = channel.guild.channels.cache.get("ChannelID")
const deletionLog = fetchedLogs.entries.first();
if (!deletionLog) return logbook.send(`A channel was updated but no relevant autid logs were found`);
const { executor, user } = deletionLog;
if (user.id) {
logbook.send(`${executor.tag} created a channel`);
} else {
logbook.send(`A channel was created but idk who did.`);
}
});
I am a newbie when it comes to fetching actions through Discord Audit Logs; so I am experimenting and somehow came up with this code. However, when I create a channel, it does not send any messages saying that a channel has been created by #user. I have no idea what my next step will be. All I wanted to do was to know who created the channel.
Discord.JS: v12.2.0
client.on("channelCreate", async channel => {
if (!channel.guild) return false; // This is a DM channel.
const AuditLogFetch = await channel.guild.fetchAuditLogs({limit: 1, type: "CHANNEL_CREATE"}); // Fetching the audot logs.
const LogChannel = client.channels.cache.get("722052103060848664"); // Getting the loggin channel. (Make sure its a TextChannel)
if (!LogChannel) return console.error(`Invalid channel.`); // Checking if the channel exists.
if (!AuditLogFetch.entries.first()) return console.error(`No entries found.`);
const Entry = AuditLogFetch.entries.first(); // Getting the first entry of AuditLogs that was found.
LogChannel.send(`${Entry.executor.tag || "Someone"} created a new channel. | ${channel}`) // Sending the message to the logging channel.
});
If the code I provided is not working, please make sure the bot has access to view AuditLogs.
When a user joins the server, the bot sends a welcome message, i want to take that welcome message's ID and make the bot delete it if the users leaves after he joins. I tried to save the message's id in a variable and make the bot delete the message when the user leaves but without success. I already took a look at the docs, but I really can't understand how to make it.
Define an object to hold the welcome messages by guild and user. You may want to use a JSON file or database (I'd highly recommend the latter) to store them more reliably.
When a user joins a guild...
Send your welcome message.
Pair the the message's ID with the user within the guild inside of the object.
When a member leaves the guild...
Fetch their welcome message.
Delete the message from Discord and the object.
Example setup:
const welcomeMessages = {};
client.on('guildMemberAdd', async member => {
const welcomeChannel = client.channels.get('channelIDHere');
if (!welcomeChannel) return console.error('Unable to find welcome channel.');
try {
const message = await welcomeChannel.send(`Welcome, ${member}.`);
if (!welcomeMessages[member.guild.id]) welcomeMessages[member.guild.id] = {};
welcomeMessages[member.guild.id][member.id] = message.id;
} catch(err) {
console.error('Error while sending welcome message...\n', err);
}
});
client.on('guildMemberRemove', async member => {
const welcomeChannel = client.channels.get('channelIDHere');
if (!welcomeChannel) return console.error('Unable to find welcome channel.');
try {
const message = await welcomeChannel.fetchMessage(welcomeMessages[member.guild.id][member.id]);
if (!message) return;
await message.delete();
delete welcomeMessages[member.guild.id][member.id];
} catch(err) {
console.error('Error while deleting existing welcome message...\n', err);
}
});
To do this you would have to store the id of the welcome message and the user that it is tied to (ideally put this in an object). And when the user leaves you would use those values to delete that message.
Example code:
const Discord = require('discord.js');
const client = new Discord.Client();
const welcomeChannel = client.channels.find("name","welcome"); // Welcome is just an example
let welcomes = [];
client.on('message', (message) => {
if(message.channel.name === 'welcome') {
const welcomeObj = { id: message.id, user: message.mentions.users.first().username };
welcomes.push(welcomeObj);
}
});
client.on('guildMemberRemove', (member) => {
welcomes.forEach(welcome, () => {
if(welcome.user === member.user.username) {
welcomeChannel.fetchMessage(welcome.id).delete();
}
});
});
This only works if the welcome message includes a mention to the user so make sure that's in the welcome message.
Also I can't test this code myself at the moment so let me know if you encounter any problems.
In my app, I am sending push notifications to the followers of a user when that user creates a new post. As you can see in the code below, I have some additional settings that I need to query from each follower's profile to get their push token and check for some additional notification settings. I am afraid that this query of each user's profile might become a bottleneck if a user has a large number of followers i.e. 1000.
What is the best way to approach this?
// The cloud function to trigger when a post is created
exports.newPost = functions.database.ref('/posts/{postId}').onCreate(event => {
const postId = event.params.postId;
const post = event.data.val();
const userId = post.author;
let tokens = [];
let promises = [];
return admin.database().ref(`/followers/${userId}`).once('value', (followers) => {
followers.forEach((f) => {
let follower = f.key;
promises.push(
admin.database().ref(`users/${follower}`).once('value')
);
});
})
.then(() => {
return Promise.all(promises).then((users) => {
users.forEach((user) => {
const userDetails = user.val();
if (userDetails.post_notifications) {
if(userDetails.push_id != null) {
tokens.push(userDetails.push_id);
}
}
})
})
})
.then(() => {
if (tokens.length > 0) {
const payload = {
notification: {
title: 'New Post!',
body: 'A new post has been created'
}
};
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload);
}
});
})
EDIT:
We have thought about using topics. But we are not sure how we can still have our customized notifications settings working with topics. Here's our dilemma.
We have multiple actions that can create notifications and we provide individual switches for each type of notification in the app so a user can select which type of notifications they want to switch off.
Let's say when User A follows User B. We can subscribe User A to "User B's topic" so whenever User B performs an action which sends out notifications to his/her followers, I can send send out notifications to users subscribed to "User B topic".
Because we have multiple notification switches in the app and when user A changes his/her settings that they do not want notifications for new posts but still want other types of notifications from the users he/she follows, we have not been able to figure out how we can use topics in this case.
Instead of using tokens, you can use topics for this. So lets say a user started following someone, then he will register to that topic.
Lets say he followed someone called "Peter", then you can execute this:
FirebaseMessaging.getInstance().subscribeToTopic("Peter");
Now if you have this database:
posts
postid
postdetails: detailshere
author: Peter
then using onCreate():
exports.newPost = functions.database.ref('/posts/{postId}').onCreate(event => {
const postId = event.params.postId;
const post = event.data.val();
const authorname = post.author;
const details=post.postdetails;
const payload = {
data: {
title:userId,
body: details,
sound: "default"
},
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
return admin.messaging().sendToTopic(authorname, payload, options);
});
You can use this, everytime the author creates a new post, onCreate() is triggered then you can add the details of the post and the author name in the notification (if you want) and sendToTopic() will send it to all users subscribed to the topic that is the authorname (ex: Peter)
After your edit, I think you want the user to be unsubscribed from a topic, but stay subscribed to other topics, then you have to use the admin sdk for this:
https://firebase.google.com/docs/cloud-messaging/admin/manage-topic-subscriptions
Using the admin sdk you can unsubscribe the user also from a topic, a simple example:
// These registration tokens come from the client FCM SDKs.
var registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// ...
'YOUR_REGISTRATION_TOKEN_n'
];
// Unsubscribe the devices corresponding to the registration tokens from
// the topic.
admin.messaging().unsubscribeFromTopic(registrationTokens, topic)
.then(function(response) {
// See the MessagingTopicManagementResponse reference documentation
// for the contents of response.
console.log('Successfully unsubscribed from topic:', response);
})
.catch(function(error) {
console.log('Error unsubscribing from topic:', error);
});
I'm building an app with Firebase and as they added functions I wanted to try this out but ran into a few errors as I am unfamiliar with this language... I'm trying to send an FCM to every user of a group (when a new one is added to the database) and I used the example I found online but still ran into some trouble.
exports.sendPush = functions.database.ref('/groups/{groupId}').onWrite(event => {
const groupId = event.params.groupId;
... // defining constants like msg
const participators = admin.database().ref('/groups/' + groupId + '/users').once('value');
let getDeviceTokensPromise = []
for (let part in participators) {
getDeviceTokensPromise.push(admin.database().ref('/users/' + part + '/notificationtoken')).once('value');
}
return Promise.all([getDeviceTokensPromise, participators]).then(results => {
const tokensSnapshot = results[0];
const follower = results[1];
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('Fetched follower profile', follower);
// Notification details.
const payload = {
notification: {
title: 'New meeting!',
body: msg
}
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
...
So I guess my mistake must be in the first few lines as all the rest follows this code (I left out the unimportant bits)... Here is my firebase architecture:
The groups branch of the firebase database
One user under the branch users
Regards
Your code is fine. Just change the following
const participators = admin.database().ref('/groups/' + groupId + '/users').once('value');
and
getDeviceTokensPromise.push(admin.database().ref('/users/' + part + '/notificationtoken')).once('value');
to these :-
const participators = admin.database().ref(`/groups/${groupId}/users`).once('value');
and
getDeviceTokensPromise.push(admin.database().ref(`/users/${part}/notificationtoken`)).once('value');
Also, make sure that you use `` and not ' ' inside the ref part.