I have created an app using socket... I am able to manage the conversation between two persons using socket connection.
Here is the code for it
User model
const schema = new Mongoose.Schema({
firstName: { type: String, default: '', trim: true },
lastName: { type: String, default: '', trim: true }
})
Conversation model
const schema = new Mongoose.Schema({
name: { type: String, trim: true },
type: { type: String, required: true, enum: ['G', 'P'] },
members: [{ type: Schema.Types.ObjectId, ref: 'Users' }]
}, { timestamps: true })
Message Model
const schema = new Mongoose.Schema({
conversationId: { type: Schema.Types.ObjectId, ref: 'Conversations' },
body: { type: String, trim: true },
author: { type: Schema.Types.ObjectId, ref: 'Users' }
}, { timestamps: true })
Done with the chatting part with this socket connection
io.on('sendMessage', async(action2) => {
action2.author = socket.decoded.id
action2.markRead = markReadSocket
const createMessage = await Message.create(action2)
const messages = await Message.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(createMessage._id) } },
{ "$lookup": {
"from": "users",
"let": { "author": "$author" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$author" ] }}},
{ "$project": { "firstName": 1, "lastName": 1, "avatar": 1 } }
],
"as": "author"
}},
{ "$unwind": "$author" },
{ "$project": {
"author": 1, "markRead": 1, "isDelivered": 1,
"body": 1, "conversationId": 1,
"isIncoming": { "$ne": [ "$author._id", mongoose.Types.ObjectId(socket.decoded.id) ] },
}}
])
io.emit(action2.conversationId, messages)
})
The above code is working fine for the one to one conversation and also for the group conversation.
Now what I want to achieve is to show delivered(two gray) and read(two blue) ticks just like the what app. Do I need to make separate collections for readBy
and deliveredTo
and need to save time
and userId
in it?
How can I do this with the nodejs
and socketio
? If someone has done this before then please post your code I will manage to understand it.
Any help would be appreciated!!!
Thanks in advance!!!
Client Side
Pseudocode
1. Register handler for 'newMessage' event, this will emit 'received' event
2. Function to emit 'markSeen' event, this will execute when the message is opened (chat window)
3. Register handler for 'delivered' event, this will display 'grey' ticks
4. Register handler for 'markedSeen' event, this will display 'blue' ticks
Functions
// Handler for 'newMessage' event
socket.on('newMessage', function(message) {
chatMessages[message.MESSAGE_ID] = message;
var options = {
messageID: message.MESSAGE_ID,
timetoken: moment().valueOf()
};
// Emit 'received' event
socket.emit('received', options);
});
// function to emit 'markSeen' event
function markSeen(message) {
var options = {
messageID: message.MESSAGE_ID
};
// Emit 'markSeen' event
socket.emit('markSeen', options);
}
// Handler for 'delivered' event
socket.on('delivered', function(message) {
chatMessages[MESSAGE_ID].delivered = true;
});
// Handler for 'markedSeen' event
socket.on('markedSeen', function(message) {
chatMessages[MESSAGE_ID].seen = true;
});
Server Side
Pseudocode
1. Register handler for 'received' event, this will emit 'delivered' event
2. Register handler for 'markSeen' event, this will emit 'markedSeen' event
Functions
// Handler for 'received' event
io.on('received', function(options) {
var options = {
timetoken: moment().valueOf(),
userID: options.message.SENDER_ID,
messageID: options.message.MESSAGE_ID
};
// Emit 'delivered' event
socket.emit('delivered', options);
});
// Handler for 'markSeen' event
io.on('markSeen', function(options) {
var options = {
timetoken: moment().valueOf(),
userID: options.message.SENDER_ID,
messageID: options.message.MESSAGE_ID
};
// Emit 'markedSeen' event
socket.emit('markedSeen', options);
});
After creating a new message entity and sending it to the recipient, recipient should emit a new delivered event as soon as this message is received. If this message is opened, send another event with read topic. Both events have to contain the message id.
In the server side, after receiving above events, check the sender of the message is that you got and pass proper events no notify sender about the current state of the message.
You'll need 2 distinct things you'll need to track. Once your server has received the message. in it's control when you're adding it to the database, this is when you're going to set the delivered tick to true. At this point you can emit a message back to the sending web-socket telling it that they're message has been delivered to the server, then the client sender can set their gray tick.
Similarly on the receiving side,once the receiver logs on, goes to the page where the message is/opens it. Basically as soon as it's visible for them, you can go through all the messages currently visible to them, if any do not have a "hasRead" checked to true, then you can send a call to to a controller that can set them to "hasRead=true". At this point your websocket can try update the sender(if they are online) that the message has been read. If they aren't online then you can just do the same thing i n reverse. E.G: If the sender comes online, pass along the "hasRead" attribute with each message and you can set the blue ticks accordingly"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With