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:
parent
296a692db9
commit
10d56dd393
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue