Модули Python для App Engine и служба каналов

Я использую модули App Engine в своем проекте на Python. (https://developers.google.com/appengine/docs/python/modules/#Python_Background_threads)

Я также использую каналы в проекте m: https://developers.google.com/appengine/docs/python/channel/

Я хочу направить подключенные / отключенные почтовые сообщения ('/ _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)

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)

Итак, мой клиент (написанный на 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 / тоже никогда не вызывается.

Служба канала не поддерживается модулями? Любые мысли относительно того, что мне не хватает?


person David Ward    schedule 03.10.2013    source источник


Ответы (3)


Согласно поддержке Google Enterprise (с небольшими изменениями по сравнению с необработанным ответом):

  1. channel_presence входящая служба должна быть включена в app.yaml.

    inbound_services:
    - channel_presence
    

    Включение этой входящей службы в файле yaml модуля (например, api.yaml в этом вопросе) не включит эту службу.

  2. Пути URL, начинающиеся с */_ah, не являются управляемыми путями и не могут маршрутизироваться с помощью dispatch.yaml. Следовательно, channel_presence обработчики URL-путей должны быть описаны в app.yaml.

    handlers:
    - url: /_ah/channel/connected/
      script: mymodule.application
    
person Emil Sit    schedule 29.10.2014
comment
Какая строка здесь должна быть правильной для golang: script: mymodule.application? - person mattes; 13.11.2014
comment
mattes - я думаю, что эта строка не зависит от языка, но Эмиль: я также был бы признателен за более подробное объяснение того, как это работает - person davidkomer; 20.02.2015
comment
Дополнительную информацию о app.yaml см. В документации it. Для Go соответствующая версия находится здесь cloud.google.com/appengine/docs/ перейти / config / appconfig - person Emil Sit; 09.03.2015

Вы должны объявить хадлер-маршрутизацию для подключения и отключить 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)
        ...
person Christopher Ramírez    schedule 03.10.2013
comment
Спасибо за ответ, но я боюсь, что проблема не в этом. Я не размещал здесь код, но у меня есть добавленные маршруты. Если бы я этого не сделал, это не сработало бы в режиме разработки. - person David Ward; 03.10.2013

Я также столкнулся с проблемами с использованием Channel API в модулях, и я попытался обойти их, используя аналогичный прием, о котором упоминает Эмиль, путем перенаправления запросов к модулям.

Это была немного более сложная настройка, потому что у меня было 3 модуля, 2 из которых использовали Channel API, а один был «интерфейсом». Что-то вроде этого:

  • интерфейс модуля (по умолчанию)
  • модуль serviceA (с использованием канала api 1)
  • модуль serviceB (с использованием канала api 2)

Я хотел иметь возможность прослушивать «уведомления» от двух отдельных сервисов во внешнем интерфейсе.

И способ, которым мне удалось обойти это (в dev), заключался в добавлении перенаправления на интерфейс, который считывал токены, которые я использовал для каждой службы, и перенаправлял на каждую службу.

"Отлично, работает!" Я подумал, но затем, когда я попытался развернуть на движке приложения, я понял, что это еще не все, поскольку конечные точки Talkgadget, используемые внутренне API канала, казалось, ожидали определенного исходного приложения и, таким образом, не допускали междоменного взаимодействия.

Так что я закончил тем, что использовал несколько проектов вместо модулей и поместил HTML iframe «мост postMessage», чтобы обойти междоменные проблемы. И, к счастью, это действительно хорошо работает, и в качестве побочного эффекта я получаю вдвое больше «бесплатных» каналов.

Я обнаружил здесь связанную с этим проблему, которую вам может быть интересно отслеживать: https://code.google.com/p/googleappengine/issues/detail?id=10293

person Robert Sköld    schedule 13.11.2014