Source code for

#!/usr/bin/env python
# Copyright 2007 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.

"""Channel API.

This module allows App Engine apps to push messages to a client.

Functions defined in this module:
  create_channel: Creates a channel to send messages to.
  send_message: Send a message to any clients listening on the given channel.

import os

from google.appengine.api import api_base_pb
from google.appengine.api import apiproxy_stub_map
from import channel_service_pb
from google.appengine.runtime import apiproxy_errors




[docs]class Error(Exception): """Base error class for this module."""
[docs]class InvalidChannelClientIdError(Error): """Error that indicates a bad client id."""
[docs]class InvalidChannelTokenDurationError(Error): """Error that indicates the requested duration is invalid."""
[docs]class InvalidMessageError(Error): """Error that indicates a message is malformed."""
[docs]class AppIdAliasRequired(Error): """Error that indicates you must assign an application alias to your app."""
def _ToChannelError(error): """Translate an application error to a channel Error, if possible. Args: error: An ApplicationError to translate. Returns: The appropriate channel service error, if a match is found, or the original ApplicationError. """ error_map = { channel_service_pb.ChannelServiceError.INVALID_CHANNEL_KEY: InvalidChannelClientIdError, channel_service_pb.ChannelServiceError.BAD_MESSAGE: InvalidMessageError, channel_service_pb.ChannelServiceError.APPID_ALIAS_REQUIRED: AppIdAliasRequired } if error.application_error in error_map: return error_map[error.application_error](error.error_detail) else: return error def _GetService(): """Gets the service name to use, based on if we're on the dev server.""" server_software = os.environ.get('SERVER_SOFTWARE', '') if (server_software.startswith('Devel') or server_software.startswith('test')): return 'channel' else: return 'xmpp' def _ValidateClientId(client_id): """Validates a client id. Args: client_id: The client id provided by the application. Returns: If the client id is of type str, returns the original client id. If the client id is of type unicode, returns the id encoded to utf-8. Raises: InvalidChannelClientIdError: if client id is not an instance of str or unicode, or if the (utf-8 encoded) string is longer than 64 characters. """ if not isinstance(client_id, basestring): raise InvalidChannelClientIdError('"%s" is not a string.' % client_id) if isinstance(client_id, unicode): client_id = client_id.encode('utf-8') if len(client_id) > MAXIMUM_CLIENT_ID_LENGTH: msg = 'Client id length %d is greater than max length %d' % ( len(client_id), MAXIMUM_CLIENT_ID_LENGTH) raise InvalidChannelClientIdError(msg) return client_id
[docs]def create_channel(client_id, duration_minutes=None): """Create a channel. Args: client_id: A string to identify this channel on the server side. duration_minutes: An int specifying the number of minutes for which the returned token should be valid. Returns: A token that the client can use to connect to the channel. Raises: InvalidChannelClientIdError: if clientid is not an instance of str or unicode, or if the (utf-8 encoded) string is longer than 64 characters. InvalidChannelTokenDurationError: if duration_minutes is not a number, less than 1, or greater than 1440 (the number of minutes in a day). Other errors returned by _ToChannelError """ client_id = _ValidateClientId(client_id) if not duration_minutes is None: if not isinstance(duration_minutes, (int, long)): raise InvalidChannelTokenDurationError( 'Argument duration_minutes must be integral') elif duration_minutes < 1: raise InvalidChannelTokenDurationError( 'Argument duration_minutes must not be less than 1') elif duration_minutes > MAXIMUM_TOKEN_DURATION_MINUTES: msg = ('Argument duration_minutes must be less than %d' % (MAXIMUM_TOKEN_DURATION_MINUTES + 1)) raise InvalidChannelTokenDurationError(msg) request = channel_service_pb.CreateChannelRequest() response = channel_service_pb.CreateChannelResponse() request.set_application_key(client_id) if not duration_minutes is None: request.set_duration_minutes(duration_minutes) try: apiproxy_stub_map.MakeSyncCall(_GetService(), 'CreateChannel', request, response) except apiproxy_errors.ApplicationError, e: raise _ToChannelError(e) return response.token()
[docs]def send_message(client_id, message): """Send a message to a channel. Args: client_id: The client id passed to create_channel. message: A string representing the message to send. Raises: InvalidChannelClientIdError: if client_id is not an instance of str or unicode, or if the (utf-8 encoded) string is longer than 64 characters. InvalidMessageError: if the message isn't a string or is too long. Errors returned by _ToChannelError """ client_id = _ValidateClientId(client_id) if isinstance(message, unicode): message = message.encode('utf-8') elif not isinstance(message, str): raise InvalidMessageError('Message must be a string') if len(message) > MAXIMUM_MESSAGE_LENGTH: raise InvalidMessageError( 'Message must be no longer than %d chars' % MAXIMUM_MESSAGE_LENGTH) request = channel_service_pb.SendMessageRequest() response = api_base_pb.VoidProto() request.set_application_key(client_id) request.set_message(message) try: apiproxy_stub_map.MakeSyncCall(_GetService(), 'SendChannelMessage', request, response) except apiproxy_errors.ApplicationError, e: raise _ToChannelError(e)

Send feedback about...

App Engine standard environment for Python