tutorial standard google español engine app google-app-engine python-2.7 module channel-api gae-module

google-app-engine - standard - google app engine tutorial español



App Engine Python Modules y servicio de canal (3)

Debe declarar un enrutamiento de hadler para las URL de conexión y desconexión.

Enrutamiento del manejador en main.py :

application = webapp2.WSGIApplication([ ... # Define a URL routing for /_ah/channel/connected/ webapp2.Route(r''/_ah/channel/connected/'', handler=ChannelConnectedHandler, name=''channel_connected'') ], debug=True, config=webapp2_config) # Implement class handler of /_ah/channel/connected/ class ChannelConnectedHandler(webapp2.RequestHandler): def post(self): client_id = self.request.get(''from'') logging.info(''client %s has connected!'' % client_id) ...

Estoy usando los módulos de App Engine en mi proyecto python. ( https://developers.google.com/appengine/docs/python/modules/#Python_Background_threads )

También estoy usando canales en el proyecto m: https://developers.google.com/appengine/docs/python/channel/

Deseo dirigir los mensajes de correo conectados / desconectados (''/ _ah / channel / connected /'', ''/ _ah / channel / desconectado /'') a mi módulo de API. En este momento no puedo hacer que aparezcan en ningún módulo (predeterminado o api)

app.yaml

api_version: 1 application: integrate version: 1-0-0 runtime: python27 threadsafe: true builtins: - deferred: on libraries: - name: pycrypto version: "2.6" handlers: - url: /favicon/.ico static_files: static/favicon.ico upload: static/favicon/.ico - url: /admin/.+ script: src.default.main.app login: admin - url: /.* script: src.default.main.app

api.yaml

api_version: 1 application: integrate module: api version: 1-0-0 runtime: python27 threadsafe: true inbound_services: - channel_presence builtins: - deferred: on libraries: - name: pycrypto version: "2.6" handlers: - url: /admin/.+ script: src.api.main.app login: admin - url: /.* script: src.api.main.app

dispatch.yaml

application: integrate dispatch: - url: "*/_ah/channel/*" module: api

Nota: Para que quede claro, todo esto funciona en modo dev localmente.

api.main.app

app = webapp2.WSGIApplication(debug=True) _routes = [ : ChannelDisconnectedHandler.mapping(), ChannelConnectHandler.mapping() ] for r in self._routes: app.router.add(r)

ChannelDisconnectHandler

CHANNEL_DISCONNECTED_URL_PATTERN = ''/_ah/channel/disconnected/'' class ChannelDisconnectedHandler(RequestHandler): @classmethod def mapping(cls): return CHANNEL_DISCONNECTED_URL_PATTERN, cls def post(self): """ Channel Presence handler. Will be called when a client disconnects. """ channel_id = self.request.get(''from'') logging.info("Channel Disconnect. Id: %s" % channel_id)

ChannelConnectHandler

CHANNEL_CONNECT_URL_PATTERN = ''/_ah/channel/connected/'' class ChannelConnectHandler(RequestHandler): @classmethod def mapping(cls): return CHANNEL_CONNECT_URL_PATTERN, cls def post(self): """ Channel Presence handler. Will be called when a client connects. """ channel_id = self.request.get(''from'') logging.info("Channel Connect. Id: %s" % channel_id)

Entonces mi cliente (escrito en javascript) publica en mi módulo de API y abre un canal.

var open_channel = function(tokenResponse) { console.log("Open Channel. token Response: " + tokenResponse) token = tokenResponse.token; var channel = new goog.appengine.Channel(token); if (socket != null) { socket.close(); } socket = channel.open(); socket.onopen = onOpened; socket.onmessage = onMessage; socket.onerror = onError; socket.onclose = onClose; }; onOpened = function() { console.info("Channel API Connection is open."); }; onError = function(e) { console.info("CHANNEL Error. Code: " + e.code + ", Description: " + e.description); }; onClose = function() { console.info("Close Channel"); }; onMessage = function(msg) { console.info("Message Received: " + msg + ", Data: " + msg.data); };

Esta función de devolución de llamada se alcanza con un token válido. Creo el socket con éxito y completa esta función como se esperaba. En mi sistema local, se llama a la función onOpened y recibo los mensajes del servidor. En producción en Abierto nunca se llama y nunca recibo ningún mensaje. El / _ah / channel / connected / tampoco se llama.

¿El servicio de canal no es compatible con módulos? ¿Alguna idea de lo que me estoy perdiendo?


De acuerdo con Google Enterprise Support (modificado ligeramente de su respuesta bruta):

  1. channel_presence servicio de entrada de channel_presence debe estar habilitado en app.yaml .

    inbound_services: - channel_presence

    La habilitación de este servicio entrante en el archivo yaml del módulo (por ejemplo, api.yaml en esta pregunta) no habilitará este servicio.

  2. Las rutas de URL que comienzan con */_ah no son rutas de acceso que se pueden despachar y no pueden ser enrutadas por dispatch.yaml . Por lo tanto, los manejadores de rutas de URL de channel_presence deben describirse en app.yaml .

    handlers: - url: /_ah/channel/connected/ script: mymodule.application


También me he topado con problemas al usar Channel API en módulos e intenté solucionarlos utilizando un truco similar al que Emil menciona al redirigir las solicitudes a los módulos.

Sin embargo, fue una configuración un poco más complicada porque en realidad tenía 3 módulos, donde 2 de ellos usaban Channel API y uno era el ''frontend''. Algo como esto:

  • frontend de módulo (predeterminado)
  • servicio de módulo A (usando canal api 1)
  • servicio de módulo B (utilizando canal api 2)

Quería poder escuchar las "notificaciones" de los dos servicios por separado en la interfaz.

Y la forma en que me las arreglé para solucionar ese problema (en dev) fue agregar redireccionamientos a la interfaz que leen los tokens que he puesto como prefijo en cada servicio y redirigirlos a cada servicio.

"¡Genial, funciona!" Pensé, pero luego, cuando traté de implementarlo en el motor de la aplicación, me di cuenta de que había más porque los puntos finales del talkgadget utilizados internamente por la API del canal parecían esperar cierta aplicación fuente y, por lo tanto, no permitían la comunicación entre dominios.

Así que terminé usando múltiples proyectos en lugar de módulos y al poner un iframe HTML "postMessage bridge" para evitar los problemas de dominio cruzado. Y con mucho gusto funciona muy bien y, como efecto secundario, tengo el doble de canales "gratuitos" para usar.

Encontré un problema relacionado con esto aquí que puede ser interesante para su seguimiento: https://code.google.com/p/googleappengine/issues/detail?id=10293