diff --git a/lib/brotli.py b/lib/brotli.py index b41ac2a..cf0fca6 100644 --- a/lib/brotli.py +++ b/lib/brotli.py @@ -1,16 +1,18 @@ -import brotli -from flask import request +from brotli import compress +from flask import request, make_response from functools import wraps from threading import Thread from hashlib import sha256 import redis +import os.path +import mimetypes class BrotliCache(object): def __init__(self, redis_kwargs={}): self.redis = redis.StrictRedis(**redis_kwargs) def compress(self, cache_key, lock_key, body): - encbody = brotli.compress(body) + encbody = compress(body) self.redis.set(cache_key, encbody, ex=3600) self.redis.delete(lock_key) @@ -25,13 +27,35 @@ class BrotliCache(object): encbody = self.redis.get(cache_key) if encbody: response.headers.set('content-encoding', 'br') - response.headers.set('vary', 'content-encoding') + response.headers.set('vary', 'accept-encoding') response.set_data(encbody) return response else: lock_key = 'brotlicache:lock:{}'.format(digest) - if self.redis.set(lock_key, 1, nx=True, ex=60): + if self.redis.set(lock_key, 1, nx=True, ex=10): t = Thread(target=self.compress, args=(cache_key, lock_key, body)) t.run() return response + +def brotli(app, static = True, dynamic = True): + original_static = app.view_functions['static'] + def static_maybe_gzip_brotli(filename=None): + path = os.path.join(app.static_folder, filename) + for encoding, extension in (('br', '.br'), ('gzip', '.gz')): + if encoding not in request.accept_encodings: + continue + encpath = path + extension + if os.path.isfile(encpath): + resp = make_response(original_static(filename=filename + extension)) + resp.headers.set('content-encoding', encoding) + resp.headers.set('vary', 'accept-encoding') + mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' + resp.headers.set('content-type', mimetype) + return resp + return original_static(filename=filename) + if static: + app.view_functions['static'] = static_maybe_gzip_brotli + if dynamic: + cache = BrotliCache() + app.after_request(cache.wrap_response) diff --git a/routes.py b/routes.py index 34a1226..21d1201 100644 --- a/routes.py +++ b/routes.py @@ -36,9 +36,8 @@ def touch_viewer(resp): db.session.commit() return resp -brcache = lib.brotli.BrotliCache(app.config.get('REDIS', {})) -app.after_request(brcache.wrap_response) +lib.brotli.brotli(app) @app.route('/') def index():