diff options
author | Lars-Dominik Braun <lars@6xq.net> | 2018-05-01 15:43:34 +0200 |
---|---|---|
committer | Lars-Dominik Braun <lars@6xq.net> | 2018-05-04 16:00:05 +0200 |
commit | de2b4036ac7ce2d242d49fe37337db890c30da3b (patch) | |
tree | 9bb0b6bb5813a5c3e6df684f4098a53760671ff7 /crocoite | |
parent | eb818f0c6eb86461a0db1845876f2a0b39b99b7f (diff) | |
download | crocoite-de2b4036ac7ce2d242d49fe37337db890c30da3b.tar.gz crocoite-de2b4036ac7ce2d242d49fe37337db890c30da3b.tar.bz2 crocoite-de2b4036ac7ce2d242d49fe37337db890c30da3b.zip |
browser: Replace context manager decorator
Use an actual class that supports multiple invokations.
Diffstat (limited to 'crocoite')
-rw-r--r-- | crocoite/browser.py | 117 |
1 files changed, 66 insertions, 51 deletions
diff --git a/crocoite/browser.py b/crocoite/browser.py index 7250b11..9e59556 100644 --- a/crocoite/browser.py +++ b/crocoite/browser.py @@ -340,64 +340,79 @@ class AccountingSiteLoader (SiteLoader): import subprocess from tempfile import mkdtemp -from contextlib import contextmanager import socket, shutil -@contextmanager -def ChromeService (binary='google-chrome-stable', host='localhost', port=9222, windowSize=(1920, 1080)): +class ChromeService: """ Start Chrome with socket activation (i.e. pass listening socket). Polling is not required with this method, since reads will block until Chrome is ready. """ - while True: - s = socket.socket () - s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - try: - s.bind ((host, port)) - break - except OSError: - # try different port - if port < 65000: - port += 1 - else: - raise - s.listen (10) - userDataDir = mkdtemp () - args = [binary, - '--window-size={},{}'.format (*windowSize), - '--user-data-dir={}'.format (userDataDir), # use temporory user dir - '--no-default-browser-check', - '--no-first-run', # don’t show first run screen - '--disable-breakpad', # no error reports - '--disable-extensions', - '--disable-infobars', - '--disable-notifications', # no libnotify - '--headless', - '--disable-gpu', - '--hide-scrollbars', # hide scrollbars on screenshots - '--mute-audio', # don’t play any audio - '--remote-debugging-socket-fd={}'.format (s.fileno ()), - '--homepage=about:blank', - 'about:blank'] - # start new session, so ^C does not affect subprocess - p = subprocess.Popen (args, pass_fds=[s.fileno()], start_new_session=True, - stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL) - s.close () - - # must be wrapped in try-finally, otherwise code in __exit__/finally is not - # executed - try: - yield 'http://{}:{}'.format (host, port) - finally: - p.terminate () - p.wait () - shutil.rmtree (userDataDir) - -@contextmanager -def NullService (url): - yield url + + def __init__ (self, binary='google-chrome-stable', host='localhost', port=9222, windowSize=(1920, 1080)): + self.binary = binary + self.host = host + self.port = port + self.windowSize = windowSize + self.p = None + + def __enter__ (self): + assert self.p is None + + port = self.port + while True: + s = socket.socket () + s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + s.bind ((self.host, port)) + break + except OSError: + # try different port + if port < 65000: + port += 1 + else: + raise + s.listen (10) + self.userDataDir = mkdtemp () + args = [self.binary, + '--window-size={},{}'.format (*self.windowSize), + '--user-data-dir={}'.format (self.userDataDir), # use temporory user dir + '--no-default-browser-check', + '--no-first-run', # don’t show first run screen + '--disable-breakpad', # no error reports + '--disable-extensions', + '--disable-infobars', + '--disable-notifications', # no libnotify + '--headless', + '--disable-gpu', + '--hide-scrollbars', # hide scrollbars on screenshots + '--mute-audio', # don’t play any audio + '--remote-debugging-socket-fd={}'.format (s.fileno ()), + '--homepage=about:blank', + 'about:blank'] + # start new session, so ^C does not affect subprocess + self.p = subprocess.Popen (args, pass_fds=[s.fileno()], start_new_session=True, + stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + s.close () + + return 'http://{}:{}'.format (self.host, port) + + def __exit__ (self, *exc): + self.p.terminate () + self.p.wait () + shutil.rmtree (self.userDataDir) + self.p = None + +class NullService: + def __init__ (self, url): + self.url = url + + def __enter__ (self): + return url + + def __exit__ (self, *exc): + pass ### tests ### |