moksha/commands/cli.py | 2 - moksha/controllers/root.py | 36 +++++++++++++++++- moksha/templates/amqp_socket.mak | 76 ++++++++++++++++++++++++++++++++++++++ moksha/templates/stomp_socket.mak | 73 ++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 2 deletions(-)
New commits: commit 077f29f1ffffcf96e6e57bf0e9ca1031a99d090a Author: Luke Macken lmacken@redhat.com Date: Thu Oct 21 12:45:58 2010 -0400
Initial implementation of stand-alone moksha live sockets.
This can be used for injecting live sockets into static html pages.
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py index 51ec227..2f2e397 100644 --- a/moksha/controllers/root.py +++ b/moksha/controllers/root.py @@ -19,8 +19,9 @@ import moksha import pylons
-from tg import url +from tg import url, config from tg import expose, flash, tmpl_context, redirect +from tg.decorators import override_template from pylons.i18n import ugettext as _
from moksha.lib.base import BaseController @@ -57,6 +58,39 @@ class RootController(BaseController): # moksha.root entry-point, then redirect to a moksha logo return DefaultRootController(), remainder
+ @expose() + def livesocket(self, topic=None, callback=None): + """Returns a raw Moksha live socket, for use in non-Moksha apps. + + <script> function bar(msg) { alert('bar(' + msg + ')'); } </script> + <script type="text/javascript" src="http://localhost:8080/livesocket?topic=foo&callback=bar"> </script> + + """ + data = {'topic': topic, 'callback': callback} + backend = config.get('moksha.livesocket.backend', 'stomp').lower() + if backend == 'stomp': + override_template(self.livesocket, 'mako:moksha.templates.stomp_socket') + data['stomp_host'] = config.get('stomp_host', 'localhost') + data['stomp_port'] = config.get('stomp_port', 61613) + data['stomp_user'] = config.get('stomp_user', 'guest') + data['stomp_pass'] = config.get('stomp_pass', 'guest') + elif backend == 'amqp': + override_template(self.livesocket, 'mako:moksha.templates.amqp_socket') + data['amqp_broker_host'] = config.get('amqp_broker_host', 'localhost') + data['amqp_broker_port'] = config.get('amqp_broker_port', 5672) + data['amqp_broker_user'] = config.get('amqp_broker_user', 'guest') + data['amqp_broker_pass'] = config.get('amqp_broker_pass', 'guest') + # TODO: dynamic widget url + # 'toscawidgets.prefix': '/toscawidgets', + + data['orbited_host'] = config.get('orbited_host', 'localhost') + data['orbited_port'] = config.get('orbited_port', 9000) + data['orbited_scheme'] = config.get('orbited_scheme', 'http') + data['orbited_url'] = '%s://%s:%s' % (data['orbited_scheme'], + data['orbited_host'], data['orbited_port']) + + return data + @expose('mako:moksha.templates.login') def login(self, came_from=None): """Start the user login.""" diff --git a/moksha/templates/amqp_socket.mak b/moksha/templates/amqp_socket.mak new file mode 100644 index 0000000..9e8bb6f --- /dev/null +++ b/moksha/templates/amqp_socket.mak @@ -0,0 +1,76 @@ +if (typeof moksha_amqp_conn == 'undefined') { + moksha_callbacks = new Object(); + moksha_amqp_remote_queue = null; + moksha_amqp_queue = null; + moksha_amqp_on_message = function(msg) { + var dest = msg.header.delivery_properties.routing_key; + if (moksha_callbacks[dest]) { + for (var i=0; i < moksha_callbacks[dest].length; i++) { + moksha_callbacks[dest][i](msg.body); + } + } + } +} + +## Register our topic callbacks +var topic = "${topic}"; +if (!moksha_callbacks[topic]) { + moksha_callbacks[topic] = []; +} +moksha_callbacks[topic].push(function(frame) { + ${callback}(frame); +}); + +## Create a new AMQP client +if (typeof moksha_amqp_conn == 'undefined') { + document.domain = document.domain; + $.getScript("${orbited_url}/static/Orbited.js", function() { + Orbited.settings.port = ${orbited_port}; + Orbited.settings.hostname = '${orbited_host}'; + Orbited.settings.streaming = true; + $.getScript('/toscawidgets/resources/moksha.api.widgets.amqp.widgets/static/amqp.protocol.js', function() { + $.getScript('/toscawidgets/resources/moksha.api.widgets.amqp.widgets/static/amqp.protocol_0_10.js', function() { + $.getScript('/toscawidgets/resources/moksha.api.widgets.amqp.widgets/static/qpid_amqp.js', function() { + moksha_amqp_conn = new amqp.Connection({ + host: '${amqp_broker_host}', + port: ${amqp_broker_port}, + username: '${amqp_broker_user}', + password: '${amqp_broker_pass}', + }); + moksha_amqp_conn.start(); + + moksha_amqp_session = moksha_amqp_conn.create_session( + 'moksha_socket_' + (new Date().getTime() + Math.random())); + + moksha_amqp_remote_queue = 'moksha_socket_queue_' + + moksha_amqp_session.name; + + moksha_amqp_session.Queue('declare', { + queue: moksha_amqp_remote_queue + }); + moksha_amqp_queue = moksha_amqp_session.create_local_queue({ + name: 'local_queue' + }); + + moksha_amqp_queue.subscribe({ + exchange: 'amq.topic', + remote_queue: moksha_amqp_remote_queue, + binding_key: '${topic}', + callback: moksha_amqp_on_message, + }); + + moksha_amqp_queue.start(); + }); + }); + }); + }); +} else { + ## Utilize the existing Moksha AMQP socket connection + moksha_amqp_queue.subscribe({ + exchange: 'amq.topic', + remote_queue: moksha_amqp_remote_queue, + binding_key: '${topic}', + callback: moksha_amqp_on_message, + }); + moksha_amqp_queue.start(); +} diff --git a/moksha/templates/stomp_socket.mak b/moksha/templates/stomp_socket.mak new file mode 100644 index 0000000..e4eb0cd --- /dev/null +++ b/moksha/templates/stomp_socket.mak @@ -0,0 +1,73 @@ +if (typeof TCPSocket == 'undefined') { + moksha_callbacks = new Object(); + moksha_socket_busy = false; +} + +## Register our topic callbacks +var topic = "${topic}"; +if (!moksha_callbacks[topic]) { + moksha_callbacks[topic] = []; +} +moksha_callbacks[topic].push(function(frame) { + ${callback}(frame); +}); + +if (typeof TCPSocket == 'undefined') { + document.domain = document.domain; + moksha_socket_busy = true; + $.getScript("${orbited_url}/static/Orbited.js", function(){ + Orbited.settings.port = ${orbited_port}; + Orbited.settings.hostname = '${orbited_host}'; + Orbited.settings.streaming = true; + TCPSocket = Orbited.TCPSocket; + $.getScript("${orbited_url}/static/protocols/stomp/stomp.js", function(){ + ## Create a new TCPSocket & Stomp client + stomp = new STOMPClient(); + stomp.onopen = function(){}; + stomp.onclose = function(c){}; + stomp.onerror = function(error){}; + stomp.onerrorframe = function(f){}; + stomp.onconnectedframe = function(){ + moksha_socket_busy = false; + $('body').triggerHandler('moksha.socket_ready'); + stomp.subscribe('${topic}') + }; + stomp.onmessageframe = function(f){ + var dest = f.headers.destination; +/* + var json = null; + try { + var json = $.parseJSON(f.body); + } catch(err) { + console.log("Unable to decode JSON message body:"); + console.log(f.body); + } +*/ + if (moksha_callbacks[dest]) { + for (var i=0; i < moksha_callbacks[dest].length; i++) { + moksha_callbacks[dest][i](f.body); + } + } + }; + + stomp.connect('${stomp_host}', ${stomp_port}, + '${stomp_user}', '${stomp_pass}'); + }); + }); + +} else { + ## Utilize the existing stomp connection + if (moksha_socket_busy) { + $('body').bind('moksha.socket_ready', function() { + stomp.subscribe('${topic}') + }); + } else { + stomp.subscribe('${topic}') + } +} + +window.onbeforeunload = function() { + if (typeof stomp != 'undefined') { + stomp.reset(); + } +}
commit 13b40da646d1b0af801dde8716d295934c881aca Author: Luke Macken lmacken@redhat.com Date: Thu Oct 21 12:45:31 2010 -0400
Minor CLI output tweak
diff --git a/moksha/commands/cli.py b/moksha/commands/cli.py index f44ce2d..1f72713 100755 --- a/moksha/commands/cli.py +++ b/moksha/commands/cli.py @@ -45,7 +45,7 @@ class MokshaCLI(object):
def _exec(self, process, *args, **kw): args = args and [process] + list(args) or [process] - print "Running %s %s" % (process, ' '.join(args)) + print "Running %s %s" % ' '.join(args) pp = MokshaProcessProtocol(name=process) process = reactor.spawnProcess(pp, process, args, env={'PYTHONPATH': os.getcwd()}, **kw)
moksha-commits@lists.fedorahosted.org