Search code examples
iosxmppejabberdxmppframeworkmultiuserchat

How to handle MUC chat messages- messages duplicating


I have implemented one to one chat using XMPP framework It has extensive support in one to one chat. Message archiving and fetching is way simple. But i see, very difficulty in handling a group chat message saving and displaying. The sorting and predicates are failing. duplicate messages are shown.

This is how i join a room before i fetch my already saved message)

XMPPRoomCoreDataStorage *coreDataRoomStorage=[self appDelegate].xmppRoomCoreDataStorage;
XMPPRoom *room=[[XMPPRoom alloc]initWithRoomStorage:coreDataRoomStorage jid:user.bareJid];
    [room activate:[self appDelegate].xmppStream];
    [room addDelegate:[self appDelegate] delegateQueue:dispatch_get_main_queue()];
    [room joinRoomUsingNickname:user.user_name history:nil];

I see, there are several redundant saving of messages. A single message is saved 3-4 times. What might i be doing wrong. Some body pls help! This is the code i do for fecthing messages in a room

- (NSFetchedResultsController *)fetchedResultsController{
if (fetchedResultsController == nil)
{
    NSManagedObjectContext *moc = [[self appDelegate] managedObjectContext_message];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject"
                                              inManagedObjectContext:moc];
    NSPredicate *predicate=[NSPredicate predicateWithFormat:@"bareJidStr=%@",_thisRoom.roomJID.bare];
    NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];
    NSArray *sortDescriptors = [NSArray arrayWithObjects:sd1, nil];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:entity];
    [fetchRequest setSortDescriptors:sortDescriptors];
    [fetchRequest setPredicate:predicate];
    [fetchRequest setFetchBatchSize:20];
    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                   managedObjectContext:moc
                                                                     sectionNameKeyPath:nil
                                                                              cacheName:nil];
    [fetchedResultsController setDelegate:self];

    NSError *error = nil;
    if (![fetchedResultsController performFetch:&error])
    {
        DDLogError(@"Error performing fetch: %@", error);
    }   
}
return fetchedResultsController;}

Solution

  • I think i found out an answer for the message duplication issue. The main issue was the message i am sending in the room was repeated on each room joining. What i did was when ever i sent a message i kept a deviceID as child element for the xmppmessage. On recieving on the message, i check the child element. If the devce id matches, its the same message i send earlier and its already in the core Data, So discard the message.

    - (void)sendMessageWithBody:(NSString *)messageBody
    {
    if ([messageBody length] == 0) return;
    
    NSXMLElement *body = [NSXMLElement elementWithName:@"body" stringValue:messageBody];
    XMPPMessage *message = [XMPPMessage message];
    [message addChild:body];
    
    
    //device id is used, so that the my message element will be unique 
    NSString *uuidString=[UIDevice currentDevice].identifierForVendor.UUIDString;
    NSXMLElement *myMsgLogic=[NSXMLElement elementWithName:@"myMsgLogic" stringValue:uuidString];
    [message addChild:myMsgLogic];
    
    [self sendMessage:message];
    }
    

    Then on message recieving in xmppstream. handle it In XMPPRoomCoreDataStorage, there is a method called

     - (void)handleIncomingMessage:(XMPPMessage *)message room:(XMPPRoom *)room
    

    on this do the message sorting logic. Not pasting the entire code:

    - (void)handleIncomingMessage:(XMPPMessage *)message room:(XMPPRoom *)room
    {
      XMPPLogTrace();
    
    XMPPJID *myRoomJID = room.myRoomJID;
    XMPPJID *messageJID = [message from];
    
    
    NSString *uuidString=[UIDevice currentDevice].identifierForVendor.UUIDString;
    
    NSString *messageLogic= [[message elementsForName:@"myMsgLogic"].firstObject stringValue];
    
    if ([uuidString isEqualToString:messageLogic]) {
        return;
    }
    
     //rest code is already there in the method
     }