From c74cbf6108548f63acaac5d119893a2eaaaea852 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 8 Aug 2017 14:56:34 +1000 Subject: [PATCH] fix media server port allocation the old code was allowing the main thread to read .port before it had been updated, and was binding to sockets that were already in use on Windows. instead, we use a system-assigned free port and block the main thread until it's been allocated --- aqt/main.py | 2 +- aqt/mediasrv.py | 21 +++++++++------------ aqt/webview.py | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/aqt/main.py b/aqt/main.py index 6fbde4b32..a44153883 100644 --- a/aqt/main.py +++ b/aqt/main.py @@ -1195,4 +1195,4 @@ Please ensure a profile is open and Anki is not busy, then try again."""), self.mediaServer.start() def baseHTML(self): - return '' % self.mediaServer.port + return '' % self.mediaServer.getPort() diff --git a/aqt/mediasrv.py b/aqt/mediasrv.py index f5f788b46..6b8430f4e 100644 --- a/aqt/mediasrv.py +++ b/aqt/mediasrv.py @@ -32,21 +32,18 @@ class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer): class MediaServer(threading.Thread): + _port = None + _ready = threading.Event() + def run(self): - self.port = 10000 - self.server = None - while not self.server: - try: - self.server = ThreadedHTTPServer( - ("localhost", self.port), RequestHandler) - except OSError as e: - if e.errno == errno.EADDRINUSE: - self.port += 1 - continue - raise - break + self.server = ThreadedHTTPServer(("localhost", 0), RequestHandler) + self._ready.set() self.server.serve_forever() + def getPort(self): + self._ready.wait() + return self.server.server_port + def shutdown(self): self.server.shutdown() diff --git a/aqt/webview.py b/aqt/webview.py index aa38d775e..0a6341d26 100644 --- a/aqt/webview.py +++ b/aqt/webview.py @@ -197,7 +197,7 @@ body { zoom: %f; %s } def webBundlePath(self, path): from aqt import mw - return "http://localhost:%d/_anki/%s" % (mw.mediaServer.port, path) + return "http://localhost:%d/_anki/%s" % (mw.mediaServer.getPort(), path) def bundledScript(self, fname): return '' % self.webBundlePath(fname)