X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/66a23d9e98fb4582c99672500f5e9b165104eb93..d0ddd5ca1a18f1dea9bc0366746e0948c06db1b7:/lib/python/Plugins/Extensions/WebInterface/webif.py diff --git a/lib/python/Plugins/Extensions/WebInterface/webif.py b/lib/python/Plugins/Extensions/WebInterface/webif.py index a452cb76..e69de29b 100644 --- a/lib/python/Plugins/Extensions/WebInterface/webif.py +++ b/lib/python/Plugins/Extensions/WebInterface/webif.py @@ -1,347 +0,0 @@ -# -# OK, this is more than 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 Components.Sources.Config import Config -from Components.Sources.ServiceList import ServiceList -from Components.Converter.Converter import Converter -#from Components.config import config -from Components.Element import Element - -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. - -class WebScreen(Screen): - def __init__(self, session): - Screen.__init__(self, session) - self.stand_alone = True - -# a test screen -class TestScreen(InfoBarServiceName, InfoBarEvent, WebScreen): - def __init__(self, session): - WebScreen.__init__(self, session) - InfoBarServiceName.__init__(self) - InfoBarEvent.__init__(self) - self["CurrentTime"] = Clock() -# self["TVSystem"] = Config(config.av.tvsystem) -# self["OSDLanguage"] = Config(config.osd.language) -# self["FirstRun"] = Config(config.misc.firstrun) - from enigma import eServiceReference - fav = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet') - self["ServiceList"] = ServiceList(fav, command_func = self.zapTo) - self["ServiceListBrowse"] = ServiceList(fav, command_func = self.browseTo) - - def browseTo(self, reftobrowse): - self["ServiceListBrowse"].root = reftobrowse - - def zapTo(self, reftozap): - self.session.nav.playService(reftozap) - -class Streaming(WebScreen): - def __init__(self, session): - WebScreen.__init__(self, session) - from Components.Sources.StreamService import StreamService - self["StreamService"] = StreamService(self.session.nav) - -# implements the 'render'-call. -# this will act as a downstream_element, like a renderer. -class OneTimeElement(Element): - def __init__(self, id): - Element.__init__(self) - self.source_id = id - - # CHECKME: is this ok performance-wise? - def handleCommand(self, args): - for c in args.get(self.source_id, []): - self.source.handleCommand(c) - - def render(self, stream): - t = self.source.getHTML(self.source_id) - if isinstance(t, unicode): - t = t.encode("utf-8") - stream.write(t) - - def execBegin(self): - pass - - def execEnd(self): - pass - - def onShow(self): - pass - - def onHide(self): - pass - - def destroy(self): - pass - -class StreamingElement(OneTimeElement): - def __init__(self, id): - OneTimeElement.__init__(self, id) - self.stream = None - - def changed(self, what): - if self.stream: - self.render(self.stream) - - def setStream(self, stream): - self.stream = stream - -# a to-be-filled list item -class ListItem: - def __init__(self, name): - self.name = name - -class TextToHTML(Converter): - def __init__(self, arg): - Converter.__init__(self, arg) - - def getHTML(self, id): - return self.source.text # encode & etc. here! - -# a null-output. Useful if you only want to issue a command. -class Null(Converter): - def __init__(self, arg): - Converter.__init__(self, arg) - - def getHTML(self, id): - return "" - -def escape(s): - return s.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"') - -class JavascriptUpdate(Converter): - def __init__(self, arg): - Converter.__init__(self, arg) - - def getHTML(self, id): - return '\n' - -# the performant 'listfiller'-engine (plfe) -class ListFiller(Converter): - def __init__(self, arg): - Converter.__init__(self, 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.converter_arguments: - 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 - self.screens = [ ] - - def startElement(self, name, attrs): - if name == "e2:screen": - self.screen = eval(attrs["name"])(self.session) # fixme - self.screens.append(self.screen) - 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 - source = attrs["source"] - self.source_id = str(attrs.get("id", source)) - self.source = self.screen[source] - self.is_streaming = "streaming" in attrs - 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 - assert "name" in attrs, "e2:item must have a name= attribute!" - 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' - # instatiate either a StreamingElement or a OneTimeElement, depending on what's required. - if not self.is_streaming: - c = OneTimeElement(self.source_id) - else: - c = StreamingElement(self.source_id) - - c.connect(self.source) - self.res.append(c) - self.screen.renderer.append(c) - 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 execBegin(self): - for screen in self.screens: - screen.execBegin() - - def cleanup(self): - print "screen cleanup!" - for screen in self.screens: - screen.execEnd() - screen.doClose() - self.screens = [ ] - -def lreduce(list): - # ouch, can be made better - res = [ ] - string = None - for x in list: - if isinstance(x, str) or isinstance(x, unicode): - if 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, path, req, session): - - # read in the template, create required screens - # we don't have persistense yet. - # if we had, this first part would only be done once. - handler = webifHandler(session) - parser = make_parser() - parser.setFeature(feature_namespaces, 0) - parser.setContentHandler(handler) - parser.parse(open(util.sibpath(__file__, path))) - - # by default, we have non-streaming pages - finish = True - - # first, apply "commands" (aka. URL argument) - for x in handler.res: - if isinstance(x, Element): - x.handleCommand(req.args) - - handler.execBegin() - - # now, we have a list with static texts mixed - # with non-static Elements. - # flatten this list, write into the stream. - for x in lreduce(handler.res): - if isinstance(x, Element): - if isinstance(x, StreamingElement): - finish = False - x.setStream(stream) - x.render(stream) - else: - stream.write(str(x)) - - def ping(s): - from twisted.internet import reactor - s.write("\n"); - reactor.callLater(3, ping, s) - - # if we met a "StreamingElement", there is at least one - # element which wants to output data more than once, - # i.e. on host-originated changes. - # in this case, don't finish yet, don't cleanup yet, - # but instead do that when the client disconnects. - if finish: - handler.cleanup() - stream.finish() - else: - # ok. - # you *need* something which constantly sends something in a regular interval, - # in order to detect disconnected clients. - # i agree that this "ping" sucks terrible, so better be sure to have something - # similar. A "CurrentTime" is fine. Or anything that creates *some* output. - ping(stream) - stream.closed_callback = lambda: handler.cleanup()