diff -r 04177743b066 -r 19ebe96b41c0 runtime/NevowServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runtime/NevowServer.py Thu Feb 05 01:35:02 2015 +0100 @@ -0,0 +1,180 @@ +import os +from nevow import rend, appserver, inevow, tags, loaders, athena +from nevow.page import renderer +from twisted.python import util + +xhtml_header = ''' + +''' + +class PLCHMI(athena.LiveElement): + + initialised = False + + def HMIinitialised(self, result): + self.initialised = True + + def HMIinitialisation(self): + self.HMIinitialised(None) + +class DefaultPLCStartedHMI(PLCHMI): + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.h1["PLC IS NOW STARTED"], + ]) + +class PLCStoppedHMI(PLCHMI): + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.h1["PLC IS STOPPED"], + ]) + +class MainPage(athena.LiveElement): + jsClass = u"WebInterface.PLC" + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.div(id='content')[ + tags.div(render = tags.directive('PLCElement')), + ]]) + + def __init__(self, *a, **kw): + athena.LiveElement.__init__(self, *a, **kw) + self.pcl_state = False + self.HMI = None + self.resetPLCStartedHMI() + + def setPLCState(self, state): + self.pcl_state = state + if self.HMI is not None: + self.callRemote('updateHMI') + + def setPLCStartedHMI(self, hmi): + self.PLCStartedHMIClass = hmi + + def resetPLCStartedHMI(self): + self.PLCStartedHMIClass = DefaultPLCStartedHMI + + def getHMI(self): + return self.HMI + + def HMIexec(self, function, *args, **kwargs): + if self.HMI is not None: + getattr(self.HMI, function, lambda:None)(*args, **kwargs) + athena.expose(HMIexec) + + def resetHMI(self): + self.HMI = None + + def PLCElement(self, ctx, data): + return self.getPLCElement() + renderer(PLCElement) + + def getPLCElement(self): + self.detachFragmentChildren() + if self.pcl_state: + f = self.PLCStartedHMIClass() + else: + f = PLCStoppedHMI() + f.setFragmentParent(self) + self.HMI = f + return f + athena.expose(getPLCElement) + + def detachFragmentChildren(self): + for child in self.liveFragmentChildren[:]: + child.detach() + +class WebInterface(athena.LivePage): + + docFactory = loaders.stan([tags.raw(xhtml_header), + tags.html(xmlns="http://www.w3.org/1999/xhtml")[ + tags.head(render=tags.directive('liveglue')), + tags.body[ + tags.div[ + tags.div( render = tags.directive( "MainPage" )) + ]]]]) + MainPage = MainPage() + PLCHMI = PLCHMI + + def __init__(self, plcState=False, *a, **kw): + super(WebInterface, self).__init__(*a, **kw) + self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, 'webinterface.js') + self.plcState = plcState + self.MainPage.setPLCState(plcState) + + def getHMI(self): + return self.MainPage.getHMI() + + def LoadHMI(self, hmi, jsmodules): + for name, path in jsmodules.iteritems(): + self.jsModules.mapping[name] = os.path.join(WorkingDir, path) + self.MainPage.setPLCStartedHMI(hmi) + + def UnLoadHMI(self): + self.MainPage.resetPLCStartedHMI() + + def PLCStarted(self): + self.plcState = True + self.MainPage.setPLCState(True) + + def PLCStopped(self): + self.plcState = False + self.MainPage.setPLCState(False) + + def renderHTTP(self, ctx): + """ + Force content type to fit with SVG + """ + req = inevow.IRequest(ctx) + req.setHeader('Content-type', 'application/xhtml+xml') + return super(WebInterface, self).renderHTTP(ctx) + + def render_MainPage(self, ctx, data): + f = self.MainPage + f.setFragmentParent(self) + return ctx.tag[f] + + def child_(self, ctx): + self.MainPage.detachFragmentChildren() + return WebInterface(plcState=self.plcState) + + def beforeRender(self, ctx): + d = self.notifyOnDisconnect() + d.addErrback(self.disconnected) + + def disconnected(self, reason): + self.MainPage.resetHMI() + #print reason + #print "We will be called back when the client disconnects" + +def RegisterWebsite(reactor): + website = WebInterface() + site = appserver.NevowSite(website) + + website_port = 8009 + website_port_range = 10 + + listening = False + port_offset = 0 + while not listening and port_offset < website_port_range: + try: + reactor.listenTCP(website_port + port_offset, site) + listening = True + print "Http interface port :",website_port + port_offset + return website + except: # TODO narrow exception + port_offset += 1 + + return None + +class statuslistener: + def __init__(self, site): + self.oldstate = None + self.site = site + + def listen(self, state): + if state != self.oldstate: + {'Started': self.site.PLCStarted, + 'Stopped': self.site.PLCStopped}[state]() + self.oldstate = state + +def website_statuslistener_factory(site): + return statuslistener(site).listen