Please note that the contents of this offline web site may be out of date. To access the most recent documentation visit the online version .
Note that links that point to online resources are green in color and will open in a new window.
We would love it if you could give us feedback about this material by filling this form (You have to be online to fill it)



Channel Python API Overview

Python | Java | PHP | Go
  1. Overview
  2. Elements of the Channel API
  3. Life of a typical channel message
  4. Example Tic Tac Toe application
  5. Tracking client connections and disconnections
  6. Tokens and security
  7. Caveats

Overview

The Channel API creates a persistent connection between your application and Google servers, allowing your application to send messages to JavaScript clients in real time without the use of polling. This is useful for applications designed to update users about new information immediately. Some example use-cases include collaborative applications, multi-player games, or chat rooms. In general, using the Channel API is a better choice than polling in situations where updates can't be predicted or scripted, such as when relaying information between human users or from events not generated systematically.

Elements of the Channel API

Javascript client

The user interacts with a JavaScript client built into a webpage. The JavaScript client is primarily responsible for three things:

  • Connecting to the channel once it receives the channel’s unique token from the server
  • Listening on the channel for updates regarding other clients and making appropriate use of the data (e.g. updating the interface, etc.)
  • Sending update messages to the server so they may be passed on to remote clients

Refer to the JavaScript Reference page for details on building your client.

The server

The server is responsible for:

  • Creating a unique channel for individual JavaScript clients
  • Creating and sending a unique token to each JavaScript client so they may connect and listen to their channel
  • Receiving update messages from clients via HTTP requests
  • Sending update messages to clients via their channels
  • Optionally, managing client connection state.

The client ID

The Client ID is responsible for identifying individual JavaScript clients on the server. The server knows what channel on which to send a particular message because of the Client ID.

A Client ID can be anything that makes sense in the design of your application. For example, you can use something like cookie or login information, randomized numerical ID, or a user-selected name.

You may also create Client IDs in whatever way makes sense in your application. For example, you may choose to create the Client ID on the client and pass it to the server in an explicit request for a token, or create it on the server and inject it into the page’s HTML when the server replies to the browser’s request for the page.

Tokens

Tokens are responsible for allowing the JavaScript Client to connect and listen to the channel created for it. The server creates one token for each client using information such as the client’s Client ID and expiration time.

Tokens expire after two hours and should also be treated as secret. See the Tokens and Security section for more details.

The channel

A channel is a one-way communication path through which the server sends updates to a specific JavaScript client identified by its Client ID. The server receives updates from clients via HTTP requests, then sends the messages to relevant clients via their channels.

The message

Messages are sent via HTTP requests from one client to the server. Once received, the server passes the message to the designated client via the correct channel identified by the Client ID. Messages are limited to 32K.

Socket

The JavaScript client opens a socket using the token provided by the server. It uses the socket to listen for updates on the channel.

Presence

The server can register to receive a notification when a client connects to or disconnects from a channel.

Life of a typical channel message

These two diagrams illustrate the life of a typical example message sent via Channel API between two different clients using one possible implementation of Channel API.

This diagram shows the creation of a channel on the server. In this example, it shows the JavaScript client explicitly requests a token and sends its Client ID to the server. In contrast, you could choose to design your application to inject the token into the client before the page loads in the browser, or some other implementation if preferred.

Next, the server uses Client A’s Client ID to create a channel and then sends the token for that channel back to Client A. Client A uses the token to open a socket and listen for updates on the channel.

This diagram shows Client B sending a message using POST to the server. The server processes the message and sends it to Client A over the channel. Client A receives the message and makes use of the new information.

Example Tic Tac Toe application

To better illustrate how to use Channel API, take a look at the following example Tic Tac Toe game application written in Python. The game allows users to create a game, invite another player by sending out a URL, and play the game together in real time. The application updates both players' views of the board in real time as soon as the other player makes a move.

The full source code of the application is available at the Channel Tac Toe Project page . We'll go over major highlights that illustrate Channel API below.

Creating and connecting to a channel

When a user visits the Tic Tac Toe game for the first time, two things happen:

  • The game server injects a token into the html page sent to the client. The client uses this token to open a socket and listen for updates on the channel.
  • The game server provides the user with a URL they can share with a friend in order to invite him or her to join the game.

To initiate the process of creating a channel, JavaScript client pages need to call the create_channel() method and get a token that the client page can use to connect to the channel. When calling create_channel() , they should use a key that the application can use to uniquely identify the client.

The following server side Python code creates the channel on the server for our Tic Tac Toe application:

import jinja2
import os
import webapp2
from google.appengine.api import channel
from google.appengine.api import users

class MainPage(webapp2.RequestHandler):
  """This page is responsible for showing the game UI. It may also
  create a new game or add the currently-logged in user to a game."""

  def get(self):
    user = users.get_current_user()
    if not user:
      self.redirect(users.create_login_url(self.request.uri))
      return

    game_key = self.request.get('gamekey')
    game = None
    if not game_key:
      # If no game was specified, create a new game and make this user
      # the 'X' player.
      game_key = user.user_id()
      game = Game(key_name = game_key,
                  userX = user,
                  moveX = True,
                  board = '         ')
      game.put()
    else:
      game = Game.get_by_key_name(game_key)
      if not game.userO and game.userX != user:
        # If this game has no 'O' player, then make the current user
        # the 'O' player.
        game.userO = user
        game.put()

    token = channel.create_channel(user.user_id() + game_key)
    template_values = {'token': token,
                       'me': user.user_id(),
                       'game_key': game_key
                       }
    template = jinja_environment.get_template('index.html')
    self.response.out.write(template.render(template_values))

jinja_environment = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
app = webapp2.WSGIApplication([('/', MainPage)],
                              debug=True)

The client creates a new goog.appengine.Channel object using the token provided by the server.

<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>

The game client uses the Channel object's open() method to create a socket. The client also sets callback functions on the socket to be called when the state of the socket changes.

Opening the socket

In our example, when the Tic Tac Toe client is ready to receive messages, it calls the onOpened() function, which it set to the socket's onopen callback. The onOpened function also updates the UI for the user to indicate that the game is ready to play and sends a POST message to the server to ask it to send the latest game state.

The following client-side JavaScript code implements this functionality:

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();
};

onOpened = function() {
  connected = true;
  sendMessage('opened');
  updateBoard();
};

Note that the application defines sendMessage() as a wrapper around XmlHttpRequest , which the client uses to send messages to the server.

Updating the game state

The Tic Tac Toe Javascript client uses an onClick handler called moveInSquare to handle mouse clicks in the board. When a player makes a move in our Tic Tac Toe game by clicking on a square, the client uses XmlHttpRequest to send a POST message to the application with the proposed move.

The following client Javascript code snippet sends the message to the server:

moveInSquare = function(id) {
  if (isMyMove() && state.board[id] == ' ') {
    sendMessage('/move', 'i=' + id);
  }
}

Validating and sending the new game state

Use an HTTP request to send messages from the client to the server. In this example, when the server receives the client's message via an HTTP request, it first uses its request handler to validate the move. Then, if the move is legal, the server uses the channel.send_message() method to send messages indicating the new state of the board to both clients.

In the code sample below, the MovePage RequestHandler is called in response to the client's POST in the sendMessage call above. This handler is responsible for validating the move and broadcasting the new board state to the clients.

class MovePage(webapp2.RequestHandler):

  def post(self):
    game = GameFromRequest(self.request).get_game()
    user = users.get_current_user()
    if game and user:
      id = int(self.request.get('i'))
      GameUpdater(game).make_move(id, user)

The GameFromRequest class uses the gamekey parameter on the POST to retrieve the current game.

class GameFromRequest():
  game = None;

  def __init__(self, request):
    user = users.get_current_user()
    game_key = request.get('gamekey')
    if user and game_key:
      self.game = Game.get_by_key_name(game_key)

  def get_game(self):
    return self.game

The GameUpdater class checks that the move is valid and, if it is, uses the channel.send_message method to send updates to the clients informing them of the new state.

class GameUpdater():
  """Creates an object to store the game's state, and handles validating moves
  and broadcasting updates to the game."""
  game = None

  def __init__(self, game):
    self.game = game

  def get_game_message(self):
    # The gameUpdate object is sent to the client to render the state of a game.
    gameUpdate = {
      'board': self.game.board,
      'userX': self.game.userX.user_id(),
      'userO': '' if not self.game.userO else self.game.userO.user_id(),
      'moveX': self.game.moveX,
      'winner': self.game.winner,
      'winningBoard': self.game.winning_board
    }
    return simplejson.dumps(gameUpdate)

  def send_update(self):
    message = self.get_game_message()
    channel.send_message(self.game.userX.user_id() + self.game.key().name(),
message)
    if self.game.userO:
      channel.send_message(self.game.userO.user_id() + self.game.key().name(),
message)

  def check_win(self):
    if self.game.moveX:
      # O just moved, check for O wins
      wins = Wins().o_wins
      potential_winner = self.game.userO.user_id()
    else:
      # X just moved, check for X wins
      wins = Wins().x_wins
      potential_winner = self.game.userX.user_id()

    for win in wins:
      if win.match(self.game.board):
        self.game.winner = potential_winner
        self.game.winning_board = win.pattern
        return

  def make_move(self, position, user):
    if position >= 0 and user == self.game.userX or user == self.game.userO:
      if self.game.moveX == (user == self.game.userX):
        boardList = list(self.game.board)
        if (boardList[position] == ' '):
          boardList[position] = 'X' if self.game.moveX else 'O'
          self.game.board = "".join(boardList)
          self.game.moveX = not self.game.moveX
          self.check_win()
          self.game.put()
          self.send_update()
          return

Tracking client connections and disconnections

Applications may register to be notified when a client connects to or disconnects from a channel.

You can enable this inbound service in app.yaml :

inbound_services:
- channel_presence

When you enable channel_presence , your application receives POSTs to the following URL paths:

  • POSTs to /_ah/channel/connected/ signal that the client has connected to the channel and can receive messages.
  • POSTs to /_ah/channel/disconnected/ signal that the client has disconnected from the channel.

Your application can register handlers to these paths in order to receive notifications. You can use these notifications to track which clients are currently connected.

The "from" parameter in the POST identifies the client_id used to create the channel whose presence has changed.

# In the handler for _ah/channel/connected/
client_id = self.request.get('from')

Tokens and security

Treat the token returned by create_channel() as a secret. If a malicious application gains access to the token, it could listen to messages sent along the channel you are using. Avoid using the token in a URL request because a malicious website could see it in their referrer logs.

By default, tokens expire in two hours, unless you explicitly set an expiration time by providing the duration_minutes argument to the create_channel() function when generating the token. If a client remains connected to a channel for longer than the token duration, the socket’s onerror() and onclose() callbacks are called. At this point, the client can make an XHR request to the application to request a new token and open a new channel.

Caveats

One client per client ID

Only one client at a time can connect to a channel using a given Client ID, so an application cannot use a Client ID for fan-out. In other words, it's not possible to create a central Client ID for connections to multiple clients (For example, you can't create a Client ID for something like a "global-high-scores" channel and use it to broadcast to multiple game clients.)

One client per channel per page

A client can only connect to one channel per page. If an application needs to send multiple types of data to a client, aggregate it on the server side and send it to appropriate handlers in the client’s socket.onmessage callback.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.