Merge pull request #1520 from MycroftAI/feature/api-etags

Add support for ETag caching
pull/860/merge
Åke 2018-04-05 11:46:59 +02:00 committed by GitHub
commit bcc423825c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 37 additions and 3 deletions

View File

@ -14,6 +14,7 @@
#
from copy import copy
import json
import requests
from requests import HTTPError, RequestException
@ -39,6 +40,8 @@ class InternetDown(RequestException):
class Api(object):
""" Generic object to wrap web APIs """
params_to_etag = {}
etag_to_response = {}
def __init__(self, path):
self.path = path
@ -76,14 +79,45 @@ class Api(object):
IdentityManager.save(data)
def send(self, params):
""" Send request to mycroft backend.
The method handles Etags and will return a cached response value
if nothing has changed on the remote.
Arguments:
params (dict): request parameters
Returns:
Requests response object.
"""
query_data = frozenset(params.get('query', {}).items())
params_key = (params.get('path'), query_data)
etag = self.params_to_etag.get(params_key)
method = params.get("method", "GET")
headers = self.build_headers(params)
data = self.build_data(params)
json = self.build_json(params)
json_body = self.build_json(params)
query = self.build_query(params)
url = self.build_url(params)
response = requests.request(method, url, headers=headers, params=query,
data=data, json=json, timeout=(3.05, 15))
# For an introduction to the Etag feature check out:
# https://en.wikipedia.org/wiki/HTTP_ETag
if etag:
headers['If-None-Match'] = etag
response = requests.request(
method, url, headers=headers, params=query,
data=data, json=json_body, timeout=(3.05, 15)
)
if response.status_code == 304:
LOG.debug('Etag matched. Nothing changed for: ' + params['path'])
response = self.etag_to_response[etag]
elif 'ETag' in response.headers:
etag = response.headers['ETag'].strip('"')
LOG.debug('Updating etag for: ' + params['path'])
self.params_to_etag[params_key] = etag
self.etag_to_response[etag] = response
return self.get_response(response)
def get_response(self, response):