development.ini | 5 - moksha.spec | 2 moksha/api/hub/consumer.py | 30 +++++++- moksha/api/hub/producer.py | 23 ++++++ moksha/api/widgets/amqp/amqp.py | 15 ++-- moksha/api/widgets/orbited/orbited.py | 2 moksha/api/widgets/stomp/stomp.py | 4 - moksha/apps/metrics/moksha/apps/metrics/consumers/metrics_consumer.py | 17 +--- moksha/apps/topics/pavement.py | 36 ---------- moksha/apps/topics/pavement.py.hide | 36 ++++++++++ moksha/commands/quickstart.py | 10 +- moksha/hub/stomp/stomp.py | 1 moksha/lib/helpers.py | 6 - moksha/pastetemplate.py | 8 +- moksha/public/javascript/moksha.js | 1 moksha/templates/moksha/consumer/moksha/apps/+package+/consumers.py_tmpl | 5 - moksha/templates/moksha/stream/moksha/apps/+package+/streams.py_tmpl | 9 -- pavement.py | 2 setup.py | 2 19 files changed, 129 insertions(+), 85 deletions(-)
New commits: commit dfb38bf7853707cf4a7780c46a7f6cefcf6ff9e4 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 08:12:31 2009 -0500
A much improved Metrics Consumer using the new API
diff --git a/moksha/apps/metrics/moksha/apps/metrics/consumers/metrics_consumer.py b/moksha/apps/metrics/moksha/apps/metrics/consumers/metrics_consumer.py index 58acdef..e249316 100644 --- a/moksha/apps/metrics/moksha/apps/metrics/consumers/metrics_consumer.py +++ b/moksha/apps/metrics/moksha/apps/metrics/consumers/metrics_consumer.py @@ -13,24 +13,21 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/. +""" +Moksha Metrics Consumer +=======================
-import logging +.. moduleauthor:: Luke Macken lmacken@redhat.com +"""
-from orbited import json from moksha.api.hub import Consumer
-log = logging.getLogger('moksha.hub') - class MokshaMessageMetricsConsumer(Consumer): """ This consumer listens to all messages on the `moksha_message_metrics` - topic, and relays the messgae to the message['headers']['topic'] + topic, and relays the message to the message.body['topic'] topic. """ topic = 'moksha_message_metrics'
def consume(self, message): - topic = message['headers'].get('topic') - if topic: - self.send_message(topic, json.encode(message['body'])) - else: - log.error('No `topic` specified in moksha_message_metrics message') + self.send_message(message['topic'], message['data'])
commit 74f6689c4be9d544e528ba28673f642611036667 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 08:12:03 2009 -0500
Remove an unnecessary debugging statment in our AMQP socket
diff --git a/moksha/api/widgets/amqp/amqp.py b/moksha/api/widgets/amqp/amqp.py index 22acd29..935422f 100644 --- a/moksha/api/widgets/amqp/amqp.py +++ b/moksha/api/widgets/amqp/amqp.py @@ -85,7 +85,6 @@ class AMQPSocket(Widget): moksha_amqp_remote_queue = null; moksha_amqp_queue = null; moksha_amqp_on_message = function(msg) { - moksha.debug('moksha_amqp_on_message(' + msg.body + ')'); var dest = msg.header.delivery_properties.routing_key; var json = $.secureEvalJSON(msg.body); if (moksha_callbacks[dest]) {
commit 909c1b9f8b12c98c78c0d232fa925bedad8cd92f Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 08:10:43 2009 -0500
Improve our Consumer API
- Add a 'jsonify' argument that will automatically decode JSON messages before consuming. It will also encode JSON messages before sending. - Abstract the Message object, to make it a simple dictionary of the body
diff --git a/moksha/api/hub/consumer.py b/moksha/api/hub/consumer.py index 08245d9..f3f32d5 100644 --- a/moksha/api/hub/consumer.py +++ b/moksha/api/hub/consumer.py @@ -28,14 +28,18 @@ loaded, and receives each message for the specified topic through the
import logging log = logging.getLogger('moksha.hub') + from moksha.hub.hub import MokshaHub -from moksha.lib.helpers import listify, create_app_engine +from moksha.lib.helpers import listify, create_app_engine, json from sqlalchemy.orm import sessionmaker
class Consumer(object): """ A message consumer """ topic = None
+ # Automatically decode JSON data + jsonify = True + def __init__(self): self.hub = MokshaHub() self.log = log @@ -50,7 +54,10 @@ class Consumer(object): self.hub.message_subscribe(queue=server_queue_name, destination=local_queue_name) self.hub.local_queue.start() - self.hub.local_queue.listen(self.consume) + if self.jsonify: + self.hub.local_queue.listen(self._consume_json) + else: + self.hub.local_queue.listen(self._consume)
# If the consumer specifies an 'app', then setup `self.engine` to # be a SQLAlchemy engine, along with a configured DBSession @@ -61,10 +68,29 @@ class Consumer(object): self.engine = create_app_engine(app) self.DBSession = sessionmaker(bind=self.engine)()
+ + def _consume_json(self, message): + """ Convert our AMQP messages into a consistent dictionary format. + + This method exists because our STOMP & AMQP message brokers consume + messages in different formats. This causes our messaging abstraction + to leak into the consumers themselves. + + :Note: We do not pass the message headers to the consumer (in this AMQP consumer) + because the current AMQP.js bindings do not allow the client to change them. + Thus, we need to throw any topic/queue details into the JSON body itself. + """ + self.consume(json.decode(message.body)) + + def _consume(self, message): + self.consume(message.body) + def consume(self, message): raise NotImplementedError
def send_message(self, topic, message): + if self.jsonify: + message = json.encode(message) try: self.hub.send_message(topic, message) except Exception, e:
commit a74264dfb9b0e7d589e38c7140143f5b1612c0a5 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:58:13 2009 -0500
Create a json.{encode,decode} abstraction in moksha.lib.helpers
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py index e640817..8ba747f 100644 --- a/moksha/lib/helpers.py +++ b/moksha/lib/helpers.py @@ -20,11 +20,11 @@ import time import pylons import urllib import uuid -import simplejson as json import re import os import logging import warnings +from orbited import json
from tw.api import js_callback from pytz import timezone, utc @@ -59,7 +59,7 @@ def _update_params(params, d): # by the passed params if isinstance(value, dict): value = _update_params(value, d) - value = json.dumps(value) + value = json.encode(value) elif isinstance(value, list): value = value
@@ -327,7 +327,7 @@ class App(ConfigWrapper): qs = self._create_query_string(p) results.update({'label': self.label, 'url': self.url, 'params': p, - 'json_params': json.dumps(p), + 'json_params': json.encode(p), 'query_string': qs, 'content_id': self.content_id + '-' + results['id'], 'css_class': css_class})
commit 4dcbcf596879ea733d8c7844788fb06ac542a953 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:55:53 2009 -0500
Hide our moksha.topics pavement.py so we don't install it by default
diff --git a/moksha/apps/topics/pavement.py b/moksha/apps/topics/pavement.py deleted file mode 100644 index 4c8b36f..0000000 --- a/moksha/apps/topics/pavement.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -from paver.easy import * -from paver.setuputils import (setup, find_package_data, find_packages, - install_distutils_tasks) -install_distutils_tasks() -from moksha.lib.paver_tasks import * - -options( - setup=Bunch( - name="moksha.topics", - version="0.1", - release="1", - url="http://moksha.fedorahosted.org", - description="Describe your package here", - license="AGPLv3", - long_description="", - author="", - author_email="", - rpm_name='moksha-topics', - packages=find_packages(), - package_data=find_package_data(), - namespace_packages=[ - 'moksha', - 'moksha.apps', - ], - install_requires=["Moksha"], - entry_points={ - 'moksha.stream': ( - 'topics = moksha.apps.topics.streams:TopicsStream', - ), - 'moksha.consumer': ( - 'topics = moksha.apps.topics.consumers:TopicsConsumer' - ), - } - ), -) diff --git a/moksha/apps/topics/pavement.py.hide b/moksha/apps/topics/pavement.py.hide new file mode 100644 index 0000000..4c8b36f --- /dev/null +++ b/moksha/apps/topics/pavement.py.hide @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from paver.easy import * +from paver.setuputils import (setup, find_package_data, find_packages, + install_distutils_tasks) +install_distutils_tasks() +from moksha.lib.paver_tasks import * + +options( + setup=Bunch( + name="moksha.topics", + version="0.1", + release="1", + url="http://moksha.fedorahosted.org", + description="Describe your package here", + license="AGPLv3", + long_description="", + author="", + author_email="", + rpm_name='moksha-topics', + packages=find_packages(), + package_data=find_package_data(), + namespace_packages=[ + 'moksha', + 'moksha.apps', + ], + install_requires=["Moksha"], + entry_points={ + 'moksha.stream': ( + 'topics = moksha.apps.topics.streams:TopicsStream', + ), + 'moksha.consumer': ( + 'topics = moksha.apps.topics.consumers:TopicsConsumer' + ), + } + ), +)
commit 30b98a87a1ead3e6fa3075dfd85f56571ef08ccc Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:31:38 2009 -0500
Empty out the queued stomp frames after we flush them
diff --git a/moksha/hub/stomp/stomp.py b/moksha/hub/stomp/stomp.py index cca8b08..741c55b 100644 --- a/moksha/hub/stomp/stomp.py +++ b/moksha/hub/stomp/stomp.py @@ -53,6 +53,7 @@ class StompHub(MessagingHub, ReconnectingClientFactory): for frame in self._frames: log.debug('Flushing queued frame') self.proto.transport.write(frame.pack()) + self._frames = []
def clientConnectionLost(self, connector, reason): log.info('Lost connection. Reason: %s' % reason)
commit 1d2b9a26db669da7e4ef3bc99086eb4bd6a6bf53 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:30:11 2009 -0500
Version bump
diff --git a/moksha.spec b/moksha.spec index b78f877..d4c594d 100644 --- a/moksha.spec +++ b/moksha.spec @@ -2,7 +2,7 @@ %{!?pyver: %define pyver %(%{__python} -c "import sys ; print sys.version[:3]")}
Name: moksha -Version: 0.4.3 +Version: 0.4.4 Release: 1%{?dist} Summary: A flexable platform for creating live collaborative web applications Group: Applications/Internet diff --git a/pavement.py b/pavement.py index 412a47a..9fe3c9e 100644 --- a/pavement.py +++ b/pavement.py @@ -25,7 +25,7 @@ from paver.setuputils import find_packages, find_package_data import paver.misctasks import paver.virtual
-VERSION = '0.4.2' +VERSION = '0.4.4'
HEADER = """This file is part of Moksha. Copyright (C) 2008-2009 Red Hat, Inc. diff --git a/setup.py b/setup.py index 2bfb452..3b16dcc 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ from paver.setuputils import find_package_data
setup( name='moksha', - version='0.4.3', + version='0.4.4', description='', author='', author_email='',
commit e5c8fe54e3e10ca6c6aa0537aac041cbd1b51af3 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:29:09 2009 -0500
Have our stream quickstart use the producer api
diff --git a/moksha/templates/moksha/stream/moksha/apps/+package+/streams.py_tmpl b/moksha/templates/moksha/stream/moksha/apps/+package+/streams.py_tmpl index 38fa4b3..845738c 100644 --- a/moksha/templates/moksha/stream/moksha/apps/+package+/streams.py_tmpl +++ b/moksha/templates/moksha/stream/moksha/apps/+package+/streams.py_tmpl @@ -1,11 +1,8 @@ -#import logging -#log = logging.getLogger('moksha.hub') - from datetime import timedelta, datetime -from moksha.api.streams import PollingDataStream +from moksha.api.hub.producer import PollingProducer
-class {{stream_name}}(PollingDataStream): - frequency = timedelta(seconds=3) +class {{stream_name}}(PollingProducer): + frequency = timedelta(seconds=5) topic = '{{topic}}' i = 0
commit 84634d968c6b394cf64819a796914c56ac97dbcf Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:28:40 2009 -0500
Add a new moksha.api.hub.producer API, to complement the Consumer API
diff --git a/moksha/api/hub/producer.py b/moksha/api/hub/producer.py new file mode 100644 index 0000000..5986134 --- /dev/null +++ b/moksha/api/hub/producer.py @@ -0,0 +1,23 @@ +# This file is part of Moksha. +# Copyright (C) 2009 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see http://www.gnu.org/licenses/. +""" +:mod:`moksha.api.hub.producer - The Moksha Producer API +======================================================= +""" +from moksha.api.streams import * + +Producer = DataStream +PollingProducer = PollingDataStream
commit 52e4f365ce4e56567b78a1d663aae63556fcf29a Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:28:13 2009 -0500
Slim down our consumer quickstart
diff --git a/moksha/templates/moksha/consumer/moksha/apps/+package+/consumers.py_tmpl b/moksha/templates/moksha/consumer/moksha/apps/+package+/consumers.py_tmpl index 6d6a467..0890787 100644 --- a/moksha/templates/moksha/consumer/moksha/apps/+package+/consumers.py_tmpl +++ b/moksha/templates/moksha/consumer/moksha/apps/+package+/consumers.py_tmpl @@ -1,10 +1,7 @@ -import logging -log = logging.getLogger('moksha.hub') - from moksha.api.hub import Consumer
class {{consumer_name}}(Consumer): topic = '{{topic}}'
def consume(self, message): - log.info("%r.consume(%r)" % (self, message)) + self.log.info("%r.consume(%r)" % (self, message))
commit e161400dfe8be49724e31f734026ff73701f29d4 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:27:43 2009 -0500
Tweak the quickstart default topics
diff --git a/moksha/pastetemplate.py b/moksha/pastetemplate.py index b099635..53730b7 100644 --- a/moksha/pastetemplate.py +++ b/moksha/pastetemplate.py @@ -43,7 +43,7 @@ class MokshaLiveWidgetTemplate(Template): egg_plugins = ['Moksha'] vars = [ var('topic', 'The moksha topic to utilize', - default='moksha.topics.test'), + default='moksha.test'), var('livewidget', 'Include an example live widget', default=False), var('widget_name', 'The name of the widget', default=None), ] @@ -51,7 +51,7 @@ class MokshaLiveWidgetTemplate(Template): def pre(self, command, output_dir, vars): """Called before template is applied.""" if 'widget_name' not in vars: - vars['widget_name'] = vars['project'].title() + 'Widget' + vars['widget_name'] = vars['package'].title() + 'Widget'
class MokshaStreamTemplate(Template): summary = 'Moksha Stream Quickstart Template' @@ -59,7 +59,7 @@ class MokshaStreamTemplate(Template): template_renderer = staticmethod(paste_script_template_renderer) vars = [ var('topic', 'The moksha topic to utilize', - default='moksha.topics.test'), + default='moksha.test'), ]
def pre(self, command, output_dir, vars): @@ -78,7 +78,7 @@ class MokshaConsumerTemplate(Template): template_renderer = staticmethod(paste_script_template_renderer) vars = [ var('topic', 'The moksha topic to utilize', - default='moksha.topics.test'), + default='moksha.test'), ]
def pre(self, command, output_dir, vars): diff --git a/moksha/public/javascript/moksha.js b/moksha/public/javascript/moksha.js index 7285481..cb2f716 100644 --- a/moksha/public/javascript/moksha.js +++ b/moksha/public/javascript/moksha.js @@ -789,7 +789,6 @@ moksha = { },
send_message: function(topic, body) { - moksha.debug('moksha.send_message(' + topic + ', ' + body + ')'); if (typeof(moksha_amqp_session) != 'undefined') { moksha_amqp_session.Message('transfer', { accept_mode: 1,
commit 90dd2d1060885e265cfe3755aa038f5dedc01019 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:27:08 2009 -0500
Minor tweak to the way we name our quickstart classes
diff --git a/moksha/commands/quickstart.py b/moksha/commands/quickstart.py index 65d6ac3..f751c4e 100644 --- a/moksha/commands/quickstart.py +++ b/moksha/commands/quickstart.py @@ -140,11 +140,11 @@ Example usage:: cmd_args.append("controller=%s" % self.controller) cmd_args.append("stream=%s" % self.stream) cmd_args.append("package=%s" % self.package) - cmd_args.append("widget_name=%s" % self.name.title() + 'Widget') - cmd_args.append("stream_name=%s" % self.name.title() + 'Stream') - cmd_args.append("consumer_name=%s" % self.name.title() + 'Consumer') - cmd_args.append("connector_name=%s" % self.name.title() + 'Connector') - cmd_args.append("controller_name=%s" % self.name.title() + 'Controller') + cmd_args.append("widget_name=%s" % self.package.title() + 'Widget') + cmd_args.append("stream_name=%s" % self.package.title() + 'Stream') + cmd_args.append("consumer_name=%s" % self.package.title() + 'Consumer') + cmd_args.append("connector_name=%s" % self.package.title() + 'Connector') + cmd_args.append("controller_name=%s" % self.package.title() + 'Controller') command.run(cmd_args)
#if not self.dry_run:
commit 4f88806c455dd316ca65b25fc59d915fe38148a6 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:26:41 2009 -0500
Make the orbited url scheme configurable, to allow https proxies
diff --git a/moksha/api/widgets/amqp/amqp.py b/moksha/api/widgets/amqp/amqp.py index 78d2887..22acd29 100644 --- a/moksha/api/widgets/amqp/amqp.py +++ b/moksha/api/widgets/amqp/amqp.py @@ -161,7 +161,9 @@ class AMQPSocket(Widget): self.notify = asbool(config.get('moksha.socket.notify', False)) self.orbited_host = config.get('orbited_host', 'localhost') self.orbited_port = config.get('orbited_port', 9000) - self.orbited_url = 'http://%s:%s' % (self.orbited_host, self.orbited_port) + self.orbited_scheme = config.get('orbited_scheme', 'http') + self.orbited_url = '%s://%s:%s' % (self.orbited_scheme, + self.orbited_host, self.orbited_port) self.orbited_js = JSLink(link=self.orbited_url + '/static/Orbited.js') self.amqp_broker_host = config.get('amqp_broker_host', 'localhost') self.amqp_broker_port = config.get('amqp_broker_port', 5672) diff --git a/moksha/api/widgets/orbited/orbited.py b/moksha/api/widgets/orbited/orbited.py index 3af78db..2a1516b 100644 --- a/moksha/api/widgets/orbited/orbited.py +++ b/moksha/api/widgets/orbited/orbited.py @@ -21,7 +21,7 @@ from tw.api import Widget, JSLink, js_callback
orbited_host = config.get('orbited_host', 'localhost') orbited_port = config.get('orbited_port', 9000) -orbited_url = 'http://%s:%s' % (orbited_host, orbited_port) +orbited_url = '%s://%s:%s' % (config.get('orbited_scheme', 'http'), orbited_host, orbited_port) orbited_js = JSLink(link=orbited_url + '/static/Orbited.js')
class OrbitedWidget(Widget): diff --git a/moksha/api/widgets/stomp/stomp.py b/moksha/api/widgets/stomp/stomp.py index a532b2e..848f10d 100644 --- a/moksha/api/widgets/stomp/stomp.py +++ b/moksha/api/widgets/stomp/stomp.py @@ -153,7 +153,9 @@ class StompWidget(Widget): self.notify = asbool(config.get('moksha.socket.notify', False)) self.orbited_host = config.get('orbited_host', 'localhost') self.orbited_port = config.get('orbited_port', 9000) - self.orbited_url = 'http://%s:%s' % (self.orbited_host, self.orbited_port) + self.orbited_scheme = config.get('orbited_scheme', 'http') + self.orbited_url = '%s://%s:%s' % (self.orbited_scheme, + self.orbited_host, self.orbited_port) self.orbited_js = JSLink(link=self.orbited_url + '/static/Orbited.js') self.stomp_host = config.get('stomp_host', 'localhost') self.stomp_port = config.get('stomp_port', 61613)
commit 5d3522a00d84f768e3dcbc249c37865aafdf4b73 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:26:02 2009 -0500
Add our send/recive hooks above everything to avoid ending our dict with a comma
diff --git a/moksha/api/widgets/amqp/amqp.py b/moksha/api/widgets/amqp/amqp.py index bb6aea1..78d2887 100644 --- a/moksha/api/widgets/amqp/amqp.py +++ b/moksha/api/widgets/amqp/amqp.py @@ -115,16 +115,16 @@ class AMQPSocket(Widget): Orbited.settings.hostname = '${orbited_host}'; Orbited.settings.streaming = true; moksha_amqp_conn = new amqp.Connection({ - host: '${amqp_broker_host}', - port: ${amqp_broker_port}, - username: '${amqp_broker_user}', - password: '${amqp_broker_pass}', % if send_hook: send_hook: function(data, frame) { ${send_hook} }, % endif % if recieve_hook: - recive_hook: function(data, frame) { ${recieve_hook} } + recive_hook: function(data, frame) { ${recieve_hook} }, % endif + host: '${amqp_broker_host}', + port: ${amqp_broker_port}, + username: '${amqp_broker_user}', + password: '${amqp_broker_pass}', }); moksha_amqp_conn.start();
commit e28e27b9b4ee2a7d07d7899d2318032d497475b7 Author: Luke Macken lmacken@redhat.com Date: Thu Dec 3 07:25:28 2009 -0500
Add an orbited_scheme to the config
diff --git a/development.ini b/development.ini index 3d692eb..449263f 100644 --- a/development.ini +++ b/development.ini @@ -16,7 +16,7 @@ error_email_from = paste@localhost
[server:main] use = egg:Paste#http -host = localhost +host = 0.0.0.0 port = 8080
[app:main] @@ -86,6 +86,7 @@ moksha.livesocket.backend = stomp # The location of our Orbited server orbited_host = localhost orbited_port = 9000 +orbited_scheme = http
# Stomp broker configuration. # By default we use the MorbidQ broker, run by Orbited, for development. @@ -94,7 +95,7 @@ stomp_port = 61613 stomp_user = guest stomp_pass = guest
-# Optional AMQP Broker. +# Optional AMQP Broker #amqp_broker = guest/guest@localhost #amqp_broker_host = localhost #amqp_broker_port = 5672
moksha-commits@lists.fedorahosted.org