From: Felix Domke Date: Fri, 14 Jul 2006 16:56:31 +0000 (+0000) Subject: add proof-of-concept web interface X-Git-Tag: 2.6.0~3166 X-Git-Url: https://git.cweiske.de/enigma2.git/commitdiff_plain/1430fa61856eb2f52e1f59b2fd7cda01f6f0405b add proof-of-concept web interface --- diff --git a/lib/python/Plugins/Extensions/WebInterface/Makefile.am b/lib/python/Plugins/Extensions/WebInterface/Makefile.am index dffb8d07..d3943bd3 100644 --- a/lib/python/Plugins/Extensions/WebInterface/Makefile.am +++ b/lib/python/Plugins/Extensions/WebInterface/Makefile.am @@ -2,6 +2,4 @@ installdir = $(LIBDIR)/enigma2/python/Plugins/Extensions/WebInterface install_PYTHON = \ __init__.py \ - plugin.py - - \ No newline at end of file + plugin.py xmlrpc.py webif.py *.xml diff --git a/lib/python/Plugins/Extensions/WebInterface/plugin.py b/lib/python/Plugins/Extensions/WebInterface/plugin.py index 0f7e2bbd..c61424c8 100644 --- a/lib/python/Plugins/Extensions/WebInterface/plugin.py +++ b/lib/python/Plugins/Extensions/WebInterface/plugin.py @@ -1,14 +1,41 @@ from Plugins.Plugin import PluginDescriptor +sessions = [ ] + def startWebserver(): from twisted.internet import reactor - from twisted.web2 import server, http, static - toplevel = static.File("/hdd") - site = server.Site(toplevel) + from twisted.web2 import server, http, static, resource, stream + import webif + + class ScreenPage(resource.Resource): + def render(self, req): + global sessions + if sessions == [ ]: + return http.Response("please wait until enigma has booted") + + s = stream.ProducerStream() + webif.renderPage(s, req, sessions[0]) # login? + return http.Response(stream=s) + + class Toplevel(resource.Resource): + addSlash = True + + def render(self, req): + return 'Hello! you want probably go to the test instead.' + + child_test = ScreenPage() # "/test" + child_hdd = static.File("/hdd") + + site = server.Site(Toplevel()) reactor.listenTCP(80, http.HTTPFactory(site)) def autostart(reason, **kwargs): + if "session" in kwargs: + global sessions + sessions.append(kwargs["session"]) + return + if reason == 0: try: startWebserver() @@ -16,4 +43,4 @@ def autostart(reason, **kwargs): print "twisted not available, not starting web services" def Plugins(**kwargs): - return PluginDescriptor(where = PluginDescriptor.WHERE_AUTOSTART, fnc = autostart) + return PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart) diff --git a/lib/python/Plugins/Extensions/WebInterface/test.xml b/lib/python/Plugins/Extensions/WebInterface/test.xml new file mode 100644 index 00000000..e69de29b diff --git a/lib/python/Plugins/Extensions/WebInterface/webif.py b/lib/python/Plugins/Extensions/WebInterface/webif.py new file mode 100644 index 00000000..6025a2e2 --- /dev/null +++ b/lib/python/Plugins/Extensions/WebInterface/webif.py @@ -0,0 +1,185 @@ +# +# OK, this is more a proof of concept +# things to improve: +# - nicer code +# - screens need to be defined somehow else. +# I don't know how, yet. Probably each in an own file. +# - more components, like the channellist +# - better error handling +# - use namespace parser + +from Screens.Screen import Screen +from Tools.Import import my_import + +# for our testscreen +from Screens.InfoBarGenerics import InfoBarServiceName, InfoBarEvent +from Components.Sources.Clock import Clock + +from xml.sax import make_parser +from xml.sax.handler import ContentHandler, feature_namespaces +from twisted.python import util +import sys +import time + +# prototype of the new web frontend template system. + +# a test screen +class TestScreen(InfoBarServiceName, InfoBarEvent, Screen): + def __init__(self, session): + Screen.__init__(self, session) + InfoBarServiceName.__init__(self) + InfoBarEvent.__init__(self) + self["CurrentTime"] = Clock() + +# turns .text into __str__ +class Element: + def __init__(self, source): + self.source = source + + def __str__(self): + return self.source.text + +# a to-be-filled list item +class ListItem: + def __init__(self, name): + self.name = name + +# the performant 'listfiller'-engine (plfe) +class ListFiller(object): + def __init__(self, arg): + self.template = arg + + def getText(self): + l = self.source.list + lut = self.source.lut + + # now build a ["string", 1, "string", 2]-styled list, with indices into the + # list to avoid lookup of item name for each entry + lutlist = [] + for element in self.template: + if isinstance(element, str): + lutlist.append(element) + elif isinstance(element, ListItem): + lutlist.append(lut[element.name]) + + # now, for the huge list, do: + res = "" + for item in l: + for element in lutlist: + if isinstance(element, str): + res += element + else: + res += str(item[element]) + # (this will be done in c++ later!) + return res + + text = property(getText) + +class webifHandler(ContentHandler): + def __init__(self, session): + self.res = [ ] + self.mode = 0 + self.screen = None + self.session = session + + def startElement(self, name, attrs): + if name == "e2:screen": + self.screen = eval(attrs["name"])(self.session) # fixme + return + + if name[:3] == "e2:": + self.mode += 1 + + tag = "<" + name + ''.join([' ' + key + '="' + val + '"' for (key, val) in attrs.items()]) + ">" + tag = tag.encode("UTF-8") + + if self.mode == 0: + self.res.append(tag) + elif self.mode == 1: # expect "" + assert name == "e2:element", "found %s instead of e2:element" % name + self.source = self.screen[attrs["source"]] + elif self.mode == 2: # expect "" + if name[:3] == "e2:": + assert name == "e2:convert" + + ctype = attrs["type"] + if ctype[:4] == "web:": # for now + self.converter = eval(ctype[4:]) + else: + self.converter = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype) + self.sub = [ ] + else: + self.sub.append(tag) + elif self.mode == 3: + assert name == "e2:item", "found %s instead of e2:item!" % name + self.sub.append(ListItem(attrs["name"])) + + def endElement(self, name): + if name == "e2:screen": + self.screen = None + return + + tag = "" + if self.mode == 0: + self.res.append(tag) + elif self.mode == 2 and name[:3] != "e2:": + self.sub.append(tag) + elif self.mode == 2: # closed 'convert' -> sub + self.sub = lreduce(self.sub) + if len(self.sub) == 1: + self.sub = self.sub[0] + c = self.converter(self.sub) + c.connect(self.source) + self.source = c + + del self.sub + elif self.mode == 1: # closed 'element' + self.res.append(Element(self.source)) + del self.source + + if name[:3] == "e2:": + self.mode -= 1 + + def processingInstruction(self, target, data): + self.res.append('') + + def characters(self, ch): + ch = ch.encode("UTF-8") + if self.mode == 0: + self.res.append(ch) + elif self.mode == 2: + self.sub.append(ch) + + def startEntity(self, name): + self.res.append('&' + name + ';'); + +def lreduce(list): + # ouch, can be made better + res = [ ] + string = None + for x in list: + if isinstance(x, str) or isinstance(x, unicode): + x = x.encode("UTF-8") + if string is None: + string = x + else: + string += x + else: + if string is not None: + res.append(string) + string = None + res.append(x) + if string is not None: + res.append(string) + string = None + return res + +def renderPage(stream, req, session): + handler = webifHandler(session) + parser = make_parser() + parser.setFeature(feature_namespaces, 0) + parser.setContentHandler(handler) + parser.parse(open(util.sibpath(__file__, 'test.xml'))) # currently fixed + for x in lreduce(handler.res): + stream.write(str(x)) + stream.finish() # must be done, unless we "callLater"