Skip to content

Commit

Permalink
Use long polling for reloading the page on rebuild.
Browse files Browse the repository at this point in the history
  • Loading branch information
rblank committed Sep 13, 2024
1 parent 3998993 commit f6a8de6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 18 deletions.
50 changes: 34 additions & 16 deletions tdoc/common/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import sys
import threading
import time
from urllib import parse

from .. import common
from . import util
Expand Down Expand Up @@ -144,7 +145,7 @@ def sphinx_build(cfg, target, *, build, tags=(), **kwargs):
class ServerBase(server.ThreadingHTTPServer):
def __init__(self, *args, cfg, **kwargs):
self.cfg = cfg
self.lock = threading.Lock()
self.lock = threading.Condition(threading.Lock())
self.directory = self.build_dir(0) / 'html'
self.upgrade_msg = None
self.stop = False
Expand All @@ -166,6 +167,12 @@ def finish_request(self, request, client_addr):
self.RequestHandlerClass(request, client_addr, self,
directory=directory)

IGNORED_EXCEPTIONS = (BrokenPipeError,)

def handle_error(self, request, client_addr):
if not isinstance(sys.exception(), self.IGNORED_EXCEPTIONS):
super().handle_error(request, client_addr)

def server_close(self):
with self.lock: self.stop = True
self.builder.join()
Expand Down Expand Up @@ -196,6 +203,7 @@ def watch_and_build(self):
with self.lock:
self.build_mtime = mtime
self.directory = build / 'html'
self.lock.notify_all()
self.print_serving()
if build_mtime is not None: self.remove_build_dir(build_mtime)
build_mtime = mtime
Expand Down Expand Up @@ -278,23 +286,33 @@ def log_message(self, format, *args):
(format % args).translate(self._control_char_table)))

def do_GET(self):
if self.path == '/*build':
if tag := self.handle_build():
self.wfile.write(tag)
return
super().do_GET()
if not self.dispatch_star_handler(True):
super().do_GET()

def do_HEAD(self):
if self.path == '/*build':
self.handle_build()
return
super().do_HEAD()

def handle_build(self):
with self.server.lock: mtime = self.server.build_mtime
if mtime is None:
self.send_error(server.HTTPStatus.SERVICE_UNAVAILABLE)
return
if not self.dispatch_star_handler(False):
super().do_HEAD()

def dispatch_star_handler(self, write_content):
url = parse.urlparse(self.path)
if not url.path.startswith('/*'): return
if handler := getattr(self, f'handle_star_{url.path[2:]}', None):
content = handler(url)
if write_content and content: self.wfile.write(content)
else:
self.send_error(server.HTTPStatus.NOT_FOUND)
return True

def handle_star_build(self, url):
t = None
for k, v in parse.parse_qsl(url.query):
if k == 't':
t = v
break
with self.server.lock:
while ((mtime := self.server.build_mtime) is None
or t == build_tag(mtime)):
self.server.lock.wait()
tag = build_tag(mtime).encode('utf-8')
self.send_response(server.HTTPStatus.OK)
self.send_header('Content-type', 'text/plain')
Expand Down
6 changes: 4 additions & 2 deletions tdoc/common/static/tdoc-reload.js.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ function sleep(ms) {

async function reloadOnTagChange() {
for (;;) {
await sleep(500);
try {
const resp = await fetch(document.location.origin + '/*build');
const resp = await fetch(
`${document.location.origin}/*build?t=${build}`);
if (!resp.ok) {
console.error(`Build tag request failed: ${resp.status} ` +
`${resp.statusText}`);
Expand All @@ -22,6 +22,8 @@ async function reloadOnTagChange() {
if (tag !== build) location.reload();
} catch (e) {
console.error(e);
} finally {
await sleep(1000);
}
}
}
Expand Down

0 comments on commit f6a8de6

Please sign in to comment.