add missing import
[vuplus_dvbapp-plugin] / growlee / src / SNP.py
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
5
6 from Screens.MessageBox import MessageBox
7 from Tools import Notifications
8 from Components.config import config
9
10 from GrowleeConnection import emergencyDisable
11 from . import NOTIFICATIONID
12
13 SNP_TCP_PORT = 9887
14
15 class SnarlNetworkProtocol(LineReceiver):
16         def __init__(self, client = False):
17                 self.client = client
18
19         def connectionMade(self):
20                 self.factory.addClient(self)
21                 if self.client:
22                         payload = "type=SNP#?version=1.0#?action=register#?app=growlee"
23                         self.sendLine(payload)
24
25                         payload = "type=SNP#?version=1.0#?action=add_class#?app=growlee#?class=growleeClass#?title=Notifications from your Dreambox"
26                         self.sendLine(payload)
27
28         def connectionLost(self, reason):
29                 self.factory.removeClient(self)
30
31         def stop(self):
32                 if self.client:
33                         payload = "type=SNP#?version=1.0#?action=unregister#?app=growlee"
34                         self.sendLine(payload)
35
36                 self.transport.loseConnection()
37
38         def sendNotification(self, title='No title.', description='No message.', timeout=1):
39                 if not self.client or not self.transport:
40                         return
41
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)
44
45         def lineReceived(self, data):
46                 if self.client or not self.transport:
47                         return
48
49                 Len = len(data)
50                 if Len < 23 or not data[:23] == "type=SNP#?version=1.0#?":
51                         return
52
53                 items = data[23:].split('#?')
54
55                 title = ''
56                 description = ''
57                 timeout = 5
58                 for item in items:
59                         key, value = item.split('=')
60                         if key == "action":
61                                 if value == "unregister":
62                                         payload = "SNP/1.0/0/OK"
63                                         self.sendLine(payload)
64                                         self.transport.loseConnection()
65                                         return
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)
70                                         return
71                         elif key == "title":
72                                 title = value
73                         elif key == "text":
74                                 description = value
75                         elif key == "timeout":
76                                 timeout = int(value)
77
78                 Notifications.AddNotificationWithID(
79                         NOTIFICATIONID,
80                         MessageBox,
81                         text = title + '\n' + description,
82                         type = MessageBox.TYPE_INFO,
83                         timeout = timeout,
84                         close_on_any_key = True,
85                 )
86
87                 # return ok
88                 payload = "SNP/1.0/0/OK"
89                 self.sendLine(payload)
90
91 class SnarlNetworkProtocolClientFactory(ClientFactory):
92         client = None
93
94         def buildProtocol(self, addr):
95                 p = SnarlNetworkProtocol(client = True)
96                 p.factory = self
97                 return p
98
99         def sendNotification(self, title='No title.', description='No message.', priority=0, timeout=-1):
100                 if self.client:
101                         title = title.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
102                         description = description.decode('utf-8', 'ignore').encode('iso8859-15', 'ignore')
103
104                         # NOTE: timeout = 0 means sticky, so add one second to map -1 to 0 and make 0 non-sticky
105                         if timeout < 1:
106                                 timeout += 1
107
108                         self.client.sendNotification(title=title, description=description, timeout=timeout)
109
110         def addClient(self, client):
111                 self.client = client
112
113         def removeClient(self, client):
114                 self.client = None
115
116 class SnarlNetworkProtocolServerFactory(ServerFactory):
117         protocol = SnarlNetworkProtocol
118
119         def __init__(self):
120                 self.clients = []
121
122         def addClient(self, client):
123                 self.clients.append(client)
124
125         def removeClient(self, client):
126                 self.clients.remove(client)
127
128         def sendNotification(self, *args, **kwargs):
129                 pass
130
131         def stopFactory(self):
132                 for client in self.clients:
133                         client.stop()
134
135 class SnarlNetworkProtocolAbstraction:
136         clientPort = None
137         serverPort = None
138         pending = 0
139
140         def __init__(self):
141                 self.clientFactory = SnarlNetworkProtocolClientFactory()
142                 self.serverFactory = SnarlNetworkProtocolServerFactory()
143
144                 if config.plugins.growlee.enable_outgoing.value:
145                         reactor.resolve(config.plugins.growlee.address.value).addCallback(self.gotIP).addErrback(self.noIP)
146
147                 if config.plugins.growlee.enable_incoming.value:
148                         self.serverPort = reactor.listenTCP(SNP_TCP_PORT, self.serverFactory)
149                         self.pending += 1
150
151         def gotIP(self, ip):
152                 self.clientPort = reactor.connectTCP(ip, SNP_TCP_PORT, self.clientFactory)
153                 self.pending += 1
154
155         def noIP(self, error):
156                 emergencyDisable()
157
158         def sendNotification(self, *args, **kwargs):
159                 self.clientFactory.sendNotification(*args, **kwargs)
160
161         def maybeClose(self, resOrFail, defer = None):
162                 self.pending -= 1
163                 if self.pending == 0:
164                         if defer:
165                                 defer.callback(True)
166
167         def stop(self):
168                 defer = Deferred()
169                 if self.clientPort:
170                         d = self.clientPort.disconnect()
171                         if d:
172                                 d.addBoth(self.maybeClose, defer = defer)
173                         else:
174                                 self.pending -= 1
175
176                 if self.serverPort:
177                         d = self.serverPort.stopListening()
178                         if d:
179                                 d.addBoth(self.maybeClose, defer = defer)
180                         else:
181                                 self.pending -= 1
182
183                 if self.pending == 0:
184                         reactor.callLater(1, defer.callback, True)
185                 return defer
186