0

I'm trying a simple to build a simple chat server. The main objective, for now, is to send the message from one client to another client, without saving into the DB, consuming less memory.
I'm using Meteor 1.4.1. So far I'm able to send and receive the messages with help of pub-sub data loading service.

// Collection declaration

if(Meteor.isServer){
  export const Messages = new Meteor.Collection("messages",{connection: null});
}

// Publish function

Meteor.publish('messages', function(rid) {
   if (!this.userId) {
    return this.ready();
  }

  let finderHandle = Messages.find({
    $or: [
      {username: Meteor.users.findOne({_id: this.userId}).username},
      {rid: Meteor.users.findOne({_id: this.userId}).username}
    ]
  })

  finderHandle.observeChanges({
    added: (_id, record) => {
      this.added( 'messages',_id, record )
    },
    changed: (_id, record) => {
      this.changed( 'messages', _id, record)
    },
    removed: (_id, record) => {
     this.removed( 'messages',_id, record)
    }
  });

  this.onStop(() => {
    console.log("disconnected")
    // finderHandle.close(); // Giving an Error: finderHandle.close() function not found.
  })
  this.ready();
});

The Problem here is, It is keeping all the messages in memory, It should only work as mediator When one client subscribe it should deliver the message and after that, it should be released from the memory. Presently, on subscribe I'm getting all the previous messages as well.

The thing which I'm missing here is onStop function, I'm not sure how this can be achieved. Please point me in the right direction.

Thanks in advance, Comments will also be appreciated.

UPDATE

from @CodeChimp, I've updated the collection query as below:

return Messages.find({
  rid: Meteor.users.findOne({_id: this.userId}).username,
  ls: {$exists: false}
},{
 sort: {ts: -1}
})

where rid is the recipient username, and ls is last seen if it doesn't exist, only those records will be sent to the recepient client only.

Ankit Balyan
  • 1,319
  • 19
  • 31

1 Answers1

1

You are trying to make the Meteor pub/sub work in a way it is not designed to work. When you create a subscription Meteor will, out of the box, create a mini-mongo db to hold the info of said subscription. Adds send from the publication will be added to all subscribed clients, modifications will be applied to all subscribed clients, and deletes are removed from all subscribed clients.

What I think you need to do is keep track of the date of the last message for each user. Then your custom publication could skip those that are older than that date. Once a message is sent through your publication, update the last message date for that user.

CodeChimp
  • 8,016
  • 5
  • 41
  • 79
  • So you basically mean is not to use mini mongo as well, In case how will I sync the messages from one user `sendMessage` `Method` call to another client. Do I need to create an array and store it for each user? – Ankit Balyan Sep 14 '16 at 18:49
  • I think plain nodejs with sockjs/socket.io would have done this perfectly. – Ankit Balyan Sep 14 '16 at 19:04
  • What I am saying is that you have hijacked the normal Meteor pub/sub process in your example, but in your example you are sending all messages to all clients. What you need to do if filter the messages based on the ones the client has already seen. There are several ways you could do it, but the easiest would be to track the post date on the message and then filter the messages to only those that were sent after the user last checked. Then you would be using the normal process of minimongo on the client, with custom publication on the server. – CodeChimp Sep 15 '16 at 14:11
  • I've updated in question, that I'm sending it only to the recipient user and unseen messages. – Ankit Balyan Sep 20 '16 at 12:59
  • Ok, I don't think you understand what I am trying to say. In your question, you say you want to filter the messages for a user to only those messages that are for that user and that the user has not already seen. In Meteor, when you publish data, that data is sent in it's entirety to the client, which then caches that in what is called 'minimongo'. So, you have two options to filter the results: 1) Filter what you send to the client, 2) filter on the client. Option 1 would be the most "secure", as it would only publish stuff the client should see. (cont.) – CodeChimp Sep 20 '16 at 13:40
  • One option for #1 would be to store something on the user's profile to aid in filtering, and the most simple thing you can store would be the date for the last message that was viewed by the client. With that bit of info you should be able to filter the resulting publication to only send things that the user can see AND hasn't already seen. Keep in mind the reactive nature of Meteor in that updating said "last seen date" for a user that is actively viewing messages will cause the publication to update the results cached to the user's client. It could make the messages appear to disappear. – CodeChimp Sep 20 '16 at 13:43
  • Is this `return Messages.find({ rid: Meteor.users.findOne({_id: this.userId}).username, ls: {$exists: false} },{ sort: {ts: -1} })` isn't the filtered data, Is it sending the whole object to the client? can you give an example for sending only filtered data please. – Ankit Balyan Sep 20 '16 at 14:18
  • I'm storing last seen timestamp in `ls` field. – Ankit Balyan Sep 20 '16 at 14:19