Mercurial > feed-push
annotate feed-push @ 33:adde3e451237 draft
use feed link as id when available
Signed-off-by: Changaco <changaco ατ changaco δοτ net>
author | Changaco <changaco ατ changaco δοτ net> |
---|---|
date | Sun, 05 Aug 2012 15:06:00 +0200 |
parents | 5348758c622d |
children | 030e8b24f8b7 |
rev | line source |
---|---|
1 | 1 #!/usr/bin/env python2 |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # This program is free software: you can redistribute it and/or modify | |
5 # it under the terms of the GNU General Public License as published by | |
6 # the Free Software Foundation, either version 3 of the License, or | |
7 # (at your option) any later version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, | |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 # GNU General Public License for more details. | |
13 # | |
14 # You should have received a copy of the GNU General Public License | |
15 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | |
17 import argparse | |
18 import calendar | |
19 from functools import partial, reduce | |
20 from glob import glob | |
21 import json | |
22 import os | |
7 | 23 from os.path import abspath, dirname, isdir |
1 | 24 import shlex |
25 from subprocess import Popen, PIPE, STDOUT | |
26 import sys | |
27 from syslog import * | |
28 import time | |
21
3ecfeaba3c92
fix exception handling
Changaco <changaco ατ changaco δοτ net>
parents:
20
diff
changeset
|
29 import traceback |
1 | 30 |
31 import feedparser | |
32 | |
33 | |
34 # Constants | |
35 | |
36 log_levels = ['DEBUG', 'INFO', 'NOTICE', 'WARNING', 'ERR', 'CRIT', 'ALERT', 'EMERG'] | |
37 | |
38 gamin_events = { | |
39 1:'GAMChanged', 2:'GAMDeleted', 3:'GAMStartExecuting', 4:'GAMStopExecuting', | |
40 5:'GAMCreated', 6:'GAMMoved', 7:'GAMAcknowledge', 8:'GAMExists', 9:'GAMEndExist' | |
41 } | |
42 | |
43 | |
44 # Generic utils | |
45 | |
46 concat = lambda l: reduce(list.__add__, l, []) | |
47 | |
48 def dict_append(d, k, v): | |
49 d.setdefault(k, []) | |
50 d[k].append(v) | |
51 | |
52 | |
53 # Logging | |
54 | |
55 def log(*args): | |
56 if len(args) == 1: | |
57 priority, msg = LOG_INFO, args[0] | |
58 elif len(args) == 2: | |
59 priority, msg = args | |
60 else: | |
61 return | |
62 priority = 7 - priority | |
63 if priority < global_args.log_level: | |
64 return | |
15
68a9b24a182a
encode log messages in UTF8 before passing them to syslog
Changaco <changaco ατ changaco δοτ net>
parents:
14
diff
changeset
|
65 if isinstance(msg, unicode): |
68a9b24a182a
encode log messages in UTF8 before passing them to syslog
Changaco <changaco ατ changaco δοτ net>
parents:
14
diff
changeset
|
66 msg = msg.encode('utf8') |
18
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
67 try: |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
68 if global_args.fork: |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
69 syslog(priority, msg) |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
70 else: |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
71 sys.stderr.write(log_levels[priority]+': '+msg+'\n') |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
72 except: |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
73 exit(1) |
1 | 74 |
75 def ignore_event(path, event): | |
76 log(LOG_DEBUG, 'ignoring event '+gamin_events.get(event, str(event))+' on '+path) | |
77 | |
78 | |
79 # Config parsing | |
80 | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
81 def parse_config_file(config_path): |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
82 try: |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
83 config_fd = open(config_path) |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
84 except IOError as e: |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
85 return log('failed to open "'+line+'": '+str(e)) |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
86 feeds_paths = config_to_feed_paths_to_commands[config_path] = {} |
11 | 87 cmd = [] |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
88 log('parsing config file '+config_path) |
1 | 89 config_fd.seek(0) |
90 for i, line in enumerate(config_fd): | |
91 line = line.strip() | |
92 if len(line) == 0 or line[0] == '#': | |
93 continue | |
94 if line[0] == '%': | |
11 | 95 if isinstance(cmd, str): |
96 cmd = [] | |
97 cmd.append(line[1:].rstrip(';')) | |
98 elif not cmd: | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
99 log(LOG_ERR, 'missing command in file '+config_path+' before line '+str(i)) |
1 | 100 return |
101 else: | |
11 | 102 cmd = '; '.join(cmd) |
1 | 103 for feed_path in glob(line): |
104 feed_path = abspath(feed_path) | |
105 dict_append(feeds_paths, feed_path, cmd) | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
106 if not feed_path in watched_feeds: |
18
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
107 monitor.watch_file(feed_path, handler(handle_feed_change)) |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
108 watched_feeds.add(feed_path) |
12
ddbbd4ee5d47
log watched/unwatched feed paths
Changaco <changaco ατ changaco δοτ net>
parents:
11
diff
changeset
|
109 log('now watching '+feed_path) |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
110 config_fd.close() |
1 | 111 |
112 | |
113 # Gamin callbacks | |
114 | |
18
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
115 def handler(f): |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
116 def g(path, event): |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
117 try: |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
118 f(path, event) |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
119 except: |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
120 log(LOG_CRIT, traceback.format_exc()) |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
121 return g |
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
122 |
1 | 123 def handle_config_change(path, event): |
124 path = abspath(path) | |
125 if os.path.isdir(path): | |
126 ignore_event(path, event) | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
127 elif not path in config_to_feed_paths_to_commands: |
1 | 128 open_config(path, event) |
129 elif event in [gamin.GAMChanged, gamin.GAMDeleted]: | |
130 update_config(path, event) | |
131 else: | |
132 ignore_event(path, event) | |
133 | |
134 def open_config(path, event): | |
135 if event in [gamin.GAMCreated, gamin.GAMExists]: | |
136 if (not path.endswith('.conf') or path[0] == '.') and not hasattr(global_args.config, 'read'): | |
137 return log('ignoring '+path+' (not a valid config file name)') | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
138 parse_config_file(path) |
1 | 139 else: |
140 ignore_event(path, event) | |
141 | |
142 def update_config(path, event): | |
10
89f581ebf4b2
fix update_config function
Changaco <changaco ατ changaco δοτ net>
parents:
7
diff
changeset
|
143 feeds_paths = set(concat(d.keys() for d in config_to_feed_paths_to_commands.values())) |
1 | 144 if event == gamin.GAMChanged: |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
145 parse_config_file(path) |
1 | 146 elif event == gamin.GAMDeleted: |
25 | 147 log('removing actions from deleted config file '+path) |
1 | 148 config_to_feed_paths_to_commands.pop(path) |
10
89f581ebf4b2
fix update_config function
Changaco <changaco ατ changaco δοτ net>
parents:
7
diff
changeset
|
149 new_feeds_paths = set(concat(d.keys() for d in config_to_feed_paths_to_commands.values())) |
1 | 150 for feed_path in feeds_paths.difference(new_feeds_paths): |
151 monitor.stop_watch(feed_path) | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
152 watched_feeds.discard(feed_path) |
12
ddbbd4ee5d47
log watched/unwatched feed paths
Changaco <changaco ατ changaco δοτ net>
parents:
11
diff
changeset
|
153 log('stopped watching '+feed_path) |
1 | 154 |
155 def handle_feed_change(path, event): | |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
156 if event in [gamin.GAMCreated, gamin.GAMExists, gamin.GAMChanged]: |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
157 try: |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
158 feed_fd = open(path) |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
159 except IOError as e: |
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
160 return log('failed to open "'+path+'": '+str(e)) |
1 | 161 feed = feedparser.parse(feed_fd.read()) |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
162 feed_fd.close() |
33
adde3e451237
use feed link as id when available
Changaco <changaco ατ changaco δοτ net>
parents:
32
diff
changeset
|
163 id_cache = state['id_cache'] |
adde3e451237
use feed link as id when available
Changaco <changaco ατ changaco δοτ net>
parents:
32
diff
changeset
|
164 feed_id = feed.feed.get('link', path) |
adde3e451237
use feed link as id when available
Changaco <changaco ατ changaco δοτ net>
parents:
32
diff
changeset
|
165 if feed_id != path and path in id_cache: |
adde3e451237
use feed link as id when available
Changaco <changaco ατ changaco δοτ net>
parents:
32
diff
changeset
|
166 id_cache[feed_id] = id_cache.pop(path) |
23
5bb7c2939da0
add some debug logging
Changaco <changaco ατ changaco δοτ net>
parents:
22
diff
changeset
|
167 i = 0 |
1 | 168 for entry in reversed(feed.entries): |
33
adde3e451237
use feed link as id when available
Changaco <changaco ατ changaco δοτ net>
parents:
32
diff
changeset
|
169 if entry.id in id_cache.get(feed_id, []) or \ |
1 | 170 not global_args.flood and calendar.timegm(entry.published_parsed) < time.time() - 86400: |
171 continue | |
23
5bb7c2939da0
add some debug logging
Changaco <changaco ατ changaco δοτ net>
parents:
22
diff
changeset
|
172 i += 1 |
1 | 173 for feed_path_to_commands in config_to_feed_paths_to_commands.values(): |
174 for cmd in feed_path_to_commands.get(path, []): | |
175 run_command(format_cmd(cmd, feed=feed.feed, entry=entry), entry.content[0].value) | |
33
adde3e451237
use feed link as id when available
Changaco <changaco ατ changaco δοτ net>
parents:
32
diff
changeset
|
176 id_cache[feed_id] = [entry.id for entry in feed.entries] |
1 | 177 save_state() |
23
5bb7c2939da0
add some debug logging
Changaco <changaco ατ changaco δοτ net>
parents:
22
diff
changeset
|
178 if i == 0: |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
179 log('no new entry in %s' % path) |
1 | 180 else: |
181 ignore_event(path, event) | |
182 | |
183 def save_state(): | |
184 global_args.state_file.truncate(0) | |
185 json.dump(state, global_args.state_file) | |
186 global_args.state_file.flush() | |
187 | |
188 | |
189 # Commands utils | |
190 | |
191 def format_cmd(cmd, **kwargs): | |
192 """The safe equivalent of str.format() for shell commands, meaning interpolated variables can't do shell injections (I hope).""" | |
193 r = u'' | |
194 for arg in shlex.split(cmd.encode('utf8')): | |
195 a = arg.decode('utf8') | |
196 b = a.format(**kwargs) | |
197 if a != b: | |
198 r += u" '" + b.replace(u"'", u'\'"\'"\'') + u"'" | |
199 else: | |
200 r += u' ' + arg | |
201 return r.lstrip() | |
202 | |
203 def run_command(cmd, input): | |
204 p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=True) | |
205 output = p.communicate(input.encode('utf8'))[0].decode('utf8') | |
206 if p.returncode != 0: | |
207 log(LOG_ERR, 'command failed: '+cmd+'\n'+output) | |
208 else: | |
209 log(LOG_INFO, 'successfully executed '+cmd) | |
210 log(LOG_DEBUG, '===== output:\n'+output) | |
211 | |
212 | |
213 # Argparse utils | |
214 | |
215 def AbsPath(next_type=None): | |
216 def f(s): | |
217 p = abspath(s) | |
218 if next_type is not None: | |
219 return next_type(p) | |
220 else: | |
221 return p | |
222 return f | |
223 | |
224 class Apply(argparse.Action): | |
225 def __init__(self, f, *args, **kwargs): | |
226 super(self.__class__, self).__init__(**kwargs) | |
227 self.f = f | |
228 def __call__(self, parser, namespace, values, option_string=None): | |
229 setattr(namespace, self.dest, self.f(values[0])) | |
230 | |
6
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
231 def MakeDirs(next_type=None): |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
232 def f(s): |
7 | 233 d = dirname(s) |
14
5c26fc1adbac
minor fix in automatic directory creation
Changaco <changaco ατ changaco δοτ net>
parents:
12
diff
changeset
|
234 if d and not isdir(d): |
6
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
235 try: |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
236 os.makedirs(d) |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
237 except OSError as e: |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
238 raise argparse.ArgumentTypeError(str(e)) |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
239 if next_type is not None: |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
240 return next_type(s) |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
241 else: |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
242 return s |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
243 return f |
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
244 |
1 | 245 def Directory(s): |
246 try: | |
247 os.listdir(s) | |
248 return s | |
249 except OSError as e: | |
250 raise argparse.ArgumentTypeError(str(e)) | |
251 | |
252 def File(flags): | |
253 def f(s): | |
254 try: | |
255 return os.fdopen(os.open(s, flags), 'w') | |
256 except OSError as e: | |
257 raise argparse.ArgumentTypeError(str(e)) | |
258 return f | |
259 | |
260 class First(argparse.Action): | |
261 def __call__(self, parser, namespace, values, option_string=None): | |
262 setattr(namespace, self.dest, values[0]) | |
263 | |
264 def FirstOf(*types, **kwargs): | |
265 kwargs.setdefault('error', 'argument "{}" is not valid') | |
266 def f(s): | |
267 for t in types: | |
268 try: | |
269 return t(s) | |
270 except: | |
271 pass | |
272 raise argparse.ArgumentTypeError(error.format(s)) | |
273 return f | |
274 | |
275 | |
276 # Main | |
277 | |
278 if __name__ == '__main__': | |
279 | |
280 p = argparse.ArgumentParser() | |
281 p.add_argument('config', type=FirstOf(AbsPath(argparse.FileType('r')), AbsPath(Directory), error='"{}" is neither a file nor a directory'), help='either a file or a directory') | |
6
455cd8c78862
create state dir if it doesn't exist
Changaco <changaco ατ changaco δοτ net>
parents:
1
diff
changeset
|
282 p.add_argument('state_file', type=MakeDirs(argparse.FileType('a+')), help='e.g. /var/lib/feed-push/state') |
1 | 283 p.add_argument('--flood', default=False, action='store_true', help='push all articles on startup instead of ignoring the ones older than 24h (useful for debugging)') |
16
183f4f544987
merge --syslog into --fork and implement double forking
Changaco <changaco ατ changaco δοτ net>
parents:
15
diff
changeset
|
284 p.add_argument('--fork', metavar='pid-file', nargs=1, type=File(os.O_WRONLY|os.O_CREAT|os.O_EXCL), action=First, help='daemonize and log to syslog') |
1 | 285 p.add_argument('--log-level', nargs=1, default=1, choices=log_levels, action=partial(Apply, log_levels.index), help='default is INFO') |
286 global_args = p.parse_args() | |
287 | |
288 if global_args.fork: | |
289 pid = os.fork() | |
290 if pid != 0: | |
16
183f4f544987
merge --syslog into --fork and implement double forking
Changaco <changaco ατ changaco δοτ net>
parents:
15
diff
changeset
|
291 exit(0) |
19 | 292 os.setsid() |
16
183f4f544987
merge --syslog into --fork and implement double forking
Changaco <changaco ατ changaco δοτ net>
parents:
15
diff
changeset
|
293 pid = os.fork() |
183f4f544987
merge --syslog into --fork and implement double forking
Changaco <changaco ατ changaco δοτ net>
parents:
15
diff
changeset
|
294 if pid != 0: |
1 | 295 global_args.fork.write(str(pid)) |
296 exit(0) | |
297 openlog(facility=LOG_DAEMON) | |
17
421a3416e768
close std{in,out,err} in daemon mode
Changaco <changaco ατ changaco δοτ net>
parents:
16
diff
changeset
|
298 null = open('/dev/null', 'r+') |
421a3416e768
close std{in,out,err} in daemon mode
Changaco <changaco ατ changaco δοτ net>
parents:
16
diff
changeset
|
299 for f in [sys.stdin, sys.stdout, sys.stderr]: |
421a3416e768
close std{in,out,err} in daemon mode
Changaco <changaco ατ changaco δοτ net>
parents:
16
diff
changeset
|
300 f.flush() |
421a3416e768
close std{in,out,err} in daemon mode
Changaco <changaco ατ changaco δοτ net>
parents:
16
diff
changeset
|
301 os.dup2(null.fileno(), f.fileno()) |
1 | 302 |
303 state = {'id_cache': {}} | |
304 saved_state = global_args.state_file.read().strip() | |
305 if len(saved_state) > 0: | |
306 state.update(json.loads(saved_state)) | |
307 del saved_state | |
308 | |
22
b763ca084088
import gamin in __main__
Changaco <changaco ατ changaco δοτ net>
parents:
21
diff
changeset
|
309 import gamin |
1 | 310 monitor = gamin.WatchMonitor() |
32
5348758c622d
don't keep file descriptors open
Changaco <changaco ατ changaco δοτ net>
parents:
31
diff
changeset
|
311 watched_feeds = set() |
1 | 312 config_to_feed_paths_to_commands = {} |
313 if hasattr(global_args.config, 'read'): | |
314 os.chdir(os.path.dirname(global_args.config.name)) | |
18
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
315 monitor.watch_file(global_args.config.name, handler(handle_config_change)) |
1 | 316 else: |
317 os.chdir(global_args.config) | |
18
868a339b19f8
log exceptions, exit when logging fails
Changaco <changaco ατ changaco δοτ net>
parents:
17
diff
changeset
|
318 monitor.watch_directory(global_args.config, handler(handle_config_change)) |
1 | 319 |
20
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
320 if global_args.fork: |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
321 while True: |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
322 monitor.handle_one_event() |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
323 else: |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
324 try: |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
325 while True: |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
326 monitor.handle_events() |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
327 time.sleep(1) |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
328 except KeyboardInterrupt: |
94f3b22beec9
use polling in non-fork mode to catch KeyboardInterrupt
Changaco <changaco ατ changaco δοτ net>
parents:
19
diff
changeset
|
329 exit(0) |