Permalink
Browse files

Earliest barebones dumping of the sub socket to http, will improve soon

  • Loading branch information...
1 parent 7fee9ed commit 71002869fb4001a88bc32909de672d889908c993 @jamesgao committed Oct 12, 2010
No changes.
@@ -0,0 +1,86 @@
+""" A minimal application using the Qt console-style IPython frontend.
+"""
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Local imports
+from IPython.external.argparse import ArgumentParser
+from IPython.frontend.html.kernelmanager import HttpKernelManager, \
+ IPyHttpServer, IPyHttpHandler
+
+#-----------------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------------
+
+LOCALHOST = '127.0.0.1'
+
+#-----------------------------------------------------------------------------
+# Main entry point
+#-----------------------------------------------------------------------------
+
+def main():
+ """ Entry point for application.
+ """
+ # Parse command line arguments.
+ parser = ArgumentParser()
+ kgroup = parser.add_argument_group('kernel options')
+ kgroup.add_argument('-e', '--existing', action='store_true',
+ help='connect to an existing kernel')
+ kgroup.add_argument('--ip', type=str, default=LOCALHOST,
+ help='set the kernel\'s IP address [default localhost]')
+ kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
+ help='set the XREQ channel port [default random]')
+ kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
+ help='set the SUB channel port [default random]')
+ kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
+ help='set the REP channel port [default random]')
+ kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
+ help='set the heartbeat port [default: random]')
+
+ egroup = kgroup.add_mutually_exclusive_group()
+ egroup.add_argument('--pure', action='store_true', help = \
+ 'use a pure Python kernel instead of an IPython kernel')
+ egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
+ const='auto', help = \
+ "Pre-load matplotlib and numpy for interactive use. If GUI is not \
+ given, the GUI backend is matplotlib's, otherwise use one of: \
+ ['tk', 'gtk', 'qt', 'wx', 'inline'].")
+
+ wgroup = parser.add_argument_group('widget options')
+ wgroup.add_argument('--paging', type=str, default='inside',
+ choices = ['inside', 'hsplit', 'vsplit', 'none'],
+ help='set the paging style [default inside]')
+ wgroup.add_argument('--rich', action='store_true',
+ help='enable rich text support')
+ wgroup.add_argument('--gui-completion', action='store_true',
+ help='use a GUI widget for tab completion')
+
+ args = parser.parse_args()
+
+ # Don't let Qt or ZMQ swallow KeyboardInterupts.
+ import signal
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+ # Create a KernelManager and start a kernel.
+ kernel_manager = HttpKernelManager(xreq_address=(args.ip, args.xreq),
+ sub_address=(args.ip, args.sub),
+ rep_address=(args.ip, args.rep),
+ hb_address=(args.ip, args.hb))
+ if args.ip == LOCALHOST and not args.existing:
+ if args.pure:
+ kernel_manager.start_kernel(ipython=False)
+ elif args.pylab:
+ kernel_manager.start_kernel(pylab=args.pylab)
+ else:
+ kernel_manager.start_kernel()
+ kernel_manager.start_channels()
+
+ #Start the web server
+ server = IPyHttpServer((args.ip, 8080), IPyHttpHandler)
+ server.serve_forever()
+
+
+if __name__ == '__main__':
+ main()
@@ -4,8 +4,62 @@
from IPython.utils.traitlets import Type
from IPython.zmq.kernelmanager import KernelManager, SubSocketChannel, \
XReqSocketChannel, RepSocketChannel, HBSocketChannel
+
+import time
+import json
+import Queue
+import threading
+from string import Template
+from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+class CometManager(object):
+ def __init__(self):
+ self.clients = {}
+
+ def register(self, client_id):
+ self.clients[client_id] = Queue.Queue()
+
+ def get(self, client_id):
+ return self.clients[client_id].get()
+
+ def append(self, msg):
+ for q in self.clients.values():
+ q.put(msg)
+
+ def __contains__(self, item):
+ return item in self.clients
+
+manager = CometManager()
+
+class IPyHttpHandler(BaseHTTPRequestHandler):
+ def do_GET(self):
+ client_id = self.path.strip("/")
+ if self.path == "/notebook":
+ self.send_response(200)
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+
+ client_id = str(time.time())
+ manager.register(client_id)
+ page_text = Template(open("notebook.html").read())
+
+ self.wfile.write(page_text.safe_substitute(client_id = client_id))
+ elif client_id in manager:
+ self.send_response(200)
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+
+ #Manager.get blocks until a message is available
+ msg = json.dumps(manager.get(client_id))
+ self.wfile.write(msg)
+ else:
+ self.send_response(404)
+ self.end_headers()
+
+class IPyHttpServer(ThreadingMixIn, HTTPServer):
+ pass
+
class HttpXReqSocketChannel(XReqSocketChannel):
# Used by the first_reply signal logic to determine if a reply is the
# first.
@@ -18,17 +72,7 @@ class HttpXReqSocketChannel(XReqSocketChannel):
def call_handlers(self, msg):
""" Reimplemented to emit signals instead of making callbacks.
"""
- # Emit the generic signal.
- self.message_received.emit(msg)
-
- # Emit signals for specialized message types.
- msg_type = msg['msg_type']
- signal = getattr(self, msg_type, None)
- if signal:
- signal.emit(msg)
-
if not self._handlers_called:
- self.first_reply.emit()
self._handlers_called = True
#---------------------------------------------------------------------------
@@ -41,49 +85,28 @@ def reset_first_reply(self):
self._handlers_called = False
-class HttpSubSocketChannel(SocketChannelQObject, SubSocketChannel):
-
+class HttpSubSocketChannel(SubSocketChannel):
#---------------------------------------------------------------------------
# 'SubSocketChannel' interface
#---------------------------------------------------------------------------
def call_handlers(self, msg):
""" Reimplemented to emit signals instead of making callbacks.
"""
-
- # Emit signals for specialized message types.
- msg_type = msg['msg_type']
- signal = getattr(self, msg_type + '_received', None)
- if signal:
- signal.emit(msg)
- elif msg_type in ('stdout', 'stderr'):
- self.stream_received.emit(msg)
-
- def flush(self):
- """ Reimplemented to ensure that signals are dispatched immediately.
- """
- super(HttpSubSocketChannel, self).flush()
-
-
-class HttpRepSocketChannel(SocketChannelQObject, RepSocketChannel):
+ manager.append(msg)
+class HttpRepSocketChannel(RepSocketChannel):
#---------------------------------------------------------------------------
# 'RepSocketChannel' interface
#---------------------------------------------------------------------------
def call_handlers(self, msg):
""" Reimplemented to emit signals instead of making callbacks.
"""
- # Emit the generic signal.
- self.message_received.emit(msg)
-
- # Emit signals for specialized message types.
- msg_type = msg['msg_type']
- if msg_type == 'input_request':
- self.input_requested.emit(msg)
+ pass
-class HttpHBSocketChannel(SocketChannelQObject, HBSocketChannel):
+class HttpHBSocketChannel(HBSocketChannel):
#---------------------------------------------------------------------------
# 'HBSocketChannel' interface
#---------------------------------------------------------------------------
@@ -92,10 +115,10 @@ def call_handlers(self, since_last_heartbeat):
""" Reimplemented to emit signals instead of making callbacks.
"""
# Emit the generic signal.
- self.kernel_died.emit(since_last_heartbeat)
+ pass
-class HttpKernelManager(KernelManager, SuperQObject):
+class HttpKernelManager(KernelManager):
""" A KernelManager that provides signals and slots.
"""
@@ -105,36 +128,3 @@ class HttpKernelManager(KernelManager, SuperQObject):
rep_channel_class = Type(HttpRepSocketChannel)
hb_channel_class = Type(HttpHBSocketChannel)
- #---------------------------------------------------------------------------
- # 'KernelManager' interface
- #---------------------------------------------------------------------------
-
- #------ Kernel process management ------------------------------------------
-
- def start_kernel(self, *args, **kw):
- """ Reimplemented for proper heartbeat management.
- """
- if self._xreq_channel is not None:
- self._xreq_channel.reset_first_reply()
- super(HttpKernelManager, self).start_kernel(*args, **kw)
-
- @property
- def xreq_channel(self):
- """ Reimplemented for proper heartbeat management.
- """
- if self._xreq_channel is None:
- self._xreq_channel = super(HttpKernelManager, self).xreq_channel
- self._xreq_channel.first_reply.connect(self._first_reply)
- return self._xreq_channel
-
- #---------------------------------------------------------------------------
- # Protected interface
- #---------------------------------------------------------------------------
-
- def _first_reply(self):
- """ Unpauses the heartbeat channel when the first reply is received on
- the execute channel. Note that this will *not* start the heartbeat
- channel if it is not already running!
- """
- if self._hb_channel is not None:
- self._hb_channel.unpause()
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>AJAX test</title>
+ <script type="text/javascript" src="http://www/~james/js/jquery.js"></script>
+ <script type="text/javascript">
+ client_id = "/$client_id";
+ $.ajaxSetup({
+ url:client_id,
+ dataType:"json"
+ })
+ function comet() {
+ $.ajax({
+ success: function(json, status, request) {
+ msg = ""
+ if (json.msg_type == "stream")
+ msg += json.content.data
+ else if (json.msg_type == "pyin")
+ msg += json.content.code
+
+ $("#messages").append("<pre>"+msg+"</pre>")
+ comet()
+ }
+ })
+ }
+ $(document).ready(function() {
+ comet()
+ })
+ </script>
+ </head>
+ <body>
+ <div id="messages"></div>
+ </body>
+</html>

0 comments on commit 7100286

Please sign in to comment.