cardstories part 13: long polling client

The JavaScript client has been adapted to give immediate feedback when an event occurs using the long polling notification service. The game is refreshed as soon as an action is required from the player or when (s)he is invited to a new game.

user interaction

When trying to experiment the game using a single computer, the following interaction was used:

  • load the lobby for player loic
  • click on start new story
  • pick an image
  • write down sentence and click on next
  • type agnes and yvi in the invitation input box
  • open a new tab
  • load the lobby for player agnes
  • click on the sentence to participate in the game
  • show the tab to player agnes and let her chose a card
  • open a new tab
  • load the lobby for player yvi
  • show the tab to player yvi and let him chose a card
  • move to the tab of player loic and reload it
  • click on voting
  • move to the tab of player agnes and reload it
  • show the tab to player agnes and let her vote for a card
  • move to the tab of player yvi and reload it
  • show the tab to player yvi and let him vote for a card
  • move to the tab of player loic and reload it
  • click on complete and show the results to everyone

The introduction of long polling removes the need to reload because each tab is notified and redisplayed as soon as an action is required.

  • open a new tab
  • load the lobby for player agnes
  • open a new tab
  • load the lobby for player yvi
  • open a new tab
  • load the lobby for player loic
  • click on start new story
  • pick an image
  • write down sentence and click on next
  • move to the tab of player yvi
  • show the tab to player yvi and let him chose a card
  • move to the tab of player agnes
  • show the tab to player agnes and let her chose a card
  • move to the tab of player loic
  • click on voting
  • move to the tab of player yvi
  • show the tab to player yvi and let him vote for a card
  • move to the tab of player agnes
  • show the tab to player agnes and let her vot for a card
  • move to the tab of player loic
  • click on complete and show the results to everyone

notification

The client needs to be notified when

  • the lobby is displayed and a new game becomes available
  • a game is displayed and its state changes

There is no need to wait for notifications when displaying a game that is complete or when waiting for a user interaction such as picking a card or voting for a card. The following code shows that the notification queue is sollicited (long polling) when it is expected invitations, except if a participating user is to pick a card.

        invitation: function(player_id, game, root) {
            var poll = true;
            if(game.owner) {
                this.invitation_owner(player_id, game, root);
            } else {
                if(game.self !== null && game.self !== undefined) {
                    this.invitation_pick(player_id, game, root);
                    // do not disturb a player while (s)he is picking a card
                    poll = game.self[0] !== null;
                } else {
                    this.invitation_participate(player_id, game, root);
                }
            }
            if(poll) {
              this.poll({ 'modified': game.modified, 'game_id': game.id, 'player_id': player_id }, root);
            }
        },

long polling and notifications

The poll function implements the core of the notification feature. It uses a sequence number to ensure that no two long poll are in a race condition. When a poll request is sent, a global sequence number is incremented.

$(root).metadata().poll += 1; // make sure pending polls results will be ignored

When the answer from a poll request is received, it will be discarded if the sequence number has increased, i.e. if another poll request has been sent in the meantime.

if($(root).metadata().poll != poll) {
   $this.poll_ignore(request, answer, $(root).metadata().poll, poll);
} else {
...

Although the window of opportunity for such a race condition is small, it can be very disrupting when it happens.