rate limit muc pings / joins. never run two pings at same time

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/Account.java               |  1 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 30 
2 files changed, 27 insertions(+), 4 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Account.java 🔗

@@ -67,6 +67,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
     public List<Conversation> pendingConferenceJoins = new CopyOnWriteArrayList<>();
     public List<Conversation> pendingConferenceLeaves = new CopyOnWriteArrayList<>();
     public final Set<Conversation> inProgressConferenceJoins = new HashSet<>();
+    public final Set<Conversation> inProgressConferencePings = new HashSet<>();
     protected Jid jid;
     protected String password;
     protected int options = 0;

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -314,6 +314,12 @@ public class XmppConnectionService extends Service {
             }
 
             account.getRoster().clearPresences();
+            synchronized (account.inProgressConferenceJoins) {
+                account.inProgressConferenceJoins.clear();
+            }
+            synchronized (account.inProgressConferencePings) {
+                account.inProgressConferencePings.clear();
+            }
             mJingleConnectionManager.cancelInTransmission();
             mQuickConversationsService.considerSyncBackground(false);
             fetchRosterFromServer(account);
@@ -2464,21 +2470,37 @@ public class XmppConnectionService extends Service {
 	}
 
 	public void mucSelfPingAndRejoin(final Conversation conversation) {
+	    final Account account = conversation.getAccount();
+	    synchronized (account.inProgressConferenceJoins) {
+            if (account.inProgressConferenceJoins.contains(conversation)) {
+                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": canceling muc self ping because join is already under way");
+                return;
+            }
+        }
+        synchronized (account.inProgressConferencePings) {
+	        if (!account.inProgressConferencePings.add(conversation)) {
+	            Log.d(Config.LOGTAG, account.getJid().asBareJid()+": canceling muc self ping because ping is already under way");
+	            return;
+            }
+        }
 	    final Jid self = conversation.getMucOptions().getSelf().getFullJid();
 	    final IqPacket ping = new IqPacket(IqPacket.TYPE.GET);
 	    ping.setTo(self);
 	    ping.addChild("ping", Namespace.PING);
-	    sendIqPacket(conversation.getAccount(), ping, (account, response) -> {
+	    sendIqPacket(conversation.getAccount(), ping, (a, response) -> {
 	        if (response.getType() == IqPacket.TYPE.ERROR) {
 	            Element error = response.findChild("error");
 	            if (error == null || error.hasChild("service-unavailable") || error.hasChild("feature-not-implemented") || error.hasChild("item-not-found")) {
-	                Log.d(Config.LOGTAG,account.getJid().asBareJid()+": ping to "+self+" came back as ignorable error");
+	                Log.d(Config.LOGTAG,a.getJid().asBareJid()+": ping to "+self+" came back as ignorable error");
                 } else {
-	                Log.d(Config.LOGTAG,account.getJid().asBareJid()+": ping to "+self+" failed. attempting rejoin");
+	                Log.d(Config.LOGTAG,a.getJid().asBareJid()+": ping to "+self+" failed. attempting rejoin");
 	                joinMuc(conversation);
                 }
             } else if (response.getType() == IqPacket.TYPE.RESULT) {
-	            Log.d(Config.LOGTAG,account.getJid().asBareJid()+": ping to "+self+" came back fine");
+	            Log.d(Config.LOGTAG,a.getJid().asBareJid()+": ping to "+self+" came back fine");
+            }
+	        synchronized (account.inProgressConferencePings) {
+	            account.inProgressConferencePings.remove(conversation);
             }
         });
     }