App Engine Python模块和通道服务

10
我在我的 Python 项目中使用 App Engine 模块 (https://developers.google.com/appengine/docs/python/modules/#Python_Background_threads),同时还使用了通道 (https://developers.google.com/appengine/docs/python/channel/)。
我想将连接/断开连接的 post 消息('/_ah/channel/connected/'、'/_ah/channel/disconnected/')指向我的 API 模块。目前它们无法在任何模块中显示(默认或 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

注意:只要清楚,这些都在本地的开发模式下工作。

api.main.app

    app = webapp2.WSGIApplication(debug=True)
    _routes = [
        :
        ChannelDisconnectedHandler.mapping(),
        ChannelConnectHandler.mapping()
    ]

    for r in self._routes:
        app.router.add(r)

通道断开连接处理程序

    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)

所以我的客户端(用JavaScript编写)向我的API模块发布并打开了一个通道。

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

当使用有效令牌时,将调用此回调函数。我成功创建了套接字并按预期完成了此函数。在我的本地系统中,然后调用onOpened函数,并从服务器接收消息。但是在生产环境中,onOpened没有被调用,我也没有收到任何消息。/_ah/channel/connected/也从未被调用。

频道服务是否不支持模块?有无想法我缺少了什么?

3个回答

6

根据谷歌企业支持(稍作修改):

  1. channel_presence inbound service must be enabled in app.yaml.

    inbound_services:
    - channel_presence
    

    Enabling this inbound service in module’s yaml file (e.g., api.yaml in this question) won’t enable this service.

  2. URL paths starting with */_ah are not dispatchable paths and cannot be routed by dispatch.yaml. Therefore, channel_presence URL paths handlers have to be described in app.yaml.

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

这里使用golang的正确代码是什么:script:mymodule.application - mattes
Mattes- 我认为那行代码是与语言无关的,但是Emil- 我也希望能够更详细地解释一下它是如何工作的。 - davidkomer
有关 app.yaml 的更多信息,请参阅相应的语言文档。对于 Go 语言,相关版本在此处 https://cloud.google.com/appengine/docs/go/config/appconfig。 - Emil Sit

0

我在使用模块中遇到了使用Channel API的问题,我尝试使用Emil提到的类似技巧来解决这些问题,通过将请求重定向到模块来解决。

但实际上,我的设置稍微复杂一些,因为我有3个模块,其中2个使用了Channel API,而另一个是“前端”。就像这样:

  • 模块前端(默认)
  • 模块服务A(使用Channel API 1)
  • 模块服务B(使用Channel API 2)

我想要能够在前端监听来自两个不同服务的“通知”。

我设法解决了这个问题(在开发环境中),方法是在前端添加重定向,读取我在每个服务上添加的令牌,并将其重定向到每个服务。

“太好了,它起作用了!”我想,但当我尝试部署到应用引擎时,我意识到其中还有更多问题,因为Channel API内部使用的talkgadget端点似乎期望特定的源应用程序,因此不允许跨域通信。

所以我最终使用了多个项目而不是模块,并通过放置一个HTML iframe“postMessage桥”来解决跨域问题。令人高兴的是,它运行得非常好,作为副作用,我获得了两倍的“免费”频道可供使用。
我在这里发现了一个相关问题,可能对您有所帮助:https://code.google.com/p/googleappengine/issues/detail?id=10293

0

您需要在连接和断开URL的处理程序路由上进行声明。

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

1
谢谢您的回答,但恐怕这不是问题所在。我没有在这里发布代码,但我已经添加了路由。如果我没有添加路由,它在开发模式下就无法工作。 - David Ward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接