changeset 919:33a5a98e9bf1

start subserver webapp with websockets, cyclone, jade, coffee Ignore-this: d0e47882e0f3edb2bcea660e612d364
author drewp@bigasterisk.com
date Mon, 10 Jun 2013 23:03:57 +0000
parents 124f4647179f
children d01b4214e5af
files bin/subserver light9/subserver/gui.coffee light9/subserver/index.jade light9/subserver/style.css makefile pydeps
diffstat 6 files changed, 127 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/bin/subserver	Mon Jun 10 20:14:27 2013 +0000
+++ b/bin/subserver	Mon Jun 10 23:03:57 2013 +0000
@@ -1,26 +1,99 @@
-# keep the database of submasters, and mix up the current client
-# requests into dmx levels for dmxserver
+#!bin/python
+"""
+live web display of all existing subs with pictures, mainly for
+dragging them into CC
+"""
+from run_local import log
+from twisted.internet import reactor
+import twisted.internet.error
+import sys, optparse, logging, json, os, subprocess
+import cyclone.web, cyclone.httpclient, cyclone.websocket
+from light9.rdfdb.syncedgraph import SyncedGraph
+import pyjade.utils
 
-class SubServe:
-    """call the server with these messages"""
-    
-    def allSubs(self):
-        """list of all the known subs"""
+try:
+    import sys
+    sys.path.append("../homeauto/lib")
+    sys.path.append("/home/drewp/projects/homeauto/lib")
+    from cycloneerr import PrettyErrorHandler
+except ImportError:
+    class PrettyErrorHandler(object):
+        pass
+        
+liveClients = set()
+def sendToLiveClients(d=None, asJson=None):
+    j = asJson or json.dumps(d)
+    for c in liveClients:
+        c.sendMessage(j)
 
-    def output(self,levels):
-        """pass a dict of {sub : level} mappings"""
+class Live(cyclone.websocket.WebSocketHandler):
+    def connectionMade(self, *args, **kwargs):
+        log.info("websocket opened")
+        liveClients.add(self)
+        self.settings.onNewClient()
+
+    def connectionLost(self, reason):
+        log.info("websocket closed")
+        liveClients.remove(self)
+
+    def messageReceived(self, message):
+        log.info("got message %s" % message)
+        self.sendMessage(message)
+        
+class Static(PrettyErrorHandler, cyclone.web.StaticFileHandler):
+    # .xhtml pages can be get() without .xhtml on them
+    def get(self, path, *args, **kw):
+        if path == '':
+            return self.respondStaticJade("light9/subserver/index.jade")
 
-def editsub
+        if path == 'gui.js':
+            return self.responseStaticCoffee('light9/subserver/gui.coffee')
+            
+        oddlyPlaced = {
+            "websocket.js":        "light9/rdfdb/web/websocket.js",
+            "jquery-1.7.2.min.js": "light9/rdfdb/web/lib/jquery-1.7.2.min.js",
+        }
+        if path in oddlyPlaced:
+            self.write(open(oddlyPlaced[path]).read())
+            return
 
+        cyclone.web.StaticFileHandler.get(self, path, *args, **kw)
+
+    def respondStaticJade(self, src):
+        html = pyjade.utils.process(open(src).read())
+        self.write(html)
 
-class SubClient:
-    """each client can receive these messages"""
+    def responseStaticCoffee(self, src):
+        self.write(subprocess.check_output([
+            '/usr/bin/coffee', '--compile', '--print', src]))
+        
+if __name__ == "__main__":
+    parser = optparse.OptionParser()
+    parser.add_option("-v", "--verbose", action="store_true",
+                      help="logging.DEBUG")
+    (options, args) = parser.parse_args()
+
+    log.setLevel(logging.DEBUG if options.verbose else logging.INFO)
+
+    graph = SyncedGraph("subserver")
+
+    d = {}
+    def updateSubs():
+        d.clear()
+        d.update({'subs':['a', 'b']})
+        sendToLiveClients(d=d)
+    def onNewClient():
+        sendToLiveClients(d=d)
+        
+    graph.addHandler(updateSubs)
     
-    def subAdded(self,newsub):
-        """sub was just added to the db"""
-
-    def subRemove(self,pastsub):
-        """this sub is about to be removed from the db"""
-
-    def subChange(self,sub):
-        """this is a new version of an existing sub"""
+    
+    port = 8052
+    reactor.listenTCP(port, cyclone.web.Application(handlers=[
+        (r'/live', Live),
+        (r'/(.*)', Static,
+         {"path" : "light9/subserver",
+          "default_filename" : "index.jade"}),
+        ], debug=True, graph=graph, onNewClient=onNewClient))
+    log.info("serving on %s" % port)
+    reactor.run()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/subserver/gui.coffee	Mon Jun 10 23:03:57 2013 +0000
@@ -0,0 +1,12 @@
+
+class Model
+  constructor: ->
+    @subs = ko.observable([])
+
+model = new Model()
+
+reconnectingWebSocket "ws://localhost:8052/live", (msg) ->
+  model.subs(msg.subs) if msg.subs?
+
+
+ko.applyBindings(model)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/subserver/index.jade	Mon Jun 10 23:03:57 2013 +0000
@@ -0,0 +1,15 @@
+doctype html
+html
+  head
+    title subserver
+    link(rel='stylesheet', href='style.css')
+  body
+    h1 subserver
+
+    div(data-bind="foreach: subs")
+      div(data-bind="text: JSON.stringify($data)")
+
+    script(src="jquery-1.7.2.min.js")
+    script(src="knockout-2.2.1.js")
+    script(src="websocket.js")
+    script(src="gui.js")
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/subserver/style.css	Mon Jun 10 23:03:57 2013 +0000
@@ -0,0 +1,3 @@
+body {
+  font-family: sans;
+}
\ No newline at end of file
--- a/makefile	Mon Jun 10 20:14:27 2013 +0000
+++ b/makefile	Mon Jun 10 23:03:57 2013 +0000
@@ -50,3 +50,6 @@
 
 gst_packages:
 	sudo aptitude install python-gi gir1.2-gst-plugins-base-1.0 libgirepository-1.0-1 gir1.2-gstreamer-1.0 gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-pulseaudio
+
+packages:
+	sudo aptitude install coffeescript
--- a/pydeps	Mon Jun 10 20:14:27 2013 +0000
+++ b/pydeps	Mon Jun 10 23:03:57 2013 +0000
@@ -13,3 +13,4 @@
 # waiting for https://github.com/xolox/python-coloredlogs/pull/1
 git+git://github.com/drewp/python-coloredlogs@9803112ddf7d4cd7dd001912ad1aa482fb8383f6
 genshi==0.7
+pyjade==2.0.2