1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-12-22 18:48:00 +01:00

[muc] Fix Presence interceptors

Presence interceptors where hooked into stanza sending listeners,
which are called *after* the stanza has been put on the wire, i.e., to
late for interceptors that any modifications, they may perform, to
take effect.

Fixes SMACK-925.

We now also dynamically add the MUC's main presence interceptor to the
connection.

Reported-by: Damian Minkov <damencho@jitsi.org>
This commit is contained in:
Florian Schmaus 2022-05-21 13:42:22 +02:00
parent aa441d743c
commit 60fee7b318

View file

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2003-2007 Jive Software. 2020-2021 Florian Schmaus * Copyright 2003-2007 Jive Software. 2020-2022 Florian Schmaus
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -59,7 +60,9 @@ import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder; import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.packet.MessageView; import org.jivesoftware.smack.packet.MessageView;
import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.PresenceBuilder;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.util.Consumer;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
@ -124,7 +127,7 @@ public class MultiUserChat {
private final Set<ParticipantStatusListener> participantStatusListeners = new CopyOnWriteArraySet<ParticipantStatusListener>(); private final Set<ParticipantStatusListener> participantStatusListeners = new CopyOnWriteArraySet<ParticipantStatusListener>();
private final Set<MessageListener> messageListeners = new CopyOnWriteArraySet<MessageListener>(); private final Set<MessageListener> messageListeners = new CopyOnWriteArraySet<MessageListener>();
private final Set<PresenceListener> presenceListeners = new CopyOnWriteArraySet<PresenceListener>(); private final Set<PresenceListener> presenceListeners = new CopyOnWriteArraySet<PresenceListener>();
private final Set<PresenceListener> presenceInterceptors = new CopyOnWriteArraySet<PresenceListener>(); private final Set<Consumer<PresenceBuilder>> presenceInterceptors = new CopyOnWriteArraySet<>();
/** /**
* This filter will match all stanzas send from the groupchat or from one if * This filter will match all stanzas send from the groupchat or from one if
@ -138,7 +141,16 @@ public class MultiUserChat {
*/ */
private final StanzaFilter fromRoomGroupchatFilter; private final StanzaFilter fromRoomGroupchatFilter;
private final StanzaListener presenceInterceptor; private final AtomicInteger presenceInterceptorCount = new AtomicInteger();
// We want to save the presence interceptor in a variable, using a lambda, (and not use a method reference) to be
// able to dynamically add and remove it from the connection.
@SuppressWarnings("UnnecessaryLambda")
private final Consumer<PresenceBuilder> presenceInterceptor = presenceBuilder -> {
for (Consumer<PresenceBuilder> interceptor : presenceInterceptors) {
interceptor.accept(presenceBuilder);
}
};
private final StanzaListener messageListener; private final StanzaListener messageListener;
private final StanzaListener presenceListener; private final StanzaListener presenceListener;
private final StanzaListener subjectListener; private final StanzaListener subjectListener;
@ -316,16 +328,6 @@ public class MultiUserChat {
fireInvitationRejectionListeners(message, rejection); fireInvitationRejectionListeners(message, rejection);
} }
}; };
presenceInterceptor = new StanzaListener() {
@Override
public void processStanza(Stanza packet) {
Presence presence = (Presence) packet;
for (PresenceListener interceptor : presenceInterceptors) {
interceptor.processPresence(presence);
}
}
};
} }
@ -379,8 +381,6 @@ public class MultiUserChat {
); );
// @formatter:on // @formatter:on
connection.addStanzaListener(declinesListener, new AndFilter(fromRoomFilter, DECLINE_FILTER)); connection.addStanzaListener(declinesListener, new AndFilter(fromRoomFilter, DECLINE_FILTER));
connection.addStanzaSendingListener(presenceInterceptor, new AndFilter(ToMatchesFilter.create(room),
StanzaTypeFilter.PRESENCE));
messageCollector = connection.createStanzaCollector(fromRoomGroupchatFilter); messageCollector = connection.createStanzaCollector(fromRoomGroupchatFilter);
// Wait for a presence packet back from the server. // Wait for a presence packet back from the server.
@ -1112,8 +1112,13 @@ public class MultiUserChat {
* *
* @param presenceInterceptor the new stanza interceptor that will intercept presence packets. * @param presenceInterceptor the new stanza interceptor that will intercept presence packets.
*/ */
public void addPresenceInterceptor(PresenceListener presenceInterceptor) { public void addPresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor) {
presenceInterceptors.add(presenceInterceptor); boolean added = presenceInterceptors.add(presenceInterceptor);
if (!added) return;
int currentCount = presenceInterceptorCount.incrementAndGet();
if (currentCount == 1) {
connection.addPresenceInterceptor(this.presenceInterceptor, ToMatchesFilter.create(room).asPredicate(Presence.class));
}
} }
/** /**
@ -1123,8 +1128,13 @@ public class MultiUserChat {
* *
* @param presenceInterceptor the stanza interceptor to remove. * @param presenceInterceptor the stanza interceptor to remove.
*/ */
public void removePresenceInterceptor(PresenceListener presenceInterceptor) { public void removePresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor) {
presenceInterceptors.remove(presenceInterceptor); boolean removed = presenceInterceptors.remove(presenceInterceptor);
if (!removed) return;
int currentCount = presenceInterceptorCount.decrementAndGet();
if (currentCount == 0) {
connection.removePresenceInterceptor(presenceInterceptor);
}
} }
/** /**
@ -2180,7 +2190,7 @@ public class MultiUserChat {
connection.removeStanzaListener(presenceListener); connection.removeStanzaListener(presenceListener);
connection.removeStanzaListener(subjectListener); connection.removeStanzaListener(subjectListener);
connection.removeStanzaListener(declinesListener); connection.removeStanzaListener(declinesListener);
connection.removeStanzaSendingListener(presenceInterceptor); connection.removePresenceInterceptor(presenceInterceptor);
if (messageCollector != null) { if (messageCollector != null) {
messageCollector.cancel(); messageCollector.cancel();
messageCollector = null; messageCollector = null;