如何使用 Smack 确定 MUC 是不是存在?

Posted

技术标签:

【中文标题】如何使用 Smack 确定 MUC 是不是存在?【英文标题】:How can I find out if a MUC exists using Smack?如何使用 Smack 确定 MUC 是否存在? 【发布时间】:2018-09-12 15:19:54 【问题描述】:

在多用户聊天 (XEP-0045-1.21) 中使用 Smack 4.3.0 我正在尝试确定是否已经创建了一个房间,但我不确定我正在做的是否是正确的方法。 我已经搜索过了,最相关的答案是 does MUC exist?。

从技术上讲:

    在 OpenFire 4.2.0 中,房间默认创建为公共和会员专用。 所有房间的名称都是由哈希字符串中的成员名称定义的 id,即XXXXXX029d8c36b62259d0eXXXXXXXX。这意味着用户 A 可以与 B、C 创建一个房间并像前一个一样获得groupId,但随后用户 B(在另一台设备中)可以尝试创建同一个房间(与用户 A、B、C),这将给他同样的groupId。 存在类似whatsapp 的架构层,因此用户可以留下Group Chat 并随时重新加入。

此刻我在做什么:

@WorkerThread
public boolean isGroupChatAlreadyCreated(@NonNull final String groupId)
        throws
        XmppStringprepException,
        XMPPException.XMPPErrorException,
        MultiUserChatException.NotAMucServiceException,
        SmackException.NotConnectedException,
        InterruptedException,
        SmackException.NoResponseException 
    List<HostedRoom> hostedRooms = manager.getHostedRooms(JidCreate.domainBareFrom(serviceDomain));
    for (HostedRoom hostedRoom : hostedRooms) 
        if (hostedRoom.getName().equalsIgnoreCase(groupId)) 
            return true;
        
    

    return false;

其中managerMultiUserChatManager managerserviceDomain 只是String

所以,问题:这是正确的方法吗?可以改进吗?

【问题讨论】:

【参考方案1】:

我相信更简单的方法是获取有关房间的一些信息,例如它的配置表格。如果不返回任何内容,则表示房间不存在:

public boolean isGroupChatAlreadyCreated(@NonNull final EntityBareJid groupId)
        throws
        XMPPErrorException,
        NotConnectedException,
        InterruptedException,
        NoResponseException 

    MultiUserChat multiUserChat = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(groupId);

    return multiUserChat.getConfigurationForm() != null;

更多信息在这里https://github.com/igniterealtime/Smack/blob/4.3/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java#L809

【讨论】:

【参考方案2】:

这基本上是正确的方法。

理想情况下,您只需使用MulitUserChatManager.getRoomInfo(EntityBareJid)。如果房间存在,该方法将返回RoomInfo,如果不存在则抛出。

您的原始方法也可以通过使用equals() 而不是equalsIgnoreCase() 将“groupId”的类型更改为EntityBareJid 来改进。并将您的 groupId 作为 MUC 地址的 Localpart。所以你的功能变成:

public boolean isGroupChatAlreadyCreated(@NonNull final EntityBareJid groupId)
        throws
        XmppStringprepException,
        XMPPErrorException,
        NotAMucServiceException,
        NotConnectedException,
        InterruptedException,
        NoResponseException 
    List<HostedRoom> hostedRooms = manager.getHostedRooms(JidCreate.domainBareFrom(serviceDomain));
    for (HostedRoom hostedRoom : hostedRooms) 
        if (hostedRoom.getJid().equals(groupId)) 
            return true;
        
    

    return false;

【讨论】:

我认为这不是一个最佳方案,因为如果您的服务器有 10 万个房间会发生什么?每次在客户端都会有一个 100K 的迭代循环,这可能会导致 ANR 不好。我有一个替代建议(在单独的答案中提供) 好点。我没有考虑过大型结果集。我可能会使用 XEP-0045 § 6.4。稍后会更新我的答案。 在我的情况下,我们不会有这么多房间,而且我用@WorkerThread 标记了那个方法。在最坏的情况下,我可以实现二进制搜索,但我很确定我们不需要它(在我们的例子中)。无论如何,我会实施最好的:D 对。如果您收到 ANR,那么无论如何您都做错了。尽管如此,如果 XEP-0045 提供了 O(1) 机制来查找房间,那么我们应该瞄准它,而不是 O(n) 方法。

以上是关于如何使用 Smack 确定 MUC 是不是存在?的主要内容,如果未能解决你的问题,请参考以下文章

smack 使用 4.1.0 rc1 在 muc 中接收消息

使用 smack 创建 MUC

Smack MUC 邀请

xmpp/smack : muc(MultiUserChat:多人聊天)房间配置表单

Android Smack MUC 400 错误请求发送群聊消息

如何知道谁在 MUC 房间收到了消息