Permalink
Browse files

Finally making better javascript tracking, looks more like ipython now

  • Loading branch information...
james authored and jamesgao committed Oct 14, 2010
1 parent d5a3490 commit ddffe2b9911e6c919f3418c139f6dbc08cd30d7f
@@ -6,6 +6,7 @@
#-----------------------------------------------------------------------------
# Local imports
+import os
from IPython.external.argparse import ArgumentParser
from IPython.frontend.html.kernelmanager import HttpKernelManager, \
IPyHttpServer, IPyHttpHandler
@@ -78,9 +79,9 @@ def main():
kernel_manager.start_channels()
#Start the web server
+ os.system("xdg-open http://localhost:8080/notebook")
server = IPyHttpServer((args.ip, 8080), IPyHttpHandler)
server.serve_forever()
-
if __name__ == '__main__':
main()
@@ -0,0 +1,128 @@
+function fixConsole(txt) {
+ //Fixes escaped console commands, IE colors. Turns them into HTML
+ //Unfortunately, the "semantics" of html and console are very
+ //different, so fancy things *will* break
+ var attrib = {"30":"cblack", "31":"cred","32":"cgreen", "34":"cblue", "01":"cbold"}
+ txt = txt.replace("<","&lt;").replace(">", "&gt;")
+ //Must remove first \033[0m to eliminate pairing errors
+// txt = txt.replace(/\033\[0m/, "")
+ //Phase 1: substitute <span> for html
+ var re = /\033\[([\d;]+?)m(.*?)\033\[0m/g
+ txt = txt.replace(re, "<span class='[[$1]]'>$2</span>")
+ //Phase 2: substitute class in span with correct attributes
+ re = /\[\[([\d;]+?)\]\]/
+ while (re.test(txt)) {
+ var match = re.exec(txt)
+ var cmds = match[1].split(";")
+ var reps = []
+ for (var j in cmds)
+ reps.push(attrib[cmds[j]])
+ txt = txt.replace( match[0], reps.join(" ") )
+ }
+ return txt
+}
+function comet() {
+ $.ajax({
+ success: function(json, status, request) {
+ comet()
+ var msg = manager.get(json.parent_header.msg_id)
+ if (json.msg_type == "status") {
+ statusbar.set(json.content.execute_state)
+ } else if (json.msg_type == "stream") {
+ msg.setOutput(fixConsole(json.content.data))
+ } else if (json.msg_type == "pyin") {
+ msg.setInput(json.content.code)
+ } else if (json.msg_type == "pyout") {
+ msg.setOutput(json.content.data, true)
+ } else if (json.msg_type == "pyerr") {
+ msg.setOutput(fixConsole(json.content.traceback.join("\n")))
+ }
+ }
+ })
+}
+function heartbeat() {
+ $.ajax({
+ type: "POST",
+ data: {client_id:client_id, type:"heartbeat"},
+ success: function() {
+ setTimeout(heartbeat, 10000)
+ }
+ })
+}
+function execute(code) {
+ $.ajax({
+ type: "POST",
+ data: {type:"execute", code:code},
+ success: function(json, status, request) {
+ exec_count = json.content.execution_count
+// $("#messages").append("<pre class='headers xreq'>"+inspect(json)+"</pre>")
+ }
+ })
+}
+function inspect(obj) {
+ if (obj instanceof Object) {
+ var str = []
+ for (var i in obj)
+ str.push(i+": "+inspect(obj[i]).replace("\n", "\n\t"))
+ return "{\n\t"+str.join("\n\t")+"\n}\n"
+ } else {
+ try {
+ return obj.toString()
+ } catch (e) {
+ }
+ return ""
+ }
+}
+
+function StatusBar(obj) {
+ $("#"+obj).append("<span class='txt'></span>")
+ $("#"+obj).append("<span class='bullet'>&#8226;</span>")
+ this.text = $("#"+obj+" .txt")
+ this.bullet = $("#"+obj+" .bullet")
+}
+StatusBar.prototype.map = { "idle":"cgreen", "busy":"cyellow", "dead":"cred" }
+StatusBar.prototype.set = function(status) {
+ this.bullet.removeClass()
+ this.bullet.addClass("bullet "+this.map[status])
+ this.text.text(status)
+}
+
+
+function Manager(obj) {
+ this.messages = {}
+ this.obj = "#"+obj
+}
+Manager.prototype.get = function (msg_id) {
+ if (typeof(this.messages[msg_id]) == "undefined") {
+ this.messages[msg_id] = new Message(msg_id, this.obj)
+ }
+ return this.messages[msg_id]
+}
+function Message(msg_id, obj) {
+ this.num = exec_count
+ $(obj).append("<div id='msg_"+msg_id+"' class='message'></div>")
+ this.obj = $(obj+" #msg_"+msg_id)
+
+ this.in_head = "<div class='input_header'>In [<span class='cbold'>"
+ this.in_head += this.num+"</span>]:</div>"
+ this.obj.append(this.in_head)
+ this.in_head = $(obj+" #msg_"+msg_id +" .input_header")
+ this.obj.append("<pre class='input'></pre><div class='clear'></div>")
+ this.input = $(obj+" #msg_"+msg_id +" .input")
+
+ this.out_head = "<div class='output_header'></div>"
+ this.obj.append(this.out_head)
+ this.out_head = $(obj+" #msg_"+msg_id +" .output_header")
+ this.obj.append("<pre class='output'></pre><div class='clear'></div>")
+ this.output = $(obj+" #msg_"+msg_id +" .output")
+}
+Message.prototype.setInput = function(value) {
+ this.input.text(value)
+}
+Message.prototype.setOutput = function(value, header) {
+ if (header) {
+ var o = "Out [<span class='cbold'>"+this.num+"</span>]:"
+ this.out_head.html(o)
+ }
+ this.output.html(this.output.html() + value)
+}
@@ -7,6 +7,7 @@
import json
import Queue
import threading
+import mimetypes
from string import Template
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
@@ -17,6 +18,7 @@ class CometManager(object):
"""Tracks msg_id, client get requests for the Comet design pattern"""
def __init__(self):
self.clients = {}
+ self.req_queue = Queue.Queue()
def register(self, client_id):
self.clients[client_id] = [time.time(), Queue.Queue()]
@@ -42,7 +44,13 @@ def heartbeat(self, client_id):
self.clients[client_id][0] = time.time()
def send(self, msg_type, *args):
- return self.kernel_manager.xreq_channel.execute(*args)
+ if msg_type == "connect_request":
+ args = ("",)
+ self.kernel_manager.xreq_channel.execute(*args)
+ return self.req_queue.get()
+
+ def addreq(self, msg):
+ self.req_queue.put(msg)
manager = CometManager()
@@ -70,7 +78,8 @@ def do_GET(self):
self.wfile.write(page_text.safe_substitute(client_id = client_id))
elif os.path.exists(path):
self.send_response(200)
- self.send_header("Content-type", "text/html")
+ mime = mimetypes.guess_type(path)[0]
+ self.send_header("Content-type", mime)
self.end_headers()
self.wfile.write(open(path).read())
@@ -95,7 +104,12 @@ def do_POST(self):
manager.heartbeat(client_id)
elif msg_type == "execute":
response = manager.send("execute_request", data["code"].value)
- self.wfile.write(response)
+ json.dump(response, self.wfile)
+ elif msg_type == "complete":
+ pass
+ elif msg_type == "connect":
+ response = manager.send("connect_request")
+ json.dump(response, self.wfile)
class IPyHttpServer(ThreadingMixIn, HTTPServer):
pass
@@ -120,6 +134,7 @@ def call_handlers(self, msg):
"""
if not self._handlers_called:
self._handlers_called = True
+ manager.addreq(msg)
#---------------------------------------------------------------------------
# 'HttpXReqSocketChannel' interface
@@ -5,71 +5,51 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>AJAX test</title>
<style type="text/css">
+ pre, p { margin:0px; }
.cblue { color: blue }
.cgreen { color: green }
+ .cyellow { color: yellow }
.cred { color: red }
.cbold { font-weight:bold }
+ .hidden { display:none; }
+ .clear { clear:both; }
+
+ .headers { font-size:60%; display:none;}
+ .xreq { font-style:italic }
+
+ #statusbar { float:right; width:20%;}
+ #statusbar span { vertical-align:middle; }
+ #statusbar .bullet {
+ font-size:150%;
+ margin-left:10px;
+ float:right;
+ }
+ .message {
+ margin:2px;
+ font-family:sans-serif;
+ font-size:10pt;
+ }
+ .message .input_header {
+ color:blue;
+ float:left;
+ width:80px;
+ }
+ .message .input { float:left; }
+ .message .output_header {
+ color:red;
+ float:left;
+ width:80px;
+ }
+ .message .output { float:left; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+ <script type="text/javascript" src="js/notebook.js"></script>
<script type="text/javascript">
client_id = "/$client_id";
$.ajaxSetup({
url: client_id,
dataType: "json"
})
- function fixConsole(txt) {
- //Fixes escaped console commands, IE colors. Turns them into HTML
- //Unfortunately, the "semantics" of html and console are very
- //different, so fancy things *will* break
- var attrib = {"30":"cblack", "31":"cred","32":"cgreen", "34":"cblue", "01":"cbold"}
- //Must remove first \033[0m to eliminate pairing errors
- txt = txt.replace(/\033\[0m/, "")
- //Phase 1: substitute <span> for html
- var re = /\033\[([\d;]+?)m(.*?)\033\[0m/g
- txt = txt.replace(re, "<span class='[[$1]]'>$2</span>")
- //Phase 2: substitute class in span with correct attributes
- re = /\[\[([\d;]+?)\]\]/
- while (re.test(txt)) {
- var match = re.exec(txt)
- var cmds = match[1].split(";")
- var reps = []
- for (var j in cmds)
- reps.push(attrib[cmds[j]])
- txt = txt.replace( match[0], reps.join(" ") )
- }
- return txt
- }
- function comet() {
- $.ajax({
- success: function(json, status, request) {
- msg = json.msg_type+": "
- if (json.msg_type == "stream")
- msg += fixConsole(json.content.data)
- else if (json.msg_type == "pyin")
- msg += json.content.code
- else if (json.msg_type == "pyout")
- msg += json.content.data
-
- $("#messages").append("<pre>"+msg+"</pre>")
- comet()
- }
- })
- }
- function heartbeat() {
- $.ajax({
- type: "POST",
- data: {client_id:client_id, type:"heartbeat"},
- success: function() {
- setTimeout(heartbeat, 10000)
- }
- })
- }
- function execute(code) {
- $.ajax({
- type: "POST",
- data: {type:"execute", code:code}
- })
- }
$(document).ready(function() {
comet()
heartbeat()
@@ -79,11 +59,24 @@
e.target.value = ""
}
})
+ //Startup POST, set some globals
+ $.ajax({
+ type: "POST",
+ data: {type:"connect"},
+ success: function(json, status, request) {
+ username = json.parent_header.username
+ session = json.parent_header.session
+ exec_count = json.content.execution_count
+ }
+ })
+ manager = new Manager("messages")
+ statusbar = new StatusBar("statusbar")
})
</script>
</head>
<body>
<div id="messages"></div>
<input id="exec" style="width:100%" />
+ <div id="statusbar"></div>
</body>
</html>

0 comments on commit ddffe2b

Please sign in to comment.