Fixing the cache?
This commit is contained in:
78
rtv/oauth.py
78
rtv/oauth.py
@@ -10,7 +10,6 @@ import logging
|
|||||||
import threading
|
import threading
|
||||||
|
|
||||||
#pylint: disable=import-error
|
#pylint: disable=import-error
|
||||||
import requests
|
|
||||||
from six.moves.urllib.parse import urlparse, parse_qs
|
from six.moves.urllib.parse import urlparse, parse_qs
|
||||||
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
|
||||||
@@ -18,6 +17,7 @@ from . import docs
|
|||||||
from .config import TEMPLATES
|
from .config import TEMPLATES
|
||||||
from .exceptions import InvalidRefreshToken
|
from .exceptions import InvalidRefreshToken
|
||||||
from .packages.praw.errors import HTTPException, OAuthException
|
from .packages.praw.errors import HTTPException, OAuthException
|
||||||
|
from .packages.praw.handlers import DefaultHandler
|
||||||
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
@@ -218,8 +218,6 @@ class OAuthHelper(object):
|
|||||||
if self.term.loader.exception:
|
if self.term.loader.exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.reddit.handler.reset()
|
|
||||||
|
|
||||||
message = 'Welcome {}!'.format(self.reddit.user.name)
|
message = 'Welcome {}!'.format(self.reddit.user.name)
|
||||||
self.term.show_notification(message)
|
self.term.show_notification(message)
|
||||||
|
|
||||||
@@ -229,37 +227,46 @@ class OAuthHelper(object):
|
|||||||
|
|
||||||
def clear_oauth_data(self):
|
def clear_oauth_data(self):
|
||||||
self.reddit.clear_authentication()
|
self.reddit.clear_authentication()
|
||||||
self.reddit.handler.reset()
|
|
||||||
self.config.delete_refresh_token()
|
self.config.delete_refresh_token()
|
||||||
|
|
||||||
|
|
||||||
class OAuthRateLimitHandler(object):
|
def fix_cache(func):
|
||||||
|
def wraps(self, _cache_key, _cache_ignore, *args, **kwargs):
|
||||||
|
if _cache_key:
|
||||||
|
# Remove the request's session cookies from the cache key.
|
||||||
|
# These appear to be unreliable and change with every
|
||||||
|
# request. Also, with the introduction of OAuth I don't think
|
||||||
|
# that cookies are being used to store anything that
|
||||||
|
# differentiates requests anymore
|
||||||
|
url, items = _cache_key
|
||||||
|
_cache_key = (url, (items[0], items[1], items[3], items[4]))
|
||||||
|
|
||||||
|
if kwargs['request'].method != 'GET':
|
||||||
|
# Why were POST/PUT/DELETE requests ever cached???
|
||||||
|
_cache_ignore = True
|
||||||
|
|
||||||
|
return func(self, _cache_key, _cache_ignore, *args, **kwargs)
|
||||||
|
return wraps
|
||||||
|
|
||||||
|
|
||||||
|
class OAuthRateLimitHandler(DefaultHandler):
|
||||||
"""Custom PRAW request handler for rate-limiting requests.
|
"""Custom PRAW request handler for rate-limiting requests.
|
||||||
|
|
||||||
This is structured as a drop-in replacement for the
|
This is an alternative to PRAW 3's DefaultHandler that uses
|
||||||
praw.handlers.DefaultHandler. It uses Reddit's modern API guidelines
|
Reddit's modern API guidelines to rate-limit requests based
|
||||||
to rate-limit based on the X-Ratelimit-* headers returned from http
|
on the X-Ratelimit-* headers returned from Reddit.
|
||||||
requests. It does not use a 30 second cache or arbitrary sleeps before
|
|
||||||
each request. Unlike the other PRAW 3 handlers, it does not attempt to
|
|
||||||
be thread-safe or multiprocess safe.
|
|
||||||
|
|
||||||
References:
|
References:
|
||||||
https://github.com/reddit/reddit/wiki/API
|
https://github.com/reddit/reddit/wiki/API
|
||||||
https://github.com/praw-dev/prawcore/blob/master/prawcore/rate_limit.py
|
https://github.com/praw-dev/prawcore/blob/master/prawcore/rate_limit.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
next_request_timestamp = None
|
||||||
self.http = requests.Session()
|
|
||||||
self.next_request_timestamp = None
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.next_request_timestamp = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def evict(cls, urls):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def delay(self):
|
def delay(self):
|
||||||
|
"""
|
||||||
|
Pause before making the next HTTP request.
|
||||||
|
"""
|
||||||
if self.next_request_timestamp is None:
|
if self.next_request_timestamp is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -269,7 +276,8 @@ class OAuthRateLimitHandler(object):
|
|||||||
time.sleep(sleep_seconds)
|
time.sleep(sleep_seconds)
|
||||||
|
|
||||||
def update(self, response_headers):
|
def update(self, response_headers):
|
||||||
"""Update the state of the rate limiter based on the response headers.
|
"""
|
||||||
|
Update the state of the rate limiter based on the response headers:
|
||||||
|
|
||||||
X-Ratelimit-Used: Approximate number of requests used this period
|
X-Ratelimit-Used: Approximate number of requests used this period
|
||||||
X-Ratelimit-Remaining: Approximate number of requests left to use
|
X-Ratelimit-Remaining: Approximate number of requests left to use
|
||||||
@@ -292,38 +300,26 @@ class OAuthRateLimitHandler(object):
|
|||||||
# which Reddit doesn't appear to care about rate limiting.
|
# which Reddit doesn't appear to care about rate limiting.
|
||||||
return
|
return
|
||||||
|
|
||||||
|
used = float(response_headers['x-ratelimit-used'])
|
||||||
remaining = float(response_headers['x-ratelimit-remaining'])
|
remaining = float(response_headers['x-ratelimit-remaining'])
|
||||||
seconds_to_reset = int(response_headers['x-ratelimit-reset'])
|
seconds_to_reset = int(response_headers['x-ratelimit-reset'])
|
||||||
|
_logger.debug('Rate limit: %s used, %s remaining, %s reset',
|
||||||
|
used, remaining, seconds_to_reset)
|
||||||
|
|
||||||
if remaining <= 0:
|
if remaining <= 0:
|
||||||
self.next_request_timestamp = time.time() + seconds_to_reset
|
self.next_request_timestamp = time.time() + seconds_to_reset
|
||||||
else:
|
else:
|
||||||
self.next_request_timestamp = None
|
self.next_request_timestamp = None
|
||||||
|
|
||||||
|
@fix_cache
|
||||||
|
@DefaultHandler.with_cache
|
||||||
def request(self, request, proxies, timeout, verify, **_):
|
def request(self, request, proxies, timeout, verify, **_):
|
||||||
"""Responsible for dispatching the request and returning the result.
|
|
||||||
|
|
||||||
Network level exceptions should be raised and only
|
|
||||||
``requests.Response`` should be returned.
|
|
||||||
|
|
||||||
:param request: A ``requests.PreparedRequest`` object containing all
|
|
||||||
the data necessary to perform the request.
|
|
||||||
:param proxies: A dictionary of proxy settings to be utilized for the
|
|
||||||
request.
|
|
||||||
:param timeout: Specifies the maximum time that the actual HTTP request
|
|
||||||
can take.
|
|
||||||
:param verify: Specifies if SSL certificates should be validated.
|
|
||||||
|
|
||||||
``**_`` should be added to the method call to ignore the extra
|
|
||||||
arguments intended for the cache handler.
|
|
||||||
|
|
||||||
"""
|
|
||||||
settings = self.http.merge_environment_settings(
|
settings = self.http.merge_environment_settings(
|
||||||
request.url, proxies, False, verify, None
|
request.url, proxies, False, verify, None)
|
||||||
)
|
|
||||||
|
|
||||||
self.delay()
|
self.delay()
|
||||||
response = self.http.send(
|
response = self.http.send(
|
||||||
request, timeout=timeout, allow_redirects=False, **settings)
|
request, timeout=timeout, allow_redirects=False, **settings)
|
||||||
self.update(response.headers)
|
self.update(response.headers)
|
||||||
return response
|
return response
|
||||||
@@ -81,6 +81,11 @@ class Page(object):
|
|||||||
ch = self.term.stdscr.getch()
|
ch = self.term.stdscr.getch()
|
||||||
self.controller.trigger(ch)
|
self.controller.trigger(ch)
|
||||||
|
|
||||||
|
@PageController.register(Command('REFRESH'))
|
||||||
|
def reload_page(self):
|
||||||
|
self.reddit.handler.clear_cache()
|
||||||
|
self.refresh_content()
|
||||||
|
|
||||||
@PageController.register(Command('EXIT'))
|
@PageController.register(Command('EXIT'))
|
||||||
def exit(self):
|
def exit(self):
|
||||||
if self.term.prompt_y_or_n('Do you really want to quit? (y/n): '):
|
if self.term.prompt_y_or_n('Do you really want to quit? (y/n): '):
|
||||||
@@ -254,7 +259,7 @@ class Page(object):
|
|||||||
# Give reddit time to process the request
|
# Give reddit time to process the request
|
||||||
time.sleep(2.0)
|
time.sleep(2.0)
|
||||||
if self.term.loader.exception is None:
|
if self.term.loader.exception is None:
|
||||||
self.refresh_content()
|
self.reload_page()
|
||||||
|
|
||||||
@PageController.register(Command('EDIT'))
|
@PageController.register(Command('EDIT'))
|
||||||
@logged_in
|
@logged_in
|
||||||
@@ -290,7 +295,7 @@ class Page(object):
|
|||||||
time.sleep(2.0)
|
time.sleep(2.0)
|
||||||
|
|
||||||
if self.term.loader.exception is None:
|
if self.term.loader.exception is None:
|
||||||
self.refresh_content()
|
self.reload_page()
|
||||||
else:
|
else:
|
||||||
raise TemporaryFileError()
|
raise TemporaryFileError()
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ class SubmissionPage(Page):
|
|||||||
|
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
@SubmissionController.register(Command('REFRESH'))
|
|
||||||
def refresh_content(self, order=None, name=None):
|
def refresh_content(self, order=None, name=None):
|
||||||
"""
|
"""
|
||||||
Re-download comments and reset the page index
|
Re-download comments and reset the page index
|
||||||
@@ -188,7 +187,7 @@ class SubmissionPage(Page):
|
|||||||
time.sleep(2.0)
|
time.sleep(2.0)
|
||||||
|
|
||||||
if self.term.loader.exception is None:
|
if self.term.loader.exception is None:
|
||||||
self.refresh_content()
|
self.reload_page()
|
||||||
else:
|
else:
|
||||||
raise TemporaryFileError()
|
raise TemporaryFileError()
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ class SubredditPage(Page):
|
|||||||
self.nav = Navigator(self.content.get)
|
self.nav = Navigator(self.content.get)
|
||||||
self.toggled_subreddit = None
|
self.toggled_subreddit = None
|
||||||
|
|
||||||
@SubredditController.register(Command('REFRESH'))
|
|
||||||
def refresh_content(self, order=None, name=None):
|
def refresh_content(self, order=None, name=None):
|
||||||
"""
|
"""
|
||||||
Re-download all submissions and reset the page index
|
Re-download all submissions and reset the page index
|
||||||
@@ -209,7 +208,7 @@ class SubredditPage(Page):
|
|||||||
self.content = page.selected_subreddit
|
self.content = page.selected_subreddit
|
||||||
self.nav = Navigator(self.content.get)
|
self.nav = Navigator(self.content.get)
|
||||||
else:
|
else:
|
||||||
self.refresh_content()
|
self.reload_page()
|
||||||
|
|
||||||
@SubredditController.register(Command('SUBREDDIT_OPEN_SUBSCRIPTIONS'))
|
@SubredditController.register(Command('SUBREDDIT_OPEN_SUBSCRIPTIONS'))
|
||||||
@logged_in
|
@logged_in
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class SubscriptionPage(Page):
|
|||||||
self.content_type = content_type
|
self.content_type = content_type
|
||||||
self.selected_subreddit = None
|
self.selected_subreddit = None
|
||||||
|
|
||||||
@SubscriptionController.register(Command('REFRESH'))
|
|
||||||
def refresh_content(self, order=None, name=None):
|
def refresh_content(self, order=None, name=None):
|
||||||
"""
|
"""
|
||||||
Re-download all subscriptions and reset the page index
|
Re-download all subscriptions and reset the page index
|
||||||
|
|||||||
Reference in New Issue
Block a user