I'm building a chat application where I have conversations and messages, which are stored as respective objects. The messages are bundled according to the conversation that they belong to. So when I push messages, they're being pushed under their conversation's Id.
I have the following implementation :
allMsgs = {
...allMsgs,
[payload.conversationId]: {
...payload.message
}
}
I am able to add and categorize the messages into their respective conversations but not bundle the messages themselves. The last message is always overwriting the contents -which are the messages- of each conversationId. So I'm left with allMsgs having multiple conversatinIds but one message in each conversationId. This seems like such a duh thing but I can't seem to figure out.
Turned out to be a duh thing
state.allMsgs = {
...state.allMsgs,
[payload.conversationId]: {
...state.allMsgs[payload.conversationId],
[payload.message.id]: payload.message
}
}
Related
I'm trying to create a basic TCG style game with Node/Vue/Socket.io and can't seem to figure out how to emit to both clients when a "ready" count = 2 but with different data, I'll explain a little below...
The sequence of events is as such:
player connects -> server sends player a "deck" -> player clicks ready to start and also sends back their first 'card'.. Then the server should send out to each player the other players first card. (Note my emit events don't have the correct titles atm - they were already written up on the front end so just kept them the same)
On connection I've pushed to an array called sockets, that I was using for testing. Then in the "ready" event I created an array called "firstCards" that I'm pushing the socket event data to then adding a .socket property to it (to signify who's who), then incrementing ready.
I've had a little bit of a play around with a few different methods but I can only seem to get the last card sent to both clients as opposed to each client getting the other clients first.. I also tried just putting the "if" statement outside of the socket event (as you will see below with the comment on the brackets/curly braces) which doesn't seem to work either.
I haven't tried this kind of asymmetric data transfer before and unsure if that is even the correct term... or whether this is even the correct way to do so, any help would be much appreciated!
This is the code I'm using so far:
socket.on('ready-up', function (card)
{
console.log(`Player ${socket.id} is ready`);
ready++;
console.log(ready);
card.socket = socket.id;
firstCards.push(card);
console.log(firstCards);
});
if (ready == 2)
{
for (let i = 0; i < sockets.length; i++)
{
io.to(sockets[i]).emit('p2hand', "Both players ready");
let opp = sockets.find(element => element != socket.id);
console.log(`Socket ID is: ${socket.id}`);
console.log(`Opp ID is: ${opp}`);
let card = firstCards.find(element => element.socket == opp)
console.log(card);
io.to(opp).emit('reveal',
{
'name': card.name,
'hp': card.hp,
'mp': card.mp,
'skills': card.skills,
'icon': card.icon
});
// io.to(opp).emit('reveal', card);
ready = 0;
}
}
// });
So I figured this one out for anyone who may end up wanting to do what I was trying to do....
I decided that upon connection, both clients join a room called "game1".
The server will then emit "firstCards" to that room.
After that it was just a case of making sure the player-client know which was the opponents card... Now I could have used the .name property for this, but I decided to add an "id" property using the socket.id instead due to the possibility of the same card being drawn for both players.
I'm thinking that all server-client interactions will now have to carry this property for any other cards in the game such as items, spells, etc
I am currently coding a discord bot and have just created a JSON file. This file is to record each members points in a system. I wanted to check within the client.on("ready") function whether a member's points is undefined if so, set it to 0
if (client.points[/*problem*/guild.member.id].points == undefined) {
client.points [/*problem*/guild.member.id] = {
points: 0;
}
fs.writeFile("./points.json", JSON.stringify (client.points, null, 4), err => {
if (err) throw.err;
});
I improvised with "guild.member.id", however, I don't think that is the right way to do it.
EDIT: Due to the impossibility and inefficiency of retrieving the User's ID within the ready function, I have created an if statement every time a player speaks, which then assigns them to my JSON. This has a benefit of recording whether the user is active or not.
You typically don't want to do this every time the bot comes online. Instead, before you do anything related to points, first check if they are saved, if they aren't initialized them with your default values and save them.
https://anidiots.guide/coding-guides/json-based-points-system
I finally got RANGE_ADD mutations to work. Now I'm a bit confused and worried about their performance.
One outputField of a RANGE_ADD mutation is the edge to the newly created node. Each edge has a cursor. cursorForObjectInConnection()(docs) is a helper function that creates that cursor. It takes an array and a member object. See:
newChatroomMessagesEdge: {
type: chatroomMessagesEdge,
resolve: async ({ chatroom, message }) => {
clearCacheChatroomMessages();
const messages = await getChatroomMessages(chatroom.id);
let messageToPass;
for (const m of messages) {
if (m.id === message.id) {
messageToPass = m;
}
}
return {
cursor: cursorForObjectInConnection(messages, messageToPass),
node: messageToPass,
};
},
},
plus a similar edge for user messages.
Now this is what confuses me. Say you want to make a chatroom app. You have a userType, a chatroomTypeand a messageType. Both the userType and the chatroomType have a field messages. It queries for all of the user's or chatroom's messages respectively and is defined as a relay-connection that points to messageType. Now, each time a user sends a new message, two new RANGE_ADD mutations are committed. One that creates an edge for the chatroom's messages and one that creates an edge for the user's messages. Each time, because of cursorForObjectInConnection(), a query for all of the user's messages and one for all of the chatroom's messages is sent to a database. See:
const messages = await getChatroomMessages(chatroom.id);
As one can imagine, there occur lots of "message-sent-mutations" in a chatroom and the number of messages in a chatroom grows rapidly.
So here is my question: Is it really necessary to query for all of the chatroom messages each time? Performance-wise, this seems like an awful thing to do.
Sure, although I did not look into it yet, there are optimistic updates I can use to ease the pain client-side - a sent message gets displayed immediately. But still, the endless database queries continue.
Also, there is Dataloader. But as far as I understand Dataloader, it is used as a per request batching and caching mechanism - especially in conjunction with GraphQL. Since each mutation should be a new request, Dataloader does not help on that front either it seems.
If anyone can shed some light on my thoughts and worries, I'd be more than happy :)
I've made a working chat with meteor and mongodb, but I want to play a sound or something when there is a new message. However, I don't know how to check if data is updated. I could check if there is a new message by counting the messages before and after the update, but I just don't know how to check for an update.
So my question here is: How do I check for an update in the data?
I have a website that needs to pop up a toastr alert whenever a new message arrives. My collection is called "Alerts". This is what I do:
Alerts.find({notified: false}).observeChanges({
added: function(id, doc) {
Alerts.update(id, {
$set: {
notified: true
}
});
toastr.info(foo, bar);
}
});
Whenever a new alert is created whose field "notified" is false, a toastr alert will be created and that alert will be marked as "notified: true".
Alternatively you could do the same thing but create a separate collection of "notifications" that when observed, are removed from the collection as well that are a distinct collection from your chat messages collection.
You could create a tailing cursor on the oplog collection, so you get a new document whenever something (anything!) in the database changes. But that's not really an elegant solution, because that handler would need to process a lot of junk.
It might be better to have the routine which writes the message to the database also inform any currently online users. There is really no good reason to go the detour over the database.
I have publishing setup along with sessions to send out messages to the right rooms.
I'm currently having issues as to how do I go about limiting returned messages so if a room has, say, 200 messages in it and another one is posted, the oldest one is deleted.
//how messages are created
Meteor.methods({
newMessage: function (message) {
message.user = Meteor.userId();
Messages.insert(message);
}
});
//how messages are published
Meteor.publish('messages', function (channel) {
return Messages.find({channel: channel});
});
//how chatrooms are published
Meteor.publish('channels', function () {
return Channels.find();
});
Problem is, normally I would do this by putting this in the publications {sort:{limit:15}}
However, that doesn't work in this case and results in ALL of the messages being limited.
They need to be sorted by room, or, well, per session:key.
Is there a simple way of going about this? Or would I have to make a method on the serverside to run .forEach channel?
There's no decent way of publishing the top 15 posts from each room in a single cursor. If the number of rooms is small it might make sense to publish an array of cursors instead, each cursor in the array corresponding to a single room.
Meteor.publish('messages', function (channel) {
return Messages.find({channel: channel}, {limit: 15});
});
I have no idea how I missed this but apparently I can just do it this way.
Huh.
(channel:channel corresponds to currently set session's name)