Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google App Engine Channel API

I am trying to learn GAE's channel API (using Java), but I cannot figure out where to start from.

I went through Channel API Overview (Java) but the code posted there wasn't complete for brevity purposes.

And since I m newbie, it would be very helpful if complete example code is available.

Thanks, Shrey

like image 462
Shrey Avatar asked Nov 25 '11 15:11

Shrey


1 Answers

The code in the Channel API Overview that you've linked to is pretty complete, it's just a bit all over the place. I will admit, once you understand it, I feel like it's much simpler than how they've made it seem, but I'm glad they erred on the side of providing too much information.

It's a bit hard to give a complete solution for this without extraneous information bleeding in, since some of how you'll use the Channel API is a bit dependent on your existing app's infrastructure. For that reason, I've tried to just elaborate a bit on what the AppEngine docs provide, so that hopefully you can understand better. And comments will allow you to ask specific questions, should you have any.

Firstly, a bit of vocabulary:

  • Channel Message: The message that you wish to have sent to clients (and likely the reason you're using the Channel API in the first place).
  • Channel Key: A string that is unique to the user and the scope in which the user is attempting to send a message.
  • Channel Token: A string that is unique to any client. 1 channel token per client per 2 hours.
  • Channel Service: The AppEngine server-side class that provides a means to create channels and send channel messages over them.

On the server, you will need to execute the following:

ChannelService channelService = ChannelServiceFactory.getChannelService();

// The channelKey can be generated in any way that you want, as long as it remains
// unique to the user.
String channelKey = "xyz";
String token = channelService.createChannel(channelKey);

Once you have the token, you just need some way to get it to the client-side code. The AppEngine doc that you've linked to does this by serving the HTML from the Java servlet and calling index.replaceAll("\\{\\{ token \\}\\}", token).

How this works is that they've done is put the literal string {{ token }} in their JavaScript code (as you'll see below), so wherever {{ token }} appears in the JavaScript code, it will be replaced by the actual token generated by the channelService.createChannel(...) call above. Note that you don't need to inject the token into the client-side code that you're serving in this manner, but it's a good place to start, since that's how they've done it (and documented it).


Now that you've sort of injected the token into the JavaScript, you need to get the code with the channel token to the client. (Note that, as stated above, you can also get just the token to the client, and create the channel that way). The code as they have it is:

<body>
  <script>
    channel = new goog.appengine.Channel('{{ token }}');
    socket = channel.open();
    socket.onopen = onOpened;
    socket.onmessage = onMessage;
    socket.onerror = onError;
    socket.onclose = onClose;
  </script>
</body>

They cut out the details on how to read this from a file on the server, but again, you can do that in any way you like. You could also just literally print the String using resp.getWriter().print(index) in your JavaServlet, where index is a String storing the HTML/JavaScript content listed above. Like I said initially, a lot is left up to you what suits your app's existing infrastructure best.

They intend for you to define your own JavaScript functions onOpened, onMessage, onError, and onClose to be called when channels are opened, receive a message, encounter an error, or are closed, respectively. You may wish to just create naive implementations to better understand what's going on:

function onOpened() {
    alert("Channel opened!");
}

function onMessage(msg) {
    alert(msg.data);
}

function onError(err) {
    alert(err);
}

function onClose() {
    alert("Channel closed!");
}

I still recommend separating them out into separate functions, so that you can more easily expand upon them to play around and figure things out. For more details on the JavaScript API, see the Channel API JavaScript Reference.


You'll need to establish a mechanism to get the data that you want to send from the client to the server. Once again, how you wish to do that does not matter. The AppEngine documentation suggests setting up an XMLHttpRequest to serve that purpose.

sendMessage = function(path, opt_param) {
  path += '?g=' + state.game_key;
  if (opt_param) {
    path += '&' + opt_param;
  }
  var xhr = new XMLHttpRequest();
  xhr.open('POST', path, true);
  xhr.send();
};

Here, opt_param is just a string of optional parameters in the format x=1&y=2&z=3. This is all infrastructure they've built for their sample Tic-Tac-Toe app, and is not crucial to the functionality of the Channel API; like I said, you can make this call however you want.

path is the path to your servlet (that you will need to set up in your web.xml file) that should handle message sending and receiving (see the following section).


After you have sent the message from the client to the server, you will need a servlet that can send an update to all clients with the same channel key.

ChannelService channelService = ChannelServiceFactory.getChannelService();

// This channelKey needs to be the same as the one in the first section above.
String channelKey = "xyz"

// This is what actually sends the message.
channelService.sendMessage(new ChannelMessage(channelKey, "Hello World!"));

The channelService.sendMessage(...) call above is what actually sends the message, so that it may be received by the onMessage function that you defined in the previous section.


I hope this answer is complete (and for that matter, correct) enough to help you get started. Most of what they've put in the docs (and my code here) can be copied and pasted, with only minor tweaks.

like image 67
Jon Newmuis Avatar answered Sep 20 '22 16:09

Jon Newmuis