我正在运行一个 ejabberd XMPP 服务器,要求所有 MultiUserChat 房间默认配置为私有。只有管理员用户才能创建多用户聊天组,只有管理员授予成员资格后,用户才能加入。
ejabberd.yml MUC 配置如下:
#Access Rules
access_rules:
local:
allow: local
c2s:
deny: blocked
allow: all
announce:
allow: admin
configure:
allow: admin
muc_create:
allow: admin
pubsub_createnode:
allow: admin
trusted_network:
allow: loopback
register:
allow:
user: admin
#Modules
modules:
mod_muc:
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
access_mam:
- allow
default_room_options:
allow_change_subj: false
allow_private_messages: false
allow_private_messages_from_visitors: nobody
allow_query_users: false
allow_subscription: false
allow_user_invites: false
allow_visitor_nickchange: false
allow_visitor_status: false
anonymous: false
captcha_protected: false
logging: false
mam: false
members_by_default: true
members_only: true
moderated: true
password_protected: false
persistent: true
presence_broadcast:
- moderator
- participant
- visitor
public: false
public_list: false
后端应用程序使用 Smack v4.4.6 客户端让管理员用户连接到服务器,并根据需要授予现有用户 MUC 频道的成员资格。管理员客户端授予房间成员资格的演示:
package com.example.xmpp;
import java.io.IOException;
import java.net.InetAddress;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
public class AdminClient {
public static void main(String[] args){
String username = "admin";
String password = "password";
String resource = "local";
String host = "example.com";
int port = 5222;
String domain = "example.com";
String channelName = "exampleChannel";
try {
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder()
.setHostAddress(InetAddress.getByName(host))
.setPort(port)
.setUsernameAndPassword(username, password)
.setXmppDomain(JidCreate.domainBareFrom(domain))
.setCompressionEnabled(true)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
;
XMPPTCPConnectionConfiguration conf = builder.build();
XMPPTCPConnection connection = new XMPPTCPConnection(conf);
connection.connect().login();
//MUC Manager
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
//Create MUC room object
EntityBareJid jid = JidCreate.entityBareFrom(channelName); //Room JID
Resourcepart resourcePart = Resourcepart.from(resource); //Admin user resource part
MultiUserChat muc = manager.getMultiUserChat(jid); //MUC object for room
//Add member to room
String memberUsername = "user1";
EntityBareJid memberJid = JidCreate.entityBareFrom(memberUsername);
muc.grantMembership(memberJid);
//Disconnect
connection.disconnect();
} catch(IOException | XMPPException | SmackException | InterruptedException e) {
e.printStackTrace();
}
}
}
客户端应用程序也将使用适用于 android 的 Smack 4.4.6 构建,并且需要监控用户已被授予会员资格的房间。 目前我无法知道服务器上有哪些多用户聊天室,也不知道是否已授予成员资格(无需主动尝试加入)。
现在,我已经实现了一个 REST API 服务来返回后端应用程序存储的频道名称列表,用户可以使用该列表,该列表在应用程序启动时调用。为了避免必须定期调用此 API,我还会在授予新成员资格时发送 firebase 通知,以便受影响的客户知道将其添加到他们的列表并加入。 但是,如果可能的话,我更愿意通过直接查询 XMPPServer 来实现。
Smack 客户端是否可以使用以下方法:
(严格来说1.如果2.可以自己完成就不需要了)
给定一个房间的 JID,可以知道成员列表。然而,给定一个用户 JID,不可能知道它所属的房间列表。 我在https://xmpp.org/extensions/xep-0045.html
中找不到任何这样的东西然后我开始研究 MucSub,它是 MUC 协议的实验性补充,在 ejabberd 的 mod_muc 中实现。并找到了一个棘手的解决方案......
如果您的用户(或管理员)添加为成员并添加为订阅者,则用户(或管理员)可以请求给定用户的订阅房间列表,您知道这等同于房间列表他是会员的地方。