minimal streaming with UI from gloda unit test
authorAndrew Sutherland <asutherland@asutherland.org>
Sun, 14 Dec 2008 04:04:03 -0800
changeset 1 1e6401f409b2277cb874f091bdb0e60f8c1168cd
parent 0 ab7bd433e928187666fd9edd0a55b3f5268312b7
child 2 0f63436107bb2f6f9a031403280927d04e2e00e9
push id1
push userbugmail@asutherland.org
push dateSun, 14 Dec 2008 17:23:57 +0000
minimal streaming with UI from gloda unit test
chrome/content/logsploder.xul
chrome/content/logviewer.css
chrome/content/logviewer.xhtml
chrome/content/viewbindings.xml
chrome/modules/gobbler.js
defaults/preferences/prefs.js
--- a/chrome/content/logsploder.xul
+++ b/chrome/content/logsploder.xul
@@ -1,7 +1,11 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 
 <window id="main" title="LogSploder" width="1024" height="768"
 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <caption label="Hello World"/>
+  <iframe id="viewerframe" flex="2"
+    src="chrome://logsploder/content/logviewer.xhtml"/>
+  <!-- 
+  <iframe id="blah" flex="1" src="chrome://global/content/console.xul"/>
+  -->
 </window>
new file mode 100644
--- /dev/null
+++ b/chrome/content/logviewer.css
@@ -0,0 +1,7 @@
+#logviewer {
+  -moz-binding: url('chrome://logsploder/content/viewbindings.xml#logviewer');
+}
+
+.logmessage {
+  -moz-binding: url('chrome://logsploder/content/viewbindings.xml#logmessage');
+}
new file mode 100644
--- /dev/null
+++ b/chrome/content/logviewer.xhtml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!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>
+    <title>Log Viewer</title>
+    <!-- 
+    <script src="chrome://visophyte/content/visophyte.js" type="application/javascript;version=1.8"/>
+    -->
+    <link rel="stylesheet"
+      href="chrome://logsploder/content/logviewer.css"
+      type="text/css" />
+    <script type="application/javascript;version=1.8">
+      const Cc = Components.classes;
+      const Ci = Components.interfaces;
+      const Cr = Components.results;
+      const Cu = Components.utils;
+
+      Cu.import("resource://logsploder/modules/gobbler.js");
+    </script>
+  </head>
+  <body bgcolor="#ffffff">
+    <canvas id="wordy" width="800" height="200"></canvas>
+    Picture above!
+    <br/>
+    <div id="logviewer"/>
+    Log crap above!
+  </body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/chrome/content/viewbindings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+
+<bindings id="viewBindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:html="http://www.w3.org/1999/xhtml"
+          xmlns:xbl="http://www.mozilla.org/xbl">
+  <binding id="logviewer">
+    <implementation>
+      <constructor><![CDATA[
+        dump("======================\n");
+        dump("document: " + document + "\n");
+        dump("this: " + this + "\n");
+        dump("Binding parent: " + document.getBindingParent(this) + "\n");
+        dump("Anonymous nodes: " + document.getAnonymousNodes(this) + "\n");
+        dump("Anonymous node 0: " + document.getAnonymousNodes(this)[0] + "\n");
+        
+        this._messageArea = document.getAnonymousElementByAttribute(this,
+          "anonid", "messagearea");
+        dump("message area: " + this._messageArea + "\n");
+        this.gobbler = new LogGobbler(this);
+        this.gobbler.start(9363);
+      ]]></constructor>
+      <method name="onLogMessage">
+        <parameter name="message"/>
+        <body><![CDATA[
+          let node = document.createElement("li");
+          node.setAttribute("class", "logmessage");
+          this._messageArea.appendChild(node);
+          node.message = message;
+        ]]></body>
+      </method>
+    </implementation>
+    <content>
+      <html:div>
+        Hello, jerky XBL world!
+      </html:div>
+      <ul anonid="messagearea" />
+    </content>
+  </binding>
+  
+  <binding id="logmessage">
+    <implementation>
+      <constructor><![CDATA[
+        //this._messageNode = document.getAnonymousElementByAttribute(this,
+        //  "anonid", "message");
+      ]]></constructor>
+      <property name="message">
+        <setter><![CDATA[
+          this._message = val;
+          
+          let messageText = "";
+          for each (let [, messageObject] in
+                    Iterator(this._message.messageObjects)) {
+            if (typeof(messageObject) != "object")
+              messageText += (messageText ? " " : "") + messageObject;
+            else if (!messageObject._isContext)
+              messageText += (messageText ? " " : "") + messageObject.toString();
+          } 
+          
+          this.textContent = messageText;
+        ]]></setter>
+      </property>
+    </implementation>
+  </binding>
+</bindings>
new file mode 100644
--- /dev/null
+++ b/chrome/modules/gobbler.js
@@ -0,0 +1,149 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Logsploder.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Messaging, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Andrew Sutherland <asutherland@asutherland.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+EXPORTED_SYMBOLS = ["LogGobbler"];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+/**
+ * Primitive incoming server base class.
+ */
+function Gobbler() {
+  this._mainThread = Cc["@mozilla.org/thread-manager;1"]
+                       .getService(Ci.nsIThreadManager).mainThread;
+  this.connections = [];
+}
+Gobbler.prototype = {
+  start: function Gobbler_start(aPort) {
+    this._socket = Cc["@mozilla.org/network/server-socket;1"]
+                     .createInstance(Ci.nsIServerSocket);
+    this._socket.init(aPort, /* local only */ true, /* default backlog */ -1);
+    this._socket.asyncListen(this);
+    dump("started!\n");
+  },
+  
+  stop: function Gobbler_stop() {
+    if (this._socket) {
+      this._socket.close();
+      this._socket = null;
+    }
+  },
+  
+  // ===== nsIServerSocketListener =====
+  onSocketAccepted: function Gobbler_onSocketAccepted(aServer, aTransport) {
+    dump("got connection!\n");
+    let inputStream = aTransport.openInputStream(0, 0, 0)
+                                .QueryInterface(Ci.nsIAsyncInputStream);
+    let conn = new this.connectionClass(this, inputStream);
+    this.connections.push(conn);
+  },
+  onStopListening: function Gobbler_onStopListening(aServer, aStatus) {
+    dump("onStopListening\n");
+  }
+};
+
+function GobblerConnection(aGobbler, aInputStream) {
+  this._gobbler = aGobbler;
+  this._inputStream = aInputStream;
+  this._scriptableInputStream = Cc["@mozilla.org/scriptableinputstream;1"]
+                                  .createInstance(Ci.nsIScriptableInputStream);
+  this._scriptableInputStream.init(this._inputStream);
+  
+  this._inputStream.asyncWait(this, 0, 0, this._gobbler._mainThread);
+  
+  this._data = "";
+}
+GobblerConnection.prototype = {
+  onInputStreamReady: function (aInputStream) {
+    try {
+      this._data += this._scriptableInputStream.read(
+          this._scriptableInputStream.available());
+    }
+    catch (ex) {
+      this.close();
+      return;
+    }
+    
+    let idxNewLine;
+    while ((idxNewline = this._data.indexOf("\r\n")) != -1) {
+      let line = this._data.substring(0, idxNewline);
+      this._data = this._data.substring(idxNewline+2);
+      this.processLine(line);
+    }
+    
+    this._inputStream.asyncWait(this, 0, 0, this._gobbler._mainThread);
+  },
+  
+  close: function () {
+    try {
+      this._scriptableInputStream.close();
+      this._inputStream.close();
+    }
+    catch (ex) {
+    }
+    this._scriptableInputStream = null;
+    this._inputStream = null;
+  }
+};
+
+/**
+ * Specialized log processing server; which is to say, we know how to create
+ *  
+ */
+function LogGobbler(aLogEventListener) {
+  Gobbler.call(this);
+  this.logEventListener = aLogEventListener;
+}
+LogGobbler.prototype = {
+  __proto__: Gobbler.prototype,
+  connectionClass: LogGobblerConnection,
+  _json: Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON),
+}
+
+function LogGobblerConnection() {
+  GobblerConnection.apply(this, arguments);
+}
+LogGobblerConnection.prototype = {
+  __proto__: GobblerConnection.prototype,
+  processLine: function LogGobblerConnection_processLine(aLine) {
+    let message = this._gobbler._json.decode(aLine);
+    this._gobbler.logEventListener.onLogMessage(message);
+  },
+};
--- a/defaults/preferences/prefs.js
+++ b/defaults/preferences/prefs.js
@@ -1,1 +1,2 @@
 pref("toolkit.defaultChromeURI", "chrome://logsploder/content/logsploder.xul");
+pref("browser.dom.window.dump.enabled", true);