1 from twisted.internet.defer import Deferred
2 from twisted.internet.protocol import ClientFactory, ServerFactory
3 from twisted.internet import reactor
4 from twisted.protocols.basic import LineReceiver
6 from Tools import Notifications
7 from Components.config import config
9 from GrowleeConnection import emergencyDisable
10 from . import NOTIFICATIONID
14 class SnarlNetworkProtocol(LineReceiver):
15 def __init__(self, client = False):
18 def connectionMade(self):
19 self.factory.addClient(self)
21 payload = "type=SNP#?version=1.0#?action=register#?app=growlee"
22 self.sendLine(payload)
24 payload = "type=SNP#?version=1.0#?action=add_class#?app=growlee#?class=growleeClass#?title=Notifications from your Dreambox"
25 self.sendLine(payload)
27 def connectionLost(self, reason):
28 self.factory.removeClient(self)
32 payload = "type=SNP#?version=1.0#?action=unregister#?app=growlee"
33 self.sendLine(payload)
35 self.transport.loseConnection()
37 def sendNotification(self, title='No title.', description='No message.', timeout=1):
38 if not self.client or not self.transport:
41 payload = "type=SNP#?version=1.0#?action=notification#?app=growlee#?class=growleeClass#?title=%s#?text=%s#?timeout=%d" % (title, description, timeout)
42 self.sendLine(payload)
44 def lineReceived(self, data):
45 if self.client or not self.transport:
49 if Len < 23 or not data[:23] == "type=SNP#?version=1.0#?":
52 items = data[23:].split('#?')
58 key, value = item.split('=')
60 if value == "unregister":
61 payload = "SNP/1.0/0/OK"
62 self.sendLine(payload)
63 self.transport.loseConnection()
65 elif value != "notification":
66 # NOTE: we pretend to handle&accept pretty much everything one throws at us
67 payload = "SNP/1.0/0/OK"
68 self.sendLine(payload)
74 elif key == "timeout":
77 Notifications.AddNotificationWithID(
80 text = title + '\n' + description,
81 type = MessageBox.TYPE_INFO,
83 close_on_any_key = True,
87 payload = "SNP/1.0/0/OK"
88 self.sendLine(payload)
90 class SnarlNetworkProtocolClientFactory(ClientFactory):
93 def buildProtocol(self, addr):
94 p = SnarlNetworkProtocol(client = True)
98 def sendNotification(self, title='No title.', description='No message.', priority=0, timeout=-1):
100 title = title.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
101 description = description.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
103 # NOTE: timeout = 0 means sticky, so add one second to map -1 to 0 and make 0 non-sticky
107 self.client.sendNotification(title=title, description=description, timeout=timeout)
109 def addClient(self, client):
112 def removeClient(self, client):
115 class SnarlNetworkProtocolServerFactory(ServerFactory):
116 protocol = SnarlNetworkProtocol
121 def addClient(self, client):
122 self.clients.append(client)
124 def removeClient(self, client):
125 self.clients.remove(client)
127 def sendNotification(self, *args, **kwargs):
130 def stopFactory(self):
131 for client in self.clients:
134 class SnarlNetworkProtocolAbstraction:
140 self.clientFactory = SnarlNetworkProtocolClientFactory()
141 self.serverFactory = SnarlNetworkProtocolServerFactory()
143 if config.plugins.growlee.enable_outgoing.value:
144 reactor.resolve(config.plugins.growlee.address.value).addCallback(self.gotIP).addErrback(self.noIP)
146 if config.plugins.growlee.enable_incoming.value:
147 self.serverPort = reactor.listenTCP(SNP_TCP_PORT, self.serverFactory)
151 self.clientPort = reactor.connectTCP(ip, SNP_TCP_PORT, self.clientFactory)
154 def noIP(self, error):
157 def sendNotification(self, *args, **kwargs):
158 self.clientFactory.sendNotification(*args, **kwargs)
160 def maybeClose(self, resOrFail, defer = None):
162 if self.pending == 0:
169 d = self.clientPort.disconnect()
171 d.addBoth(self.maybeClose, defer = defer)
176 d = self.serverPort.stopListening()
178 d.addBoth(self.maybeClose, defer = defer)
182 if self.pending == 0:
183 reactor.callLater(1, defer.callback, True)