from __future__ import division import md5, urllib, time, sys, math, socket from sets import Set from twisted.application import internet, service from twisted.internet import task from twisted.python import log, util from twisted.python.components import registerAdapter from zope.interface import Interface import nevow from nevow import appserver from nevow import loaders, rend, static, tags as T, athena, inevow from nevow.vhost import VHostMonsterResource from louie import dispatcher from twisted.web.http import HTTPFactory def shortLog(self, request): if hasattr(self, "logFile"): # if request.uri != "/": # return line = '"%s %s" %s %s (%s)\n' % ( self._escape(request.method), self._escape(request.uri), request.code, request.sentLength or "-", self._escape(request.getHeader("referer") or "-")) self.logFile.write(line) HTTPFactory.log = shortLog position = [0, 0] # out in the ocean :) key = open("access.key").read().strip() class GpsClient(rend.Page): docFactory = loaders.xmlstr("") def renderHTTP(self, ctx): if ctx.arg('key') != key: raise ValueError("key must be set to the contents of access.key") position[:] = [float(ctx.arg('lat')), float(ctx.arg('long'))] dispatcher.send("updatePosition") return rend.Page.renderHTTP(self, ctx) class MapWatch(athena.LivePage): addSlash = True def child_(self, ctx): return MapWatch() def renderHTTP(self, ctx): self.client = inevow.IRequest(ctx).getClient() headers = inevow.IRequest(ctx).getAllHeaders() if 'x-forwarded-for' in headers: try: (self.client, _, _) = socket.gethostbyaddr(headers['x-forwarded-for']) except socket.herror: self.client = headers['x-forwarded-for'] self.displayedWatchers = [] ret = athena.LivePage.renderHTTP(self, ctx) dispatcher.connect(self.updatePosition, "client connected") dispatcher.connect(self.updatePosition, "client disconnected") dispatcher.connect(self.addMsg, "addMsg") dispatcher.send("client connected") d = self.notifyOnDisconnect() def discon(result, whichClient): dispatcher.send("client disconnected", clientJustLeft=whichClient) return result d.addErrback(discon, self) return ret def nick(self): return unicode("%s-%s" % (self.client, hex(id(self))[-4:])) def __repr__(self): return "" % self.nick() def child_gpsClient(self, ctx): return GpsClient() docFactory = loaders.xmlfile("main.html") # def __init__(self, *args, **kw): # super(MapWatch, self).__init__(*args, **kw) def locateMethod(self, ctx, methodName): # this is overridden from LivePage. # i can't figure out what iface or rootObject are for, so i'll # do my own simple dispatching meth = getattr(self, methodName) if meth.expose: return meth raise NameError("%s not exposed" % methodName) def startUpdates(self): self.updatePosition() dispatcher.connect(self.updatePosition, "updatePosition") startUpdates.expose = True def findGps(self): self.callRemote('panTo', position) findGps.expose = True def updatePosition(self, clientJustLeft=None): watchers = self.factory.clients.values() if clientJustLeft in watchers: watchers.remove(clientJustLeft) deadWatchers = self.displayedWatchers[:] for w in watchers: if w not in deadWatchers: if w not in self.displayedWatchers: d = self.callRemote('addWatcher', w.nick(), w is self) self.displayedWatchers.append(w) else: deadWatchers.remove(w) for w in deadWatchers: d = self.callRemote('removeWatcher', w.nick()) self.displayedWatchers.remove(w) self.callRemote('placeGps', position) def submitMsg(self, clientMsg): print "%s writes %s" % (self.nick(), clientMsg) dispatcher.send("addMsg", client=self, msg=clientMsg) submitMsg.expose = True def addMsg(self, client, msg): self.callRemote('addMsg', client.nick(), msg) for f in ['rings.png', 'MochiKit.js']: setattr(MapWatch, 'child_' + f, static.File(f)) print "nevow", nevow.__version__ main = MapWatch() main.putChild('vhost', VHostMonsterResource()) application = service.Application('maps') webServer = internet.TCPServer(8084, appserver.NevowSite(main)) webServer.setServiceParent(application)