From 8e6758a38990ca7ea1ac6309c486c6121c2df78f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Piboub=C3=A8s?= Date: Sat, 5 Sep 2015 16:25:34 +0200 Subject: [PATCH 1/4] Open terminal web browser asynchronously --- rtv/oauth.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/rtv/oauth.py b/rtv/oauth.py index 307cf4a..f696918 100644 --- a/rtv/oauth.py +++ b/rtv/oauth.py @@ -11,7 +11,8 @@ from six.moves import configparser from . import config from .curses_helpers import show_notification, prompt_input -from tornado import ioloop, web +from tornado import gen, ioloop, web +from concurrent.futures import ThreadPoolExecutor __all__ = ['token_validity', 'OAuthTool'] _logger = logging.getLogger(__name__) @@ -28,18 +29,15 @@ class HomeHandler(web.RequestHandler): class AuthHandler(web.RequestHandler): def get(self): - try: - global oauth_state - global oauth_code - global oauth_error + global oauth_state + global oauth_code + global oauth_error - oauth_state = self.get_argument('state', default='state_placeholder') - oauth_code = self.get_argument('code', default='code_placeholder') - oauth_error = self.get_argument('error', default='error_placeholder') + oauth_state = self.get_argument('state', default='state_placeholder') + oauth_code = self.get_argument('code', default='code_placeholder') + oauth_error = self.get_argument('error', default='error_placeholder') - self.render('auth.html', state=oauth_state, code=oauth_code, error=oauth_error) - finally: - ioloop.IOLoop.current().stop() + self.render('auth.html', state=oauth_state, code=oauth_code, error=oauth_error) class OAuthTool(object): @@ -99,6 +97,13 @@ class OAuthTool(object): self.config.remove_option('oauth', 'refresh_token') self.save_config() + @gen.coroutine + def open_terminal_browser(self, url): + with ThreadPoolExecutor(max_workers=1) as executor: + yield executor.submit(webbrowser.open_new_tab, url) + + ioloop.IOLoop.current().stop() + def authorize(self): if self.compact and not '.compact' in self.reddit.config.API_PATHS['authorize']: self.reddit.config.API_PATHS['authorize'] += '.compact' @@ -112,7 +117,7 @@ class OAuthTool(object): if not self.config.has_section('oauth') or not self.config.has_option('oauth', 'refresh_token'): # Start HTTP server and listen on port 65000 self.callback_app.listen(65000) - + # Generate a random UUID hex_uuid = uuid.uuid4().hex @@ -122,7 +127,7 @@ class OAuthTool(object): if self.compact: show_notification(self.stdscr, ['Opening ' + os.environ.get('BROWSER')]) curses.endwin() - webbrowser.open_new_tab(permission_ask_page_link) + ioloop.IOLoop.current().add_callback(self.open_terminal_browser, permission_ask_page_link) ioloop.IOLoop.current().start() curses.doupdate() else: From e90dcc6e5cd478e5f27a97520ccd4a0299bb9ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Piboub=C3=A8s?= Date: Sat, 5 Sep 2015 16:29:31 +0200 Subject: [PATCH 2/4] Start HTTP server only once --- rtv/oauth.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rtv/oauth.py b/rtv/oauth.py index f696918..1dfcc67 100644 --- a/rtv/oauth.py +++ b/rtv/oauth.py @@ -11,7 +11,7 @@ from six.moves import configparser from . import config from .curses_helpers import show_notification, prompt_input -from tornado import gen, ioloop, web +from tornado import gen, ioloop, web, httpserver from concurrent.futures import ThreadPoolExecutor __all__ = ['token_validity', 'OAuthTool'] @@ -67,6 +67,8 @@ class OAuthTool(object): (r'/auth', AuthHandler), ], template_path='rtv/templates') + self.http_server = None + def get_config_fp(self): HOME = os.path.expanduser('~') XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME', @@ -115,8 +117,9 @@ class OAuthTool(object): self.open_config(update=True) # If no previous OAuth data found, starting from scratch if not self.config.has_section('oauth') or not self.config.has_option('oauth', 'refresh_token'): - # Start HTTP server and listen on port 65000 - self.callback_app.listen(65000) + if self.http_server is None: + self.http_server = httpserver.HTTPServer(self.callback_app) + self.http_server.listen(65000) # Generate a random UUID hex_uuid = uuid.uuid4().hex From a84ac2f61e4ec6e81bcce926618eb01bcccf4eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Piboub=C3=A8s?= Date: Sat, 5 Sep 2015 16:36:12 +0200 Subject: [PATCH 3/4] Stop IOLoop when callback page reached with GUI browser --- rtv/oauth.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rtv/oauth.py b/rtv/oauth.py index 1dfcc67..6a51ada 100644 --- a/rtv/oauth.py +++ b/rtv/oauth.py @@ -28,6 +28,9 @@ class HomeHandler(web.RequestHandler): class AuthHandler(web.RequestHandler): + def initialize(self): + self.compact = os.environ.get('BROWSER') in ['w3m', 'links', 'elinks', 'lynx'] + def get(self): global oauth_state global oauth_code @@ -39,6 +42,10 @@ class AuthHandler(web.RequestHandler): self.render('auth.html', state=oauth_state, code=oauth_code, error=oauth_error) + # Stop IOLoop if using BackgroundBrowser (or GUI browser) + if not self.compact: + ioloop.IOLoop.current().stop() + class OAuthTool(object): def __init__(self, reddit, stdscr=None, loader=None, From c8a2b480421f279f9df6aaf50967b60fb8fa09ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Piboub=C3=A8s?= Date: Sun, 6 Sep 2015 02:39:41 +0200 Subject: [PATCH 4/4] Python 2 concurrent.futures backport requirement --- setup.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 38d0d08..f00c25d 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,14 @@ from setuptools import setup from version import __version__ as version +import sys + +requirements = ['tornado', 'praw>=3.1.0', 'six', 'requests', 'kitchen'] + +# Python 2: add required concurrent.futures backport from Python 3.2 +if sys.version_info.major <= 2: + requirements.append('futures') + setup( name='rtv', version=version, @@ -13,7 +21,7 @@ setup( keywords='reddit terminal praw curses', packages=['rtv'], include_package_data=True, - install_requires=['tornado', 'praw>=3.1.0', 'six', 'requests', 'kitchen'], + install_requires=requirements, entry_points={'console_scripts': ['rtv=rtv.__main__:main']}, classifiers=[ 'Intended Audience :: End Users/Desktop',