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 Screens.MessageBox import MessageBox
7 from Tools import Notifications
8 from Components.config import config
10 from GrowleeConnection import emergencyDisable
11 from . import NOTIFICATIONID
15 class SnarlNetworkProtocol(LineReceiver):
16 def __init__(self, client = False):
19 def connectionMade(self):
20 self.factory.addClient(self)
22 payload = "type=SNP#?version=1.0#?action=register#?app=growlee"
23 self.sendLine(payload)
25 payload = "type=SNP#?version=1.0#?action=add_class#?app=growlee#?class=growleeClass#?title=Notifications from your Dreambox"
26 self.sendLine(payload)
28 def connectionLost(self, reason):
29 self.factory.removeClient(self)
33 payload = "type=SNP#?version=1.0#?action=unregister#?app=growlee"
34 self.sendLine(payload)
36 self.transport.loseConnection()
38 def sendNotification(self, title='No title.', description='No message.', timeout=1):
39 if not self.client or not self.transport:
42 payload = "type=SNP#?version=1.0#?action=notification#?app=growlee#?class=growleeClass#?title=%s#?text=%s#?timeout=%d" % (title, description, timeout)
43 self.sendLine(payload)
45 def lineReceived(self, data):
46 if self.client or not self.transport:
50 if Len < 23 or not data[:23] == "type=SNP#?version=1.0#?":
53 items = data[23:].split('#?')
59 key, value = item.split('=')
61 if value == "unregister":
62 payload = "SNP/1.0/0/OK"
63 self.sendLine(payload)
64 self.transport.loseConnection()
66 elif value != "notification":
67 # NOTE: we pretend to handle&accept pretty much everything one throws at us
68 payload = "SNP/1.0/0/OK"
69 self.sendLine(payload)
75 elif key == "timeout":
78 Notifications.AddNotificationWithID(
81 text = title + '\n' + description,
82 type = MessageBox.TYPE_INFO,
84 close_on_any_key = True,
88 payload = "SNP/1.0/0/OK"
89 self.sendLine(payload)
91 class SnarlNetworkProtocolClientFactory(ClientFactory):
94 def buildProtocol(self, addr):
95 p = SnarlNetworkProtocol(client = True)
99 def sendNotification(self, title='No title.', description='No message.', priority=0, timeout=-1):
101 title = title.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
102 description = description.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
104 # NOTE: timeout = 0 means sticky, so add one second to map -1 to 0 and make 0 non-sticky
108 self.client.sendNotification(title=title, description=description, timeout=timeout)
110 def addClient(self, client):
113 def removeClient(self, client):
116 class SnarlNetworkProtocolServerFactory(ServerFactory):
117 protocol = SnarlNetworkProtocol
122 def addClient(self, client):
123 self.clients.append(client)
125 def removeClient(self, client):
126 self.clients.remove(client)
128 def sendNotification(self, *args, **kwargs):
131 def stopFactory(self):
132 for client in self.clients:
135 class SnarlNetworkProtocolAbstraction:
141 self.clientFactory = SnarlNetworkProtocolClientFactory()
142 self.serverFactory = SnarlNetworkProtocolServerFactory()
144 if config.plugins.growlee.enable_outgoing.value:
145 reactor.resolve(config.plugins.growlee.address.value).addCallback(self.gotIP).addErrback(self.noIP)
147 if config.plugins.growlee.enable_incoming.value:
148 self.serverPort = reactor.listenTCP(SNP_TCP_PORT, self.serverFactory)
152 self.clientPort = reactor.connectTCP(ip, SNP_TCP_PORT, self.clientFactory)
155 def noIP(self, error):
158 def sendNotification(self, *args, **kwargs):
159 self.clientFactory.sendNotification(*args, **kwargs)
161 def maybeClose(self, resOrFail, defer = None):
163 if self.pending == 0:
170 d = self.clientPort.disconnect()
172 d.addBoth(self.maybeClose, defer = defer)
177 d = self.serverPort.stopListening()
179 d.addBoth(self.maybeClose, defer = defer)
183 if self.pending == 0:
184 reactor.callLater(1, defer.callback, True)