Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Smack中的聊天标记(XEP-0333)_Android_Xmpp_Smack - Fatal编程技术网

Android Smack中的聊天标记(XEP-0333)

Android Smack中的聊天标记(XEP-0333),android,xmpp,smack,Android,Xmpp,Smack,关于这一点有很多建议,但当时没有对XMPP扩展(XEP-0333)的支持。此外,在discussion.igniterealtime.org中还有一个问题,但没有答案,主要是询问他们何时支持xep-0333扩展 此时,它由Smack in支持,您可以找到代码 我一直在寻找示例、指南或如何使用此扩展,但迄今为止运气不佳。 我也试着挖掘代码,希望找到一些关于如何使用的javadoc,但也没有成功 这个问题的目的是获取一段代码,说明我如何在smack 4.x.x中使用它更新:等待PR代码审查以更新以下

关于这一点有很多建议,但当时没有对XMPP扩展(XEP-0333)的支持。此外,在discussion.igniterealtime.org中还有一个问题,但没有答案,主要是询问他们何时支持xep-0333扩展

此时,它由Smack in支持,您可以找到代码

我一直在寻找示例、指南或如何使用此扩展,但迄今为止运气不佳。 我也试着挖掘代码,希望找到一些关于如何使用的javadoc,但也没有成功


这个问题的目的是获取一段代码,说明我如何在smack 4.x.x中使用它更新:等待PR代码审查以更新以下代码。

回答我自己的问题:
正如我所说,Smack库对XEP-0333有实验性的支持,在尝试将其与4.2和4.3.0-rc1版本一起使用后,我发现XEP-0333需要改进,以使其工作方式类似于
IncomingChatMessageListener
ChatStateListener

此外,我无法仅使用
OutgoingChatMessageListener
IncomingChatMessageListener
接口使其工作,因为它们在内部检查
是否有
标记(因为xmpp协议规则),但该规则不适用于XEP-0333:

当接收者发送聊天标记时,它应该确保消息节只包含聊天标记子元素和可选的(适当时)线程子元素。当然,在路由或传递接收消息时,中间实体可能会向消息添加其他扩展元素,例如延迟传递(XEP-0203)中指定的元素

因此,我所做的是从
ChatManager
(版本2)和
ChatStateManager
改进
ChatMarkersManager
的体系结构和行为

下面的代码是经过改进的代码(我仍然需要Smack library人员的反馈),但它正在工作:

public final class ChatMarkersManager extends Manager {

private static final Map<XMPPConnection, ChatMarkersManager> INSTANCES = new WeakHashMap<>();

// @FORMATTER:OFF
private static final StanzaFilter FILTER = new NotFilter(new StanzaExtensionFilter(ChatMarkersElements.NAMESPACE));
private static final StanzaFilter CHAT_STATE_FILTER = new NotFilter(new StanzaExtensionFilter(ChatStateManager.NAMESPACE));

private static final StanzaFilter MESSAGE_FILTER = new OrFilter(
        MessageTypeFilter.NORMAL_OR_CHAT,
        MessageTypeFilter.GROUPCHAT
);

private static final StanzaFilter INCOMING_MESSAGE_FILTER = new AndFilter(
        MESSAGE_FILTER,
        new StanzaExtensionFilter(ChatMarkersElements.NAMESPACE)
);
// @FORMATTER:ON

private final Set<IncomingChatMarkerMessageListener> incomingListeners = new CopyOnWriteArraySet<>();

private final AsyncButOrdered<Chat> asyncButOrdered = new AsyncButOrdered<>();

private ChatMarkersManager(XMPPConnection connection) {
    super(connection);
    connection.addStanzaInterceptor(new StanzaListener() {
        @Override
        public void processStanza(Stanza packet)
                throws
                SmackException.NotConnectedException,
                InterruptedException,
                SmackException.NotLoggedInException {
            Message message = (Message) packet;
            if (shouldDiscardMessage(message)) {
                return;
            }

            if (message.getBodies().isEmpty()) {
                return;
            }

            // if message already has a chatMarkerExtension, then do nothing,
            if (!FILTER.accept(message)) {
                return;
            }

            // otherwise add a markable extension,
            message.addExtension(new ChatMarkersElements.MarkableExtension());
        }
    }, MESSAGE_FILTER);

    connection.addSyncStanzaListener(new StanzaListener() {
        @Override
        public void processStanza(Stanza packet)
                throws
                SmackException.NotConnectedException,
                InterruptedException,
                SmackException.NotLoggedInException {
            final Message message = (Message) packet;
            if (shouldDiscardMessage(message)) {
                return;
            }

            EntityFullJid fullFrom = message.getFrom().asEntityFullJidIfPossible();
            EntityBareJid bareFrom = fullFrom.asEntityBareJid();
            final Chat chat = ChatManager.getInstanceFor(connection()).chatWith(bareFrom);

            List<IncomingChatMarkerMessageListener> listeners;
            synchronized (incomingListeners) {
                listeners = new ArrayList<>(incomingListeners.size());
                listeners.addAll(incomingListeners);
            }

            final List<IncomingChatMarkerMessageListener> finalListeners = listeners;
            asyncButOrdered.performAsyncButOrdered(chat, new Runnable() {
                @Override
                public void run() {
                    for (IncomingChatMarkerMessageListener listener : finalListeners) {
                        if (ChatMarkersElements.MarkableExtension.from(message) != null) {
                            listener.newMarkableMessage(message);
                        } else if (ChatMarkersElements.ReceivedExtension.from(message) != null) {
                            listener.newReceivedMessage(message);
                        } else if (ChatMarkersElements.DisplayedExtension.from(message) != null) {
                            listener.newDisplayedMessage(message);
                        } else if (ChatMarkersElements.AcknowledgedExtension.from(message) != null) {
                            listener.newAcknowledgedMessage(message);
                        }
                    }
                }
            });

        }
    }, INCOMING_MESSAGE_FILTER);

    ServiceDiscoveryManager.getInstanceFor(connection).addFeature(ChatMarkersElements.NAMESPACE);
}

/**
 * Get the singleton instance of ChatMarkersManager.
 *
 * @param connection
 * @return the instance of ChatMarkersManager
 */
public static synchronized ChatMarkersManager getInstanceFor(XMPPConnection connection) {
    ChatMarkersManager chatMarkersManager = INSTANCES.get(connection);

    if (chatMarkersManager == null) {
        chatMarkersManager = new ChatMarkersManager(connection);
        INSTANCES.put(connection, chatMarkersManager);
    }

    return chatMarkersManager;
}

/**
 * Register a IncomingChatMarkerMessageListener. That listener will be informed about new
 * incoming markable messages.
 *
 * @param listener IncomingChatMarkerMessageListener
 * @return true, if the listener was not registered before
 */
public boolean addIncomingChatMarkerMessageListener(IncomingChatMarkerMessageListener listener) {
    synchronized (incomingListeners) {
        return incomingListeners.add(listener);
    }
}

/**
 * Unregister a IncomingChatMarkerMessageListener.
 *
 * @param listener IncomingChatMarkerMessageListener
 * @return true, if the listener was registered before
 */
public boolean removeIncomingChatMarkerMessageListener(IncomingChatMarkerMessageListener listener) {
    synchronized (incomingListeners) {
        return incomingListeners.remove(listener);
    }
}

public void markMessageAsReceived(String id, Jid to, Jid from, String thread)
        throws
        SmackException.NotConnectedException,
        InterruptedException {
    Message message = createMessage(id, to, from, thread);
    message.addExtension(new ChatMarkersElements.ReceivedExtension(id));
    sendChatMarkerMessage(message);
}

public void markMessageAsDisplayed(String id, Jid to, Jid from, String thread)
        throws
        SmackException.NotConnectedException,
        InterruptedException {
    Message message = createMessage(id, to, from, thread);
    message.addExtension(new ChatMarkersElements.DisplayedExtension(id));
    sendChatMarkerMessage(message);
}

public void markMessageAsAcknowledged(String id, Jid to, Jid from, String thread)
        throws
        SmackException.NotConnectedException,
        InterruptedException {
    Message message = createMessage(id, to, from, thread);
    message.addExtension(new ChatMarkersElements.AcknowledgedExtension(id));
    sendChatMarkerMessage(message);
}

private Message createMessage(String id, Jid to, Jid from, String thread) {
    Message message = new Message();
    message.setStanzaId(id);
    message.setTo(to);
    message.setFrom(from);
    message.setThread(thread);
    return message;
}

private void sendChatMarkerMessage(Message message) throws SmackException.NotConnectedException, InterruptedException {
    connection().sendStanza(message);
}

/**
 * From XEP-0333, Protocol Format: The Chat Marker MUST have an 'id' which is the 'id' of the
 * message being marked.
 *
 * @param message to be analyzed.
 * @return true if the message contains a stanza Id.
 * @see <a href="http://xmpp.org/extensions/xep-0333.html">XEP-0333: Chat Markers</a>
 */
private boolean shouldDiscardMessage(Message message) {
    if (StringUtils.isNullOrEmpty(message.getStanzaId())) {
        return true;
    }

    if (!CHAT_STATE_FILTER.accept(message)) {
        ExtensionElement extension = message.getExtension(ChatStateManager.NAMESPACE);
        String chatStateElementName = extension.getElementName();

        ChatState state;
        try {
            state = ChatState.valueOf(chatStateElementName);
            return !(state == ChatState.active);
        } catch (Exception ex) {
            return true;
        }
    }

    return false;
}

/**
 * Returns true if Chat Markers is supported by the server.
 *
 * @return true if Chat Markers is supported by the server.
 * @throws SmackException.NotConnectedException
 * @throws XMPPException.XMPPErrorException
 * @throws SmackException.NoResponseException
 * @throws InterruptedException
 */
public boolean isSupportedByServer()
        throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
    return ServiceDiscoveryManager.getInstanceFor(connection())
            .serverSupportsFeature(ChatMarkersElements.NAMESPACE);
}
}

目前我没有使用
Chat
对象,因此我没有通过接口传递它,但它可以很容易地添加。实际上,我希望能够处理
聊天
和MultiChat

如中所示,可与XEP-0085一起使用


就像我在它工作之前说的,遵循协议规则,但我有一些问题无法回答,我想从Smack library的家伙那里得到一些反馈:D

更新:等待PR代码审查以更新以下代码。

回答我自己的问题:
正如我所说,Smack库对XEP-0333有实验性的支持,在尝试将其与4.2和4.3.0-rc1版本一起使用后,我发现XEP-0333需要改进,以使其工作方式类似于
IncomingChatMessageListener
ChatStateListener

此外,我无法仅使用
OutgoingChatMessageListener
IncomingChatMessageListener
接口使其工作,因为它们在内部检查
是否有
标记(因为xmpp协议规则),但该规则不适用于XEP-0333:

当接收者发送聊天标记时,它应该确保消息节只包含聊天标记子元素和可选的(适当时)线程子元素。当然,在路由或传递接收消息时,中间实体可能会向消息添加其他扩展元素,例如延迟传递(XEP-0203)中指定的元素

因此,我所做的是从
ChatManager
(版本2)和
ChatStateManager
改进
ChatMarkersManager
的体系结构和行为

下面的代码是经过改进的代码(我仍然需要Smack library人员的反馈),但它正在工作:

public final class ChatMarkersManager extends Manager {

private static final Map<XMPPConnection, ChatMarkersManager> INSTANCES = new WeakHashMap<>();

// @FORMATTER:OFF
private static final StanzaFilter FILTER = new NotFilter(new StanzaExtensionFilter(ChatMarkersElements.NAMESPACE));
private static final StanzaFilter CHAT_STATE_FILTER = new NotFilter(new StanzaExtensionFilter(ChatStateManager.NAMESPACE));

private static final StanzaFilter MESSAGE_FILTER = new OrFilter(
        MessageTypeFilter.NORMAL_OR_CHAT,
        MessageTypeFilter.GROUPCHAT
);

private static final StanzaFilter INCOMING_MESSAGE_FILTER = new AndFilter(
        MESSAGE_FILTER,
        new StanzaExtensionFilter(ChatMarkersElements.NAMESPACE)
);
// @FORMATTER:ON

private final Set<IncomingChatMarkerMessageListener> incomingListeners = new CopyOnWriteArraySet<>();

private final AsyncButOrdered<Chat> asyncButOrdered = new AsyncButOrdered<>();

private ChatMarkersManager(XMPPConnection connection) {
    super(connection);
    connection.addStanzaInterceptor(new StanzaListener() {
        @Override
        public void processStanza(Stanza packet)
                throws
                SmackException.NotConnectedException,
                InterruptedException,
                SmackException.NotLoggedInException {
            Message message = (Message) packet;
            if (shouldDiscardMessage(message)) {
                return;
            }

            if (message.getBodies().isEmpty()) {
                return;
            }

            // if message already has a chatMarkerExtension, then do nothing,
            if (!FILTER.accept(message)) {
                return;
            }

            // otherwise add a markable extension,
            message.addExtension(new ChatMarkersElements.MarkableExtension());
        }
    }, MESSAGE_FILTER);

    connection.addSyncStanzaListener(new StanzaListener() {
        @Override
        public void processStanza(Stanza packet)
                throws
                SmackException.NotConnectedException,
                InterruptedException,
                SmackException.NotLoggedInException {
            final Message message = (Message) packet;
            if (shouldDiscardMessage(message)) {
                return;
            }

            EntityFullJid fullFrom = message.getFrom().asEntityFullJidIfPossible();
            EntityBareJid bareFrom = fullFrom.asEntityBareJid();
            final Chat chat = ChatManager.getInstanceFor(connection()).chatWith(bareFrom);

            List<IncomingChatMarkerMessageListener> listeners;
            synchronized (incomingListeners) {
                listeners = new ArrayList<>(incomingListeners.size());
                listeners.addAll(incomingListeners);
            }

            final List<IncomingChatMarkerMessageListener> finalListeners = listeners;
            asyncButOrdered.performAsyncButOrdered(chat, new Runnable() {
                @Override
                public void run() {
                    for (IncomingChatMarkerMessageListener listener : finalListeners) {
                        if (ChatMarkersElements.MarkableExtension.from(message) != null) {
                            listener.newMarkableMessage(message);
                        } else if (ChatMarkersElements.ReceivedExtension.from(message) != null) {
                            listener.newReceivedMessage(message);
                        } else if (ChatMarkersElements.DisplayedExtension.from(message) != null) {
                            listener.newDisplayedMessage(message);
                        } else if (ChatMarkersElements.AcknowledgedExtension.from(message) != null) {
                            listener.newAcknowledgedMessage(message);
                        }
                    }
                }
            });

        }
    }, INCOMING_MESSAGE_FILTER);

    ServiceDiscoveryManager.getInstanceFor(connection).addFeature(ChatMarkersElements.NAMESPACE);
}

/**
 * Get the singleton instance of ChatMarkersManager.
 *
 * @param connection
 * @return the instance of ChatMarkersManager
 */
public static synchronized ChatMarkersManager getInstanceFor(XMPPConnection connection) {
    ChatMarkersManager chatMarkersManager = INSTANCES.get(connection);

    if (chatMarkersManager == null) {
        chatMarkersManager = new ChatMarkersManager(connection);
        INSTANCES.put(connection, chatMarkersManager);
    }

    return chatMarkersManager;
}

/**
 * Register a IncomingChatMarkerMessageListener. That listener will be informed about new
 * incoming markable messages.
 *
 * @param listener IncomingChatMarkerMessageListener
 * @return true, if the listener was not registered before
 */
public boolean addIncomingChatMarkerMessageListener(IncomingChatMarkerMessageListener listener) {
    synchronized (incomingListeners) {
        return incomingListeners.add(listener);
    }
}

/**
 * Unregister a IncomingChatMarkerMessageListener.
 *
 * @param listener IncomingChatMarkerMessageListener
 * @return true, if the listener was registered before
 */
public boolean removeIncomingChatMarkerMessageListener(IncomingChatMarkerMessageListener listener) {
    synchronized (incomingListeners) {
        return incomingListeners.remove(listener);
    }
}

public void markMessageAsReceived(String id, Jid to, Jid from, String thread)
        throws
        SmackException.NotConnectedException,
        InterruptedException {
    Message message = createMessage(id, to, from, thread);
    message.addExtension(new ChatMarkersElements.ReceivedExtension(id));
    sendChatMarkerMessage(message);
}

public void markMessageAsDisplayed(String id, Jid to, Jid from, String thread)
        throws
        SmackException.NotConnectedException,
        InterruptedException {
    Message message = createMessage(id, to, from, thread);
    message.addExtension(new ChatMarkersElements.DisplayedExtension(id));
    sendChatMarkerMessage(message);
}

public void markMessageAsAcknowledged(String id, Jid to, Jid from, String thread)
        throws
        SmackException.NotConnectedException,
        InterruptedException {
    Message message = createMessage(id, to, from, thread);
    message.addExtension(new ChatMarkersElements.AcknowledgedExtension(id));
    sendChatMarkerMessage(message);
}

private Message createMessage(String id, Jid to, Jid from, String thread) {
    Message message = new Message();
    message.setStanzaId(id);
    message.setTo(to);
    message.setFrom(from);
    message.setThread(thread);
    return message;
}

private void sendChatMarkerMessage(Message message) throws SmackException.NotConnectedException, InterruptedException {
    connection().sendStanza(message);
}

/**
 * From XEP-0333, Protocol Format: The Chat Marker MUST have an 'id' which is the 'id' of the
 * message being marked.
 *
 * @param message to be analyzed.
 * @return true if the message contains a stanza Id.
 * @see <a href="http://xmpp.org/extensions/xep-0333.html">XEP-0333: Chat Markers</a>
 */
private boolean shouldDiscardMessage(Message message) {
    if (StringUtils.isNullOrEmpty(message.getStanzaId())) {
        return true;
    }

    if (!CHAT_STATE_FILTER.accept(message)) {
        ExtensionElement extension = message.getExtension(ChatStateManager.NAMESPACE);
        String chatStateElementName = extension.getElementName();

        ChatState state;
        try {
            state = ChatState.valueOf(chatStateElementName);
            return !(state == ChatState.active);
        } catch (Exception ex) {
            return true;
        }
    }

    return false;
}

/**
 * Returns true if Chat Markers is supported by the server.
 *
 * @return true if Chat Markers is supported by the server.
 * @throws SmackException.NotConnectedException
 * @throws XMPPException.XMPPErrorException
 * @throws SmackException.NoResponseException
 * @throws InterruptedException
 */
public boolean isSupportedByServer()
        throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
    return ServiceDiscoveryManager.getInstanceFor(connection())
            .serverSupportsFeature(ChatMarkersElements.NAMESPACE);
}
}

目前我没有使用
Chat
对象,因此我没有通过接口传递它,但它可以很容易地添加。实际上,我希望能够处理
聊天
和MultiChat

如中所示,可与XEP-0085一起使用


就像我在它工作之前说的,遵循协议规则,但我有一些问题无法回答,我想从Smack library的家伙那里得到一些反馈:D

嗨,你在使用这个聊天室管理员吗。实际上,我对使用这个实现很感兴趣,想知道您对此的反馈。为你工作顺利吗?嗨@umerk44!是的,该应用程序使用的版本与此非常相似,但有一些改进。您可以在GitHub中签出PR。您好,您正在使用此ChatMarkersManager。实际上,我对使用这个实现很感兴趣,想知道您对此的反馈。为你工作顺利吗?嗨@umerk44!是的,该应用程序使用的版本与此非常相似,但有一些改进。您可以在GitHub中签出PR。