Google App Engine Channel API

此生再无相见时 提交于 2019-12-02 21:13:33
Jon Newmuis

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.

I'm new to StackOverflow and am not sure if this question is still open, but if you are still looking for a complete Java example using Google's Channel API, both ServerSide(Java) and Client(Java) you can find a detailed description I've written up here: http://masl.cis.gvsu.edu/2012/01/31/java-client-for-appengine-channels/

It lays out everything from creating a Channel(Client & Server), Sending a message on a channel (client & server) as well as a simple framework Java clients can utilize to interact with Channels. I too had a hard time understanding Google's Documentation and making sense of it all. I hope this information is still relavent and helpful :-)

The Complete Source Code and Chat Example can be found on GitHub: https://github.com/gvsumasl/jacc

Here's some sample code, I hope this helps :-)


Java Client Side Channel Creation (Using ChannelAPI Framework: Jacc)

ChatListener chatListener = new ChatListener();
ChannelAPI channel = new ChannelAPI("http://localhost:8888", "key", chatListener);
channel.open();

Java Server Side Channel Creation:

public class ChatChannelServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {    
    String channelKey = req.getParameter("c");

    //Create a Channel using the 'channelKey' we received from the client
    ChannelService channelService = ChannelServiceFactory.getChannelService();
    String token = channelService.createChannel(channelKey);

    //Send the client the 'token' + the 'channelKey' this way the client can start using the new channel
    resp.setContentType("text/html");
    StringBuffer sb = new StringBuffer();
    sb.append("{ \"channelKey\":\"" + channelKey + "\",\"token\":\"" + token + "\"}");

    resp.getWriter().write(sb.toString());
  }
}

Java Client Message Sending (Using ChannelAPI Framework: Jacc)

/***
* Sends your message on the open channel
* @param message
*/
public void sendMessage(String message){
try {
        channel.send(message, "/chat");
    } catch (IOException e) {
        System.out.println("Problem Sending the Message");
    }
}

Java Server Side Message Sending:

public class ChatServlet extends HttpServlet {
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    String channelKey = req.getParameter("channelKey");
    String message = req.getParameter("message");

    //Send a message based on the 'channelKey' any channel with this key will receive the message
    ChannelService channelService = ChannelServiceFactory.getChannelService();
    channelService.sendMessage(new ChannelMessage(channelKey, message));
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!