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(a)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(a)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)