AutoPoller.py: deque should be enough
[enigma2-plugins.git] / autotimer / src / AutoPoller.py
1 from __future__ import print_function
2
3 # Core functionality
4 from enigma import eTimer, ePythonMessagePump
5
6 # Config
7 from Components.config import config
8
9 # Notifications
10 from Tools.FuzzyDate import FuzzyTime
11 from Tools.Notifications import AddPopup
12 from Screens.MessageBox import MessageBox
13
14 NOTIFICATIONID = 'AutoTimerConflictEncounteredNotification'
15 SIMILARNOTIFICATIONID = 'AutoTimerSimilarUsedNotification'
16
17 from threading import Thread, Semaphore
18 from collections import deque
19
20 class AutoPollerThread(Thread):
21         """Background thread where the EPG is parsed (unless initiated by the user)."""
22         def __init__(self):
23                 Thread.__init__(self)
24                 self.__semaphore = Semaphore(0)
25                 self.__queue = deque(maxlen=1)
26                 self.__pump = ePythonMessagePump()
27                 self.__pump.recv_msg.get().append(self.gotThreadMsg)
28                 self.__timer = eTimer()
29                 self.__timer.callback.append(self.timeout)
30                 self.running = False
31
32         def timeout(self):
33                 self.__semaphore.release()
34
35         def gotThreadMsg(self, msg):
36                 """Create Notifications if there is anything to display."""
37                 ret = self.__queue.pop()
38                 conflicts = ret[4]
39                 if conflicts and config.plugins.autotimer.notifconflict.value:
40                         AddPopup(
41                                 _("%d conflict(s) encountered when trying to add new timers:\n%s") % (len(conflicts), '\n'.join([_("%s: %s at %s") % (x[4], x[0], FuzzyTime(x[2])) for x in conflicts])),
42                                 MessageBox.TYPE_INFO,
43                                 5,
44                                 NOTIFICATIONID
45                         )
46                 similars = ret[5]
47                 if similars and config.plugins.autotimer.notifsimilar.value:
48                         AddPopup(
49                                 _("%d conflict(s) solved with similar timer(s):\n%s") % (len(similars), '\n'.join([_("%s: %s at %s") % (x[4], x[0], FuzzyTime(x[2])) for x in similars])),
50                                 MessageBox.TYPE_INFO,
51                                 5,
52                                 SIMILARNOTIFICATIONID
53                         )
54
55         def start(self, initial=True):
56                 # NOTE: we wait for 10 seconds on initial launch to not delay enigma2 startup time
57                 if initial: delay = 10
58                 else: delay = config.plugins.autotimer.interval.value*3600
59
60                 self.__timer.startLongTimer(delay)
61                 Thread.start(self)
62
63         def stop(self):
64                 self.__timer.stop()
65                 self.running = False
66                 self.__semaphore.release()
67
68         def run(self):
69                 self.running = True
70                 while True:
71                         self.__semaphore.acquire()
72                         # NOTE: we have to check this here and not using the while to prevent the parser to be started on shutdown
73                         if not self.running: break
74
75                         from plugin import autotimer
76                         # Ignore any program errors
77                         try:
78                                 self.__queue.append(autotimer.parseEPG())
79                                 self.__pump.send(0)
80                         except Exception:
81                                 # Dump error to stdout
82                                 import traceback, sys
83                                 traceback.print_exc(file=sys.stdout)
84
85                         self.__timer.startLongTimer(config.plugins.autotimer.interval.value*3600)
86
87 class AutoPoller:
88         """Manages actual thread which does the polling. Used for convenience."""
89
90         def __init__(self):
91                 self.thread = AutoPollerThread()
92
93         def start(self, initial=True):
94                 self.thread.start(initial=initial)
95
96         def stop(self):
97                 self.thread.stop()
98                 # NOTE: while we don't need to join the thread, we should do so in case it's currently parsining
99                 self.thread.join()
100