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):
channel_presence
servicio de entrada dechannel_presence
debe estar habilitado enapp.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.Las rutas de URL que comienzan con
*/_ah
no son rutas de acceso que se pueden despachar y no pueden ser enrutadas pordispatch.yaml
. Por lo tanto, los manejadores de rutas de URL dechannel_presence
deben describirse enapp.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