comparison foodtruck/pubutil.py @ 602:c6bc0ef03f82

admin: Better UI for publishing websites. * Support multiple publish targets. * Dedicated UI for publishing. * Some UI polish.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 27 Jan 2016 18:02:25 -0800
parents
children 978d8bca9fb3
comparison
equal deleted inserted replaced
601:effbc78b5528 602:c6bc0ef03f82
1 import os
2 import os.path
3 import time
4 import signal
5 import logging
6 from .web import app
7
8
9 logger = logging.getLogger(__name__)
10
11 server_shutdown = False
12
13
14 def _shutdown_server_and_raise_sigint():
15 if not app.debug or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
16 # This is needed when hitting CTRL+C to shutdown the Werkzeug server,
17 # otherwise SSE generators will keep it alive.
18 logger.debug("Shutting down SSE generators...")
19 global server_shutdown
20 server_shutdown = True
21 raise KeyboardInterrupt()
22
23
24 if app.config['FOODTRUCK_CMDLINE_MODE']:
25 # Make sure CTRL+C works correctly.
26 signal.signal(signal.SIGINT,
27 lambda *args: _shutdown_server_and_raise_sigint())
28
29
30 class PublishLogReader(object):
31 _pub_max_time = 10 * 60 # Don't bother about pubs older than 10mins.
32 _poll_interval = 2 # Check the PID file every 2 seconds.
33 _ping_interval = 30 # Send a ping message every 30 seconds.
34
35 def __init__(self, pid_path, log_path):
36 self.pid_path = pid_path
37 self.log_path = log_path
38 self._pub_pid_mtime = 0
39 self._last_seek = 0
40 self._last_ping_time = 0
41
42 def run(self):
43 logger.debug("Opening publish log...")
44
45 try:
46 while not server_shutdown:
47 # PING!
48 interval = time.time() - self._last_ping_time
49 if interval > self._ping_interval:
50 logger.debug("Sending ping...")
51 self._last_ping_time = time.time()
52 yield bytes("event: ping\ndata: 1\n\n", 'utf8')
53
54 # Check pid file.
55 prev_mtime = self._pub_pid_mtime
56 try:
57 self._pub_pid_mtime = os.path.getmtime(self.pid_path)
58 if time.time() - self._pub_pid_mtime > \
59 self._pub_max_time:
60 self._pub_pid_mtime = 0
61 except OSError:
62 self._pub_pid_mtime = 0
63
64 # Send data.
65 new_data = None
66 if self._pub_pid_mtime > 0 or prev_mtime > 0:
67 if self._last_seek == 0:
68 outstr = 'event: message\ndata: Publish started.\n\n'
69 yield bytes(outstr, 'utf8')
70
71 try:
72 with open(self.log_path, 'r', encoding='utf8') as fp:
73 fp.seek(self._last_seek)
74 new_data = fp.read()
75 self._last_seek = fp.tell()
76 except OSError:
77 pass
78 if self._pub_pid_mtime == 0:
79 self._last_seek = 0
80
81 if new_data:
82 logger.debug("SSE: %s" % outstr)
83 for line in new_data.split('\n'):
84 outstr = 'event: message\ndata: %s\n\n' % line
85 yield bytes(outstr, 'utf8')
86
87 time.sleep(self._poll_interval)
88
89 except GeneratorExit:
90 pass
91
92 logger.debug("Closing publish log...")
93