1 from netgrowl import GROWL_UDP_PORT
2 from twisted.internet.defer import Deferred
3 from twisted.internet.protocol import ClientFactory, ServerFactory
4 from twisted.internet import reactor
5 from twisted.protocols.basic import LineReceiver
7 from Tools import Notifications
8 from Components.config import config
10 from GrowleeConnection import emergencyDisable
11 from . import NOTIFICATIONID
13 class SnarlNetworkProtocol(LineReceiver):
14 def __init__(self, client = False):
17 def connectionMade(self):
18 self.factory.addClient(self)
20 payload = "type=SNP#?version=1.0#?action=register#?app=growlee"
21 self.sendLine(payload)
23 payload = "type=SNP#?version=1.0#?action=add_class#?app=growlee#?class=growleeClass#?title=Notifications from your Dreambox"
24 self.sendLine(payload)
26 def connectionLost(self, reason):
27 self.factory.removeClient(self)
31 payload = "type=SNP#?version=1.0#?action=unregister#?app=growlee"
32 self.sendLine(payload)
34 self.transport.loseConnection()
36 def sendNotification(self, title='No title.', description='No message.', timeout=1):
37 if not self.client or not self.transport:
40 payload = "type=SNP#?version=1.0#?action=notification#?app=growlee#?class=growleeClass#?title=%s#?text=%s#?timeout=%d" % (title, description, timeout)
41 self.sendLine(payload)
43 def lineReceived(self, data):
44 if self.client or not self.transport:
48 if Len < 23 or not data[:23] == "type=SNP#?version=1.0#?":
51 items = data[23:].split('#?')
57 key, value = item.split('=')
59 if value == "unregister":
60 payload = "SNP/1.0/0/OK"
61 self.sendLine(payload)
62 self.transport.loseConnection()
64 elif value != "notification":
65 # NOTE: we pretend to handle&accept pretty much everything one throws at us
66 payload = "SNP/1.0/0/OK"
67 self.sendLine(payload)
73 elif key == "timeout":
76 Notifications.AddNotificationWithID(
79 text = title + '\n' + description,
80 type = MessageBox.TYPE_INFO,
82 close_on_any_key = True,
86 payload = "SNP/1.0/0/OK"
87 self.sendLine(payload)
89 class SnarlNetworkProtocolClientFactory(ClientFactory):
92 def buildProtocol(self, addr):
93 p = SnarlNetworkProtocol(client = True)
97 def sendNotification(self, title='No title.', description='No message.', priority=0, timeout=-1):
99 title = title.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
100 description = description.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
102 # NOTE: timeout = 0 means sticky, so add one second to map -1 to 0 and make 0 non-sticky
106 self.client.sendNotification(title=title, description=description, timeout=timeout)
108 def addClient(self, client):
111 def removeClient(self, client):
114 class SnarlNetworkProtocolServerFactory(ServerFactory):
115 protocol = SnarlNetworkProtocol
120 def addClient(self, client):
121 self.clients.append(client)
123 def removeClient(self, client):
124 self.clients.remove(client)
126 def sendNotification(self, *args, **kwargs):
129 def stopFactory(self):
130 for client in self.clients:
133 class SnarlNetworkProtocolAbstraction:
139 self.clientFactory = SnarlNetworkProtocolClientFactory()
140 self.serverFactory = SnarlNetworkProtocolServerFactory()
142 if config.plugins.growlee.enable_outgoing.value:
143 reactor.resolve(config.plugins.growlee.address.value).addCallback(self.gotIP).addErrback(self.noIP)
145 if config.plugins.growlee.enable_incoming.value:
146 self.serverPort = reactor.listenTCP(GROWL_UDP_PORT, self.serverFactory)
150 self.clientPort = reactor.connectTCP(ip, GROWL_UDP_PORT, self.clientFactory)
153 def noIP(self, error):
156 def sendNotification(self, *args, **kwargs):
157 self.clientFactory.sendNotification(*args, **kwargs)
159 def maybeClose(self, resOrFail, defer = None):
161 if self.pending == 0:
168 d = self.clientPort.disconnect()
170 d.addBoth(self.maybeClose, defer = defer)
175 d = self.serverPort.stopListening()
177 d.addBoth(self.maybeClose, defer = defer)
181 if self.pending == 0:
182 reactor.callLater(1, defer.callback, True)