Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Play!'s Comet support work?

I saw the Akka module's description says that Play has great Comet support, but I've never used Comet before and I can't find any mention of it in Play's documentation. How does it work in Play?


I spent a few hours over two days figuring this out so I wanted to share this info for other Play beginners.

like image 793
Brad Mace Avatar asked Dec 22 '10 17:12

Brad Mace


People also ask

How do I use Comet app?

In the COMET app, click on My next matches. It then brings up a list of all of your next matches and you can click on the relevant fixture to access further details. Firstly, from the list of your upcoming matches, pick the match you want to select the team line-up for.

How do you release a player on Comet?

To release a player from your club for a transfer, you need to click on the transfer involving the player through your National Transfers button shown on the previous page. Once on the players registration page, click the Edit button on the players Active registration with your club.

How do you add a player to Comet?

Within the competition page, to select your squad list or roster, click the Clubs tab. Next, on the row of your club click the + Player button. Once you have clicked the +Player button, simply click the checkbox next to the players that will be in your squad and then click Add Selected at the bottom.

How do you put a shirt number on Comet?

To change the players shirt number simple click on the number to display the number input screen. If you add an incorrect player just click the red minus (-) button. Once you have selected all the players for the starting lineup, tap the blue checkmark to save the line-up.


1 Answers

Play includes a sample Chat application which demonstrates how to use Comet. The example doesn't explain what's going on though, so here's what I've figured out.

Model

In order for others to find new updates you send, they'll need to be stored somewhere. Conceivably this could be in a cache or even in the controller itself, but the database is going to be the safest bet, so you'll want a model. They'll also need a way to determine which updates are new to them, which means you'll probably want a date field (see also: Last update timestamp with JPA). The Chat example uses a simple model:

@Entity
public class Message extends Model {     
    public String user;
    public Date date;
    public String text;

    public Message(String user, String text) {
        this.user = user;
        this.text = text;
        this.date = new Date();
    }       
}

Controller

The controller needs two methods to facilitate Comet. One where new data is posted, which doesn't do anything special:

public static void postMessage(String message) {
    new Message(session.get("nick"), message).save();
}

and one for retrieving updates:

public static void newMessages() {
    List<Message> messages = Message.find("date > ?", request.date).fetch();
    if (messages.isEmpty()) {
        suspend("1s");
    }
    renderJSON(messages);
}

The key bit here is suspend("1s") which is what holds the HTTP request open, checking for new data once per second.

View

The view has three responsibilities -- sending new data, fetching updates and then rendering those updates.

Sending, like the corresponding controller action, doesn't do anything special:

$('#send').click(function(e) {
    var message = $('#message').val();
    $('#message').val('');
    $.post('@{postMessage()}', {message: message}); 
});

Fetching updates is the magic bit:

// Retrieve new messages
var getMessages = function() {
    $.ajax({
        url: '@{newMessages()}',
        success: function(messages) {
            $(messages).each(function() {
                display(this);
            });
        },
        complete: function() {
            getMessages();
        },
        dataType: 'json'
    });
}
getMessages();

getMessages() is called once to get things started, and afterwards it calls itself recursively after each successful request. It GETs the newMessages() action which looks for new messages, and if there aren't any it holds the request open until it has something to report. When new messages are found, the JSON data is passed to a display function:

var display = function(message) {
    $('#thread').append(tmpl('message_tmpl', {message: message}));
}

The display function applies a JavaScript Micro-Template to the JSON data to render new messages. Use of micro templates isn't necessary, but it does work pretty well. They're included right in the template of the page that's going to use them:

<script type="text/html" id="message_tmpl">
    <div class="message <%= message.user == '${session.nick}' ? 'you' : '' %> <%= message.user == 'notice' ? 'notice' : '' %>">
        <h2><%= message.user %></h2>
        <p><%= message.text.replace('\n', '<br/>') %></p>
    </div>
</script>

The type="text/html" causes browsers, search engines and screen readers to ignore the whole script block. The result is much easier to read and maintain than using jQuery to build nodes or concatenating strings. Overall it's pretty simple once you know which bits are relevant.

like image 139
Brad Mace Avatar answered Oct 19 '22 12:10

Brad Mace