Using the App Engine Channel API from a Java client

Posted by

For my game, one of the features is real-time chat. Now, App Engine comes with a "Channel API" which is basically a means of executing comet-like "long polling". The API is really simple, yet it has one serious drawback: the client-side is JavaScript.

That means, if I wanted to include a Channel API client in my game, I would need to create a "hidden" WebKit frame, with a bit of JavaScript and then a bunch of wrappers to actually get the messages into my Java game client. What a pain in the butt!

There's a number of bugs and feature requests against the App Engine API to support more than just JavaScript clients (for example, this one for a Java client). Tom Parker has written a Java client that talks to the Channel API on the dev server, but it doesn't work against the production API (as far as I can tell anyway -- the production API is completely different and implemented in terms of the Google Talk chat client). I found a post, "Using Google Appengine Channel API with a Python Client" by Schibum which works against the production API, but it's written in Python (and it doesn't work against the dev server -- I'd like something which worked against both, obviously).

So over the weekend, I've been working on my own Java client. This client works against both the development server and production App Engine servers. I've taken inspiration from both implementations I linked to above. The code is not entirely self-contained, it requires the Appache HttpClient library, an implementation of JSONObject and it uses SLF4j for logging. Of course, the code is quite simple and could be refactored to use whatever else you need. HttpClient is nice because it's included in the Android SDK.

The code is up on GitHub here:

https://github.com/codeka/appengine-channel-api-java

Usage is quite simple, I don't have a sample available at the moment, but basically:

URI appEngineURI = new URI("https://myapp.appspot.com/");
// URI appEngineURI = new URI("http://localhost:8080/");

// Get a Channel token from the server
String token = "<TOKEN HERE>";

ChannelClient cc = new ChannelClient(appEngineURI, token,
  new ChannelListener() {
    @Override
    public void onOpen() {
      System.out.println("* onOpen()");
    }

    @Override
    public void onMessage(String message) {
      System.out.println("> "+message);
    }

    @Override
    public void onError(int code,
         String description) {
      System.out.println("* onError("+code+
         ", \""+description+"\")");
    }

    @Override
    public void onClose() {
      System.out.println("* onClose()");
    }
  });

Now, after going through all of this trouble, I'm not entirely sure I'll continue using this code. Don't get me wrong, it works perfectly well (though it's not been load-tested or anything and obviously the error handling leaves quite a bit to be desired) but the main issue that I'm not entirely sure if there's a huge benefit here over simple polling. It might require less network traffic during quiet periods, but I would guess that during heavy periods, where there's a lot of chatting going on, the network savings won't be that great. And polling is a heck of a lot simpler.

But for now, it's there and I'll use it.

blog comments powered by Disqus