3

Consider the following scenario...

  1. Member connects to chat channel
  2. Member disconnects from chat channel
  3. Same member tries to reconnect to same chat channel

My problem is the following...Between steps 2 and 3, when the member tries to reconnect to the same channel, I get the error, "Member already exists". In order to solve the problem, I tried the following steps:

2.1 Call channel.leave()

2.2 channel.leave() successfully returns

2.3 Member tries to reconnect to same chat channel

  1. Member successfully connects to same chat channel

After successfully reconnecting, when the member tries to send a message, it appears twice. Not a working solution. Instead of using channel.leave(), also tried using channel.removeMember(identity) instead. After reconnecting back to the same channel, again, if the member send a message, it appears twice. Time for the final question, how could/should a member connect and disconnect gracefully from a chat channel so it could keep having a conversation just like if that member had never left the channel?

Thanks!

Edit:

Step 1

  const token = await axios.post('/twilio/chat', 
                { identity: identity , room: channelName }, 
                { headers: header })

Step 2.

   const client = await Chat.Client.create(token);

Step 3.

   const channel = await client.getChannelByUniqueName(channelName)

Step 4.

   const joinedChannel = await channel.join();

Step 5

   const messages = await channel.getMessages()

   messages.items.forEach((message) => {                                                          
    //Consume unread messages...                                                                       
   })    

   channel.setAllMessagesConsumed() 

Step 6. Listen to added messages

   channel.on('messageAdded', (message) => {    
   //When sending a message, this is where I get it duplicated after reconnecting to room
   })
    const previousChannel = await channel.leave()

Step 7. When leaving channel....

    const previousChannel = await channel.leave()    

After many trial and errors, I have finally come to the following conclusion. In order to "fix" the problem, I have to refresh the tab, and in order to recreate it, I follow the aforementioned steps without refreshing the tab... Memory leak?

Firefox 65.0.1

Chromium 72.0.3626.53

UPDATE:

Fixed. In step 7, after leaving the room, the client has to be gracefully shutdown...

 client.shutdown()            

Not a really friendly fix since it is not even documented as a required step for leaving a room. The most probable cause is indeed a memory leak somewhere. Hope this bug can be fixed sometime soon...

  • 1
    This is interesting. Can you share the code you're using rather than a description? It would make it much easier to work out what is going wrong here and how better to write it. Thanks! – philnash Mar 12 '19 at 05:51
  • Hey @philnash, added the code! Really appreciate your help – Sebastian Serrano Mar 12 '19 at 18:23

3 Answers3

3

Twilio developer evangelist here.

I believe that your duplicate messages are because you do not disconnect the messageAdded handler from the old channel object. When you leave the channel, try also removing the event listener.

channel.off('messageAdded', this.messageAdded);

As for the error between leaving and rejoining, you may want to listen for the channels memberLeft event before you can be completely sure that the member has left. Otherwise, handling the error is a reasonable way to deal with it.

philnash
  • 70,667
  • 10
  • 60
  • 88
  • I have same problem and even after turning off channel messageAdded, when I re-join channel it got duplicated the times getChannelByUniqueName is called. – Zohaib Imtiaz Apr 29 '20 at 11:15
  • 2
    Hi @f158087MuhammadZohaib, I'm not sure what you're asking here. Perhaps it would be better if you asked a new question and sent me a link to it so I can see your question with more context and your own code. – philnash Apr 29 '20 at 11:27
  • the `off` function is not defined for the channel I get a `channel.off is not a function` error when I try to detach the event listener for `messageAdded` event. I'm using v4.0.0 – Masroor Nov 20 '20 at 11:26
  • @Prime I am not sure why you wouldn't have access to the `off` method on `channel` unless in your case the `channel` has gone out of scope somehow and you are calling `off` on `undefined`. Perhaps you could ask a new question and share some of your code? – philnash Nov 22 '20 at 00:55
1

A private channel cannot be seen or joined directly. The gate pass to entering these channels are only via REST invites. The creator and the admin members of the private channel will be given access to a unique invite that they can pass around for people to join their group. These are visible only to participants and will decrease channel synchronization time at client start.

0

If a user has joined the channel already and attempts to join it again, it will throw an error that

Member already exists

To avoid this what I did was create the channel on my server side(and this is recommended by twilio itself), add both the participants to that channel(still on server side). Channel docs here

def create_channel_and_add_members(channel_name, identity, invited_identity, channel_type="private")
  channel = @client.chat.services(ENV["TWILIO_CHAT_SERVICE_SID"])
    .channels
    .create(unique_name: channel_name, type: channel_type)
  if channel && add_member(identity, channel.sid) && add_member(invited_identity, channel.sid)
    return channel.sid
  end
end

where identity is your logged in user's unique identifier, and invited_identity is the unique identifier of user with who you want to set up a one-to-one chat.
The add member function was, I used the member resource docs

def add_member(identity, channel_id)
  member = @client.chat.services(ENV["TWILIO_CHAT_SERVICE_SID"])
    .channels(channel_id)
    .members
    .create(identity: identity)
  if member
    true
  else
    false
  end
end

The create_channel_and_add_members returned a channel SID to the front-end, which I used to fetch the channel itself on the front-end side, using this code

chatClient.getChannelBySid(sid_of_channel).then((channel)=>{
  console.log(channel);
  // you can now set event listeners on this channel object directly.
  // no need to call join() on it since, our server side code has already added the members(which means they've joined it)
  //to receive the messages of this channel, set an event listener on the channel
  channel.on('messageAdded', function(message) {
    console.log("Messagge is received", message);
  });
})

Next time you want to get the user's channels. You can just fetch the Channels which the user has subscribed to i.e has joined,

chatClient.getSubscribedChannels().then(function(paginator) {
  console.log("Your subscribed channels are ", paginator.items);
  // each item is a channel, on which you can set event Listeners and do other stuff related to the channel
});

Do not forget to include the Twilio sdk in your project on front-end and back-end sides. I hope this helps someone in the future.

Masroor
  • 1,484
  • 3
  • 14
  • 23