Trouble creating xmpp muc room: Code 503 (service unavailable)

后端 未结 1 924
旧巷少年郎
旧巷少年郎 2020-12-08 12:22

My code to create a room:

XMPPRoomCoreDataStorage *rosterstorage = [[XMPPRoomCoreDataStorage alloc] init];
XMPPRoom *xmppRoom = [[XMPPRoom alloc] initWithRoo         


        
相关标签:
1条回答
  • 2020-12-08 13:01

    First, take look here XEP-0045: Multi-User Chat.
    As you can see, first you have to discover which capabilities your user (XMPPJID) has on the Jabber server.

    To do this, send next command to your Jabber Server:

    <iq from='user@jabber.server.com/resource' id='some_expression' to='jabber.server.com' type='get'>
        <query xmlns='http://jabber.org/protocol/disco#items'/>
    </iq>
    

    or writen in objective-c using XMPP library functions:

    NSError *error = nil;
    NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:@"<query xmlns='http://jabber.org/protocol/disco#items'/>" 
                                                            error:&error];
    XMPPIQ *iq = [XMPPIQ iqWithType:@"get" 
                                 to:[XMPPJID jidWithString:@"jabber.server.com"] 
                          elementID:[xmppStream generateUUID] child:query];
    [xmppStream sendElement:iq];
    

    Now listen response from server in XMPPStream delegate - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq and server response should be something like this:

    <iq from='jabber.server.com' id='some_expression' to='user@jabber.server.com/resource' type='result'>
        <query xmlns='http://jabber.org/protocol/disco#items'>
            <item jid='im.jabber.server.com' name='Instant Message Service'/>
            <item jid='conference.jabber.server.com' name='Chatroom Service'/>
        </query>
    </iq>
    

    or objective c:

    - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
    {
    
        if([iq isResultIQ])
        {
            if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"])
            {
                NSLog(@"Jabber Server's Capabilities: %@", [iq XMLString]);
            }
        }
    }
    

    Now for every item returned send IQ to your server for it's properties and figure out which one is type of conference, something like this:

    <iq from='user@jabber.server.com/resource' id='some_expression' to='conference.jabber.server.com' type='get'>
        <query xmlns='http://jabber.org/protocol/disco#info'/>
    </iq>
    

    or in objective c:

    - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
    {
    
        if([iq isResultIQ])
        {
            if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"])
            {
                NSXMLElement *query = [iq childElement];
                NSArray *items = [query children];
                for(NSXMLElement *item in items)
                {
                    NSError *error = nil;
                    NSXMLElement *sendQuery = [[NSXMLElement alloc] initWithXMLString:@"<query xmlns='http://jabber.org/protocol/disco#info'/>" 
                                                                                error:&error];
                    XMPPIQ *sendIQ = [XMPPIQ iqWithType:@"get" 
                                                     to:[XMPPJID jidWithString:[item attributeStringValueForName:@"jid"]] 
                                              elementID:[xmppStream generateUUID] 
                                                  child:sendQuery];
                    [xmppStream sendElement:sendIQ];
                }
            }
        }
    }
    

    Listen for responses from server:

    <iq from='conference.jabber.server.com' id='some_expression' to='user@jabber.server.com/resource' type='result'>
        <query xmlns='http://jabber.org/protocol/disco#info'>
            <identity category='conference' name='Server Group Chat Service' type='text'/>
            <feature var='http://jabber.org/protocol/muc'/>
        </query>
    </iq>
    

    and take group chat domain from identity with category:conference

    - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
    {
    
        if([iq isResultIQ])
        {
            if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"])
            {
                ...
            }
            else if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#info"])
            {
                NSXMLElement *query = [iq childElement];
                NSXMLElement *identity = [query elementForName:@"identity"];
                if([[identity attributeStringValueForName:@"category"] isEqualToString:@"conference"])
                {
                    groupChatDomain = [iq fromStr];
                }
            }
        }
    }
    

    Finally, when we got group chat domain we can create chat room something like this:

    XMPPJID *chatRoomJID = [XMPPJID jidWithUser:@"chat_room" 
                                         domain:groupChatDomain 
                                       resource:@"user"];
    XMPPRoomMemoryStorage *roomMemoryStorage = [[XMPPRoomMemoryStorage alloc] init];
    XMPPRoom *xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:roomMemoryStorage
                                                           jid:roomChatJID
                                                 dispatchQueue:dispatch_get_main_queue()];
    [xmppRoom activate:xmppStream];
    [xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
    [xmppRoom joinRoomUsingNickname:user history:nil];
    

    and add <XMPPRoomDelegate> protocol in your view controller and its delegates:

    - (void)xmppRoomDidCreate:(XMPPRoom *)sender
    - (void)xmppRoomDidDestroy:(XMPPRoom *)sender
    - (void)xmppRoom:(XMPPRoom *)sender didConfigure:(XMPPIQ *)iqResult
    - (void)xmppRoom:(XMPPRoom *)sender didNotConfigure:(XMPPIQ *)iqResult
    - (void)xmppRoomDidJoin:(XMPPRoom *)sender
    - (void)xmppRoomDidLeave:(XMPPRoom *)sender
    - (void)xmppRoom:(XMPPRoom *)sender occupantDidJoin:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
    - (void)xmppRoom:(XMPPRoom *)sender occupantDidLeave:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
    - (void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID
    

    Note: Before inviting other users to Chat Room, you have to send and confirm room configurations (other users can be invited but messages can not be sent).
    So you can do this after Room is created (delegate - (void)xmppRoomDidCreate:(XMPPRoom *)sender is called) or your user has joined (delegate - (void)xmppRoomDidJoin:(XMPPRoom *)sender is called) to Chat Room.

    To send and confirm room configuration do one of the following:

    - (void)xmppRoomDidCreate:(XMPPRoom *)sender
    {
        [sender configureRoomUsingOptions:nil];
    }
    

    or

    - (void)xmppRoomDidJoin:(XMPPRoom *)sender
    {    
        [sender configureRoomUsingOptions:nil];
    }
    

    Send nil to accept default options or you can send IQ with syntax as below to your server:

    <iq type='set' from='user@jabber.server.com/resource' id='some_expression' to='chat_room@conference.jabber.server.com'>
        <query xmlns='http://jabber.org/protocol/muc#owner'>
            <x xmlns='jabber:x:data' type='submit'>
                <field var='FORM_TYPE'>
                    <value>http://jabber.org/protocol/muc#roomconfig</value>
                </field>
                <field var='muc#roomconfig_roomname'>
                    <value>My Chat Room</value>
                </field>
                  .
                  .
                  .
            <x>
    </query>
    </iq>
    

    or objective c code:

    NSError *error = nil;
    NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:@"<query xmlns='http://jabber.org/protocol/muc#owner'/>" 
                                                            error:&error];
    NSXMLElement *x = [NSXMLElement elementWithName:@"x" 
                                              xmlns:@"jabber:x:data"];
    [x addAttributeWithName:@"type" stringValue:@"submit"];
    NSXMLElement *field1 = [NSXMLElement elementWithName:@"field"];
    [field1 addAttributeWithName:@"var" stringValue:@"FORM_TYPE"];
    NSXMLElement *value1 = [NSXMLElement elementWithName:@"value" 
                                             stringValue:@"http://jabber.org/protocol/muc#roomconfig"];
    [field1 addChild:value1];
    
    NSXMLElement *field2 = [NSXMLElement elementWithName:@"field"];
    [field2 addAttributeWithName:@"var" stringValue:@"muc#roomconfig_roomname"];
    NSXMLElement *value2 = [NSXMLElement elementWithName:@"value" 
                                             stringValue:@"My Chat Room"];
    [field2 addChild:value2];
    
    //Add other fields you need, just like field1 and field2
    
    [x addChild:field1];
    [x addChild:field2];
    
    [query addChild:x];
    
    NSXMLElement *roomOptions = [NSXMLElement elementWithName:@"iq"];
    [roomOptions addAttributeWithName:@"type" stringValue:@"set"];
    [roomOptions addAttributeWithName:@"id" stringValue:[xmppStream generateUUID];
    [roomOptions addAttributeWithName:@"to" stringValue:@"chat_room@conference.jabber.server.com"];
    
    [roomOptions addChild:query];
    
    [sender configureRoomUsingOptions:roomOptions];
    

    and list of all possible Configuration Form fields is here

    0 讨论(0)
提交回复
热议问题