enigma2 (20120327 rel32 -> 20120430 master)
[enigma2.git] / usr / lib / enigma2 / python / e2reactor.py
1 # based on qt4reactor.py
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4 # Original Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
5 # Original Ported to QT4: U{Gabe Rudy<mailto:rudy@goldenhelix.com>}
6
7 """
8 This module provides support for Twisted to interact with Enigma2's mainloop.
9
10 Maintainer: U{Andreas Monzner<mailto:andreas.monzner@dream-property.net>}
11 """
12
13 __all__ = ['install']
14
15 # System Imports
16 from enigma import runMainloop, quitMainloop, eSocketNotifier, eTimer
17 from select import POLLIN, POLLOUT
18
19 from zope.interface import implements
20
21 from twisted.internet.interfaces import IReactorFDSet
22 from twisted.python import log
23 from twisted.internet.posixbase import PosixReactorBase
24
25 class TwistedSocketNotifier:
26     """
27     Connection between an fd event and reader/writer callbacks.
28     """
29
30     def __init__(self, reactor, watcher, type):
31         self.sn = eSocketNotifier(watcher.fileno(), type)
32         self.reactor = reactor
33         self.watcher = watcher
34         self.fn = None
35         if type == POLLIN:
36             self.fn = self.read
37         elif type == POLLOUT:
38             self.fn = self.write
39         self.sn.callback.append(self.fn)
40
41
42     def shutdown(self):
43         self.fn = self.watcher = None
44         del self.sn
45
46
47     def read(self, sock):
48         w = self.watcher
49         def _read():
50             why = None
51             try:
52                 why = w.doRead()
53             except:
54                 log.err()
55                 why = sys.exc_info()[1]
56             if why:
57                 self.reactor._disconnectSelectable(w, why, True)
58         log.callWithLogger(w, _read)
59         self.reactor.simulate()
60
61
62     def write(self, sock):
63         w = self.watcher
64         def _write():
65             why = None
66             try:
67                 why = w.doWrite()
68             except:
69                 log.err()
70                 why = sys.exc_info()[1]
71             if why:
72                 self.reactor._disconnectSelectable(w, why, False)
73         log.callWithLogger(w, _write)
74         self.reactor.simulate()
75
76
77 class e2reactor(PosixReactorBase):
78     """
79     e2 reactor.
80     """
81     implements(IReactorFDSet)
82
83     # Reference to a DelayedCall for self.crash() when the reactor is
84     # entered through .iterate()
85     _crashCall = None
86
87     _timer = None
88
89     def __init__(self):
90         self._reads = {}
91         self._writes = {}
92         PosixReactorBase.__init__(self)
93         self.addSystemEventTrigger('after', 'shutdown', self.cleanup)
94         self._timer = eTimer()
95         self._timer.callback.append(self.simulate)
96
97
98     def addReader(self, reader):
99         if not reader in self._reads:
100             self._reads[reader] = TwistedSocketNotifier(self, reader,
101                                                        POLLIN)
102
103
104     def addWriter(self, writer):
105         if not writer in self._writes:
106             self._writes[writer] = TwistedSocketNotifier(self, writer,
107                                                         POLLOUT)
108
109
110     def removeReader(self, reader):
111         if reader in self._reads:
112             self._reads[reader].shutdown()
113             del self._reads[reader]
114
115
116     def removeWriter(self, writer):
117         if writer in self._writes:
118             self._writes[writer].shutdown()
119             del self._writes[writer]
120
121
122     def removeAll(self):
123         return self._removeAll(self._reads, self._writes)
124
125
126     def getReaders(self):
127         return self._reads.keys()
128
129
130     def getWriters(self):
131         return self._writes.keys()
132
133
134     def simulate(self):
135         if not self.running:
136             quitMainloop()
137             return
138
139         self.runUntilCurrent()
140
141         if self._crashCall is not None:
142             self._crashCall.reset(0)
143
144         timeout = self.timeout()
145         if timeout is not None and timeout > 0:
146             self._timer.start(int(timeout * 1010))
147
148
149     def cleanup(self):
150         if self._timer is not None:
151             self._timer.stop()
152             self._timer = None
153
154
155     def iterate(self, delay=0.0):
156         self._crashCall = self.callLater(delay, self._crash)
157         self.run()
158
159
160     def mainLoop(self):
161         self.simulate()
162         runMainloop()
163
164
165     def _crash(self):
166         if self._crashCall is not None:
167             if self._crashCall.active():
168                 self._crashCall.cancel()
169             self._crashCall = None
170         self.running = False
171
172
173
174 def install(app=None):
175     """
176     Configure the twisted mainloop to be run inside the e2 mainloop.
177     """
178     from twisted.internet import main
179     reactor = e2reactor()
180     main.installReactor(reactor)