From 389c54583de08e2740682bffeeceff0b6aa3df03 Mon Sep 17 00:00:00 2001 From: Moritz Venn Date: Mon, 31 Jan 2011 16:15:30 +0100 Subject: [PATCH] growlee: more work on multiconnect tested working using a single (converted) config, still needs code to add/remove new connections. --- growlee/src/GrowlTalk.py | 22 +++++----- growlee/src/GrowleeConnection.py | 74 +++++++++++++++++++++----------- growlee/src/Prowl.py | 10 +++-- growlee/src/SNP.py | 9 ++-- growlee/src/plugin.py | 49 ++++++++++----------- 5 files changed, 92 insertions(+), 72 deletions(-) diff --git a/growlee/src/GrowlTalk.py b/growlee/src/GrowlTalk.py index e3190058..40b1987d 100644 --- a/growlee/src/GrowlTalk.py +++ b/growlee/src/GrowlTalk.py @@ -5,7 +5,6 @@ from hashlib import md5 from Screens.MessageBox import MessageBox from Tools import Notifications -from Components.config import config from GrowleeConnection import emergencyDisable from . import NOTIFICATIONID @@ -15,9 +14,12 @@ GROWL_UDP_PORT = 9887 class GrowlTalk(DatagramProtocol): addr = None + def __init__(self, host): + self.host = host + def gotIP(self, ip): self.addr = (ip, GROWL_UDP_PORT) - if config.plugins.growlee.enable_outgoing.value: + if self.host.enable_outgoing.value: p = pack("!BBHBB", 1, # version 0, # registration @@ -32,7 +34,7 @@ class GrowlTalk(DatagramProtocol): p += "Notifications from your Dreambox" # first notification type name p += "\x00" # index of default notifications - password = config.plugins.growlee.password.value + password = self.host.password.value checksum = md5() checksum.update(p) if password: @@ -46,10 +48,10 @@ class GrowlTalk(DatagramProtocol): emergencyDisable() def startProtocol(self): - reactor.resolve(config.plugins.growlee.address.value).addCallback(self.gotIP).addErrback(self.noIP) + reactor.resolve(self.host.address.value).addCallback(self.gotIP).addErrback(self.noIP) def sendNotification(self, title='No title.', description='No description.', flags=0): - if not self.transport or not self.addr or not config.plugins.growlee.enable_outgoing.value: + if not self.transport or not self.addr or not self.host.enable_outgoing.value: return p = pack("!BBHHHHH", @@ -66,7 +68,7 @@ class GrowlTalk(DatagramProtocol): p += description p += "growlee" - password = config.plugins.growlee.password.value + password = self.host.password.value checksum = md5() checksum.update(p) if password: @@ -76,7 +78,7 @@ class GrowlTalk(DatagramProtocol): self.transport.write(p, self.addr) def datagramReceived(self, data, addr): - if not config.plugins.growlee.enable_incoming.value: + if not self.host.enable_incoming.value: return Len = len(data) @@ -90,7 +92,7 @@ class GrowlTalk(DatagramProtocol): # type == GROWL_TYPE_NOTIFICATION if data[1] == '\x01': digest = data[-16:] - password = config.plugins.growlee.password.value + password = self.host.password.value checksum = md5() checksum.update(data[:-16]) if password: @@ -118,8 +120,8 @@ class GrowlTalk(DatagramProtocol): ) class GrowlTalkAbstraction: - def __init__(self): - self.growltalk = GrowlTalk() + def __init__(self, host): + self.growltalk = GrowlTalk(host) self.serverPort = reactor.listenUDP(GROWL_UDP_PORT, self.growltalk) def sendNotification(self, title='No title.', description='No description.', priority=-1, timeout=-1): diff --git a/growlee/src/GrowleeConnection.py b/growlee/src/GrowleeConnection.py index 0bbd81eb..43cbf790 100644 --- a/growlee/src/GrowleeConnection.py +++ b/growlee/src/GrowleeConnection.py @@ -1,6 +1,8 @@ from Components.config import config from Tools import Notifications from Screens.MessageBox import MessageBox +from twisted.internet.defer import Deferred +from twisted.internet import reactor from . import NOTIFICATIONID @@ -21,7 +23,7 @@ def gotNotification(): notifications = Notifications.notifications if notifications: _, screen, args, kwargs, id = notifications[-1] - if screen is MessageBox and id != NOTIFICATIONID and id not in config.plugins.growlee.blacklist.value: + if screen is MessageBox and id != NOTIFICATIONID: # NOTE: priority is in [-2; 2] but type is [0; 3] so map it # XXX: maybe priority==type-2 would be more appropriate @@ -34,41 +36,61 @@ def gotNotification(): description = args[0] description = description - growleeConnection.sendNotification(title="Dreambox", description=description, priority=priority, timeout=timeout) + growleeConnection.sendNotification(title="Dreambox", description=description, priority=priority, timeout=timeout, id=id) class GrowleeConnection: - connection = None + connections = [] + pending = 0 - def sendNotification(self, title="Dreambox", description='', priority=-1, timeout=-1): - try: - level = int(config.plugins.growlee.level.value) - except ValueError: - level = -1 + def sendNotification(self, title="Dreambox", description='', priority=-1, timeout=-1, id=""): + for connection, host in self.connections: + try: + level = int(host.level.value) + except ValueError: + level = -1 - if self.connection and not priority < level: - self.connection.sendNotification(title=title, description=description, priority=priority, timeout=timeout) + if connection and id not in host.blacklist.value and not priority < level: + connection.sendNotification(title=title, description=description, priority=priority, timeout=timeout) def listen(self): - if self.connection: + if self.connections: return - proto = config.plugins.growlee.protocol.value - if proto == "prowl": - from Prowl import ProwlAPI - self.connection = ProwlAPI() - elif proto == "growl": - from GrowlTalk import GrowlTalkAbstraction - self.connection = GrowlTalkAbstraction() - else: # proto == "snarl": - from SNP import SnarlNetworkProtocolAbstraction - self.connection = SnarlNetworkProtocolAbstraction() + for host in config.plugins.growlee.hosts: + if not (host.enable_outgoing.value or host.enable_incoming.value): + continue + + proto = host.protocol.value + if proto == "prowl": + from Prowl import ProwlAPI + connection = ProwlAPI(host) + elif proto == "growl": + from GrowlTalk import GrowlTalkAbstraction + connection = GrowlTalkAbstraction(host) + else: # proto == "snarl": + from SNP import SnarlNetworkProtocolAbstraction + connection = SnarlNetworkProtocolAbstraction(host) + + self.connections.append((connection, host)) + + def maybeClose(self, resOrFail, defer = None): + self.pending -= 1 + if self.pending == 0: + if defer: defer.callback(True) def stop(self): - if self.connection: - d = self.connection.stop() - self.connection = None - return d - return None + defer = Deferred() + self.pending = 0 + for connection, host in self.connections: + d = connection.stop() + if d is not None: + self.pending += 1 + d.addBoth(self.maybeClose, defer = defer) + del self.connections[:] + + if self.pending == 0: + reactor.callLater(1, defer, True) + return defer growleeConnection = GrowleeConnection() diff --git a/growlee/src/Prowl.py b/growlee/src/Prowl.py index a9ee1f17..41cf897d 100644 --- a/growlee/src/Prowl.py +++ b/growlee/src/Prowl.py @@ -3,19 +3,21 @@ from twisted.internet.defer import Deferred from twisted.internet import reactor from urllib import urlencode -from Components.config import config - from GrowleeConnection import emergencyDisable from . import NOTIFICATIONID class ProwlAPI: + def __init__(self, host): + self.enable_outgoing = host.enable_outgoing.value + self.api_key = host.password.value + def sendNotification(self, title='No title.', description='No message.', priority=0, timeout=-1): - if not config.plugins.growlee.enable_outgoing.value: + if not self.enable_outgoing: return headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'} data = { - 'apikey': config.plugins.growlee.prowl_api_key.value, + 'apikey': self.api_key, 'application': "growlee", 'event': title, 'description': description, diff --git a/growlee/src/SNP.py b/growlee/src/SNP.py index 3d7ffba3..09b8636b 100644 --- a/growlee/src/SNP.py +++ b/growlee/src/SNP.py @@ -5,7 +5,6 @@ from twisted.protocols.basic import LineReceiver from Screens.MessageBox import MessageBox from Tools import Notifications -from Components.config import config from GrowleeConnection import emergencyDisable from . import NOTIFICATIONID @@ -137,14 +136,14 @@ class SnarlNetworkProtocolAbstraction: serverPort = None pending = 0 - def __init__(self): + def __init__(self, host): self.clientFactory = SnarlNetworkProtocolClientFactory() self.serverFactory = SnarlNetworkProtocolServerFactory() - if config.plugins.growlee.enable_outgoing.value: - reactor.resolve(config.plugins.growlee.address.value).addCallback(self.gotIP).addErrback(self.noIP) + if host.enable_outgoing.value: + reactor.resolve(host.address.value).addCallback(self.gotIP).addErrback(self.noIP) - if config.plugins.growlee.enable_incoming.value: + if host.enable_incoming.value: self.serverPort = reactor.listenTCP(SNP_TCP_PORT, self.serverFactory) self.pending += 1 diff --git a/growlee/src/plugin.py b/growlee/src/plugin.py index 6b78b398..7993cf26 100644 --- a/growlee/src/plugin.py +++ b/growlee/src/plugin.py @@ -7,7 +7,7 @@ from Screens.Screen import Screen from Components.ActionMap import ActionMap from Components.config import config, getConfigListEntry, ConfigSubsection, \ ConfigText, ConfigPassword, ConfigYesNo, ConfigSelection, ConfigSet, \ - ConfigSubList, NoSave + ConfigSubList, ConfigNumber, NoSave from Components.ConfigList import ConfigListScreen from Components.Sources.StaticText import StaticText @@ -20,10 +20,9 @@ config.plugins.growlee = growlee growlee.hostcount = ConfigNumber(default=0) growlee.hosts = ConfigSubList() -i = 0 -while i < growlee.hostcount.value: +def addHost(idx): s = ConfigSubsection() - s.name = ConfigText(default=str(i+1), fixed_size=False) + s.name = ConfigText(default=str(idx+1), fixed_size=False) s.enable_incoming = ConfigYesNo(default=False) s.enable_outgoing = ConfigYesNo(default=False) s.address = ConfigText(fixed_size=False) @@ -31,13 +30,19 @@ while i < growlee.hostcount.value: s.protocol = ConfigSelection(default="growl", choices=[("growl", "Growl"), ("snarl", "Snarl"), ("prowl", "Prowl")]) s.level = ConfigSelection(default="-1", choices=[("-1", _("Low (Yes/No)")), ("0", _("Normal (Information)")), ("1", _("High (Warning)")), ("2", _("Highest (Emergency)"))]) s.blacklist = ConfigSet(choices=[]) - growlee.hosts.append(s) + config.plugins.growlee.hosts.append(s) + return s + +i = 0 +while i < growlee.hostcount.value: + addHost(i) i += 1 - del s # XXX: change to new config format -growlee.enable_outgoing = ConfigYesNo(default=False) -if growlee.hostcount.value == 0 and growlee.enable_outgoing.value: +# NOTE: after some time, remove this and hardcode default length to 1 +# since internally we assume to have at least 1 host configured +if growlee.hostcount.value == 0: + growlee.enable_outgoing = ConfigYesNo(default=False) growlee.enable_incoming = ConfigYesNo(default=False) growlee.address = ConfigText(fixed_size=False) growlee.password = ConfigPassword() @@ -49,16 +54,7 @@ if growlee.hostcount.value == 0 and growlee.enable_outgoing.value: if growlee.protocol.value == "prowl": password = growlee.prowl_api_key.value - s = ConfigSubsection() - s.name = ConfigText(default="1", fixed_size=False) - s.enable_incoming = ConfigYesNo(default=False) - s.enable_outgoing = ConfigYesNo(default=False) - s.address = ConfigText(fixed_size=False) - s.password = ConfigPassword() - s.protocol = ConfigSelection(default="growl", choices=[("growl", "Growl"), ("snarl", "Snarl"), ("prowl", "Prowl")]) - s.level = ConfigSelection(default="-1", choices=[("-1", _("Low (Yes/No)")), ("0", _("Normal (Information)")), ("1", _("High (Warning)")), ("2", _("Highest (Emergency)"))]) - s.blacklist = ConfigSet(choices=[]) - + s = addHost(0) s.enable_incoming.value = growlee.enable_incoming.value s.enable_outgoing.value = growlee.enable_outgoing.value s.address.value = growlee.address.value @@ -77,8 +73,6 @@ if growlee.hostcount.value == 0 and growlee.enable_outgoing.value: growlee.blacklist.value = [] growlee.hostcount.value += 1 - growlee.hosts.append(s) - growlee.save() del s @@ -113,6 +107,7 @@ class GrowleeConfiguration(Screen, ConfigListScreen): session=session, on_change=self.changed ) + self.cur = self.hostElement.value # Trigger change self.setupList() @@ -127,6 +122,7 @@ class GrowleeConfiguration(Screen, ConfigListScreen): if self.setupList in last.protocol.notifiers: last.protocol.notifiers.remove(self.setupList) cur = self.hostElement.value + self.cur = cur cur.protocol.notifiers.append(self.setupList) l = [ @@ -165,13 +161,12 @@ class GrowleeConfiguration(Screen, ConfigListScreen): def keySave(self): if self["config"].isChanged(): - def maybeConnect(*args, **kwargs): - if config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value: - growleeConnection.listen() + def doConnect(*args, **kwargs): + growleeConnection.listen() d = growleeConnection.stop() if d is not None: - d.addCallback(maybeConnect).addErrback(emergencyDisable) + d.addCallback(doConnect).addErrback(emergencyDisable) else: maybeConnect() @@ -179,7 +174,8 @@ class GrowleeConfiguration(Screen, ConfigListScreen): self.close() def close(self): - config.plugins.growlee.protocol.notifiers.remove(self.setupList) + if self.setupList in self.cur.protocol.notifiers: + self.cur.protocol.notifiers.remove(self.setupList) Screen.close(self) def configuration(session, **kwargs): @@ -190,8 +186,7 @@ def autostart(**kwargs): # may remove the notifications from the list for good Notifications.notificationAdded.insert(0, gotNotification) - if config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value: - growleeConnection.listen() + growleeConnection.listen() def Plugins(**kwargs): return [ -- 2.20.1