# HG changeset patch # User drewp@bigasterisk.com # Date 2013-06-10 23:03:57 # Node ID 33a5a98e9bf174ccee55068725eeda0b09c0d2fb # Parent 124f4647179fa6c90e0c16fa64450141430dc8d3 start subserver webapp with websockets, cyclone, jade, coffee Ignore-this: d0e47882e0f3edb2bcea660e612d364 diff --git a/bin/subserver b/bin/subserver --- a/bin/subserver +++ b/bin/subserver @@ -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() diff --git a/light9/subserver/gui.coffee b/light9/subserver/gui.coffee new file mode 100644 --- /dev/null +++ b/light9/subserver/gui.coffee @@ -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 diff --git a/light9/subserver/index.jade b/light9/subserver/index.jade new file mode 100644 --- /dev/null +++ b/light9/subserver/index.jade @@ -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 diff --git a/light9/subserver/style.css b/light9/subserver/style.css new file mode 100644 --- /dev/null +++ b/light9/subserver/style.css @@ -0,0 +1,3 @@ +body { + font-family: sans; +} \ No newline at end of file diff --git a/makefile b/makefile --- a/makefile +++ b/makefile @@ -50,3 +50,6 @@ bin/ascoltami2: gst_packages link_to_sys 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 diff --git a/pydeps b/pydeps --- a/pydeps +++ b/pydeps @@ -13,3 +13,4 @@ ipdb==0.7 # 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