User: use a stably-ordered queue for long-polling

If the AJAX request for LongPollServlet happens with enough of a delay,
there may be two stateful messages in the queue -- I have observed two
GAME_STATE_CHANGE messages enqueued simultaneously when the Card Czar
does not long-poll while the other players progress the game through
PLAYING to JUDGING.  The JS code overwrites the state as it iterates the
list, so the "last state wins".  But PriorityQueue<E> explicitly does
not guarantee any particular ordering among elements that compare
"equal", causing the client to think the game is PLAYING.
This commit is contained in:
Matt Mullins 2020-04-08 22:18:03 -07:00
parent 296a692db9
commit 10d56dd393
4 changed files with 8 additions and 23 deletions

View File

@ -269,8 +269,7 @@ public class ConnectedUsers {
* @param broadcastTo * @param broadcastTo
* List of users to broadcast the message to. * List of users to broadcast the message to.
* @param type * @param type
* Type of message to broadcast. This determines the order the messages are returned by * Type of message to broadcast.
* priority.
* @param masterData * @param masterData
* Message data to broadcast. * Message data to broadcast.
*/ */

View File

@ -463,8 +463,7 @@ public class Game {
* Broadcast a message to all players in this game. * Broadcast a message to all players in this game.
* *
* @param type * @param type
* Type of message to broadcast. This determines the order the messages are returned by * Type of message to broadcast.
* priority.
* @param masterData * @param masterData
* Message data to broadcast. * Message data to broadcast.
*/ */

View File

@ -33,7 +33,7 @@ import net.socialgamer.cah.Constants.ReturnableData;
* *
* @author Andy Janata (ajanata@socialgamer.net) * @author Andy Janata (ajanata@socialgamer.net)
*/ */
public class QueuedMessage implements Comparable<QueuedMessage> { public class QueuedMessage {
private final MessageType messageType; private final MessageType messageType;
private final Map<ReturnableData, Object> data; private final Map<ReturnableData, Object> data;
@ -42,8 +42,7 @@ public class QueuedMessage implements Comparable<QueuedMessage> {
* Create a new queued message. * Create a new queued message.
* *
* @param messageType * @param messageType
* Type of message to be queued. The type influences the priority in returning messages * Type of message to be queued.
* to the client.
* @param data * @param data
* The data of the message to be queued. * The data of the message to be queued.
*/ */
@ -66,15 +65,6 @@ public class QueuedMessage implements Comparable<QueuedMessage> {
return data; return data;
} }
/**
* This is not guaranteed to be consistent with .equals() since we do not care about the data for
* ordering.
*/
@Override
public int compareTo(final QueuedMessage qm) {
return this.messageType.getWeight() - qm.messageType.getWeight();
}
@Override @Override
public String toString() { public String toString() {
return messageType.toString() + "_" + data.toString(); return messageType.toString() + "_" + data.toString();
@ -92,9 +82,5 @@ public class QueuedMessage implements Comparable<QueuedMessage> {
MessageType(final int weight) { MessageType(final int weight) {
this.weight = weight; this.weight = weight;
} }
public int getWeight() {
return weight;
}
} }
} }

View File

@ -26,7 +26,8 @@ package net.socialgamer.cah.data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -54,7 +55,7 @@ public class User {
private final String idCode; private final String idCode;
private final PriorityBlockingQueue<QueuedMessage> queuedMessages; private final BlockingQueue<QueuedMessage> queuedMessages;
private final Object queuedMessageSynchronization = new Object(); private final Object queuedMessageSynchronization = new Object();
@ -121,7 +122,7 @@ public class User {
this.sessionId = sessionId; this.sessionId = sessionId;
this.clientLanguage = clientLanguage == null ? "" : clientLanguage; this.clientLanguage = clientLanguage == null ? "" : clientLanguage;
agent = UADetectorServiceFactory.getResourceModuleParser().parse(clientAgent); agent = UADetectorServiceFactory.getResourceModuleParser().parse(clientAgent);
queuedMessages = new PriorityBlockingQueue<QueuedMessage>(); queuedMessages = new LinkedBlockingQueue<QueuedMessage>();
} }
public interface Factory { public interface Factory {