speedup tileserver by factor 2x (not 0.6ms per request)

This commit is contained in:
Laura Klünder 2017-11-21 01:29:35 +01:00
parent 0f6b372b92
commit d74d9a8a77

View file

@ -3,7 +3,6 @@ import logging
import os import os
import re import re
import time import time
from http.cookies import SimpleCookie
from io import BytesIO from io import BytesIO
import requests import requests
@ -19,7 +18,8 @@ logger = logging.getLogger('c3nav')
class TileServer: class TileServer:
regex = re.compile(r'^/(?P<level>\d+)/(?P<zoom>\d+)/(?P<x>-?\d+)/(?P<y>-?\d+).png$') path_regex = re.compile(r'^/(\d+)/(\d+)/(-?\d+)/(-?\d+).png$')
cookie_regex = re.compile(r'[^ ]c3nav_tile_access=([^; ])')
def __init__(self): def __init__(self):
try: try:
@ -86,11 +86,13 @@ class TileServer:
return [text] return [text]
def __call__(self, env, start_response): def __call__(self, env, start_response):
match = self.regex.match(env['PATH_INFO']) match = self.path_regex.match(env['PATH_INFO'])
if match is None: if match is None:
return self.not_found(start_response, b'invalid tile path.') return self.not_found(start_response, b'invalid tile path.')
zoom = int(match.group('zoom')) level, zoom, x, y = match.groups()
zoom = int(zoom)
if not (0 <= zoom <= 10): if not (0 <= zoom <= 10):
return self.not_found(start_response, b'zoom out of bounds.') return self.not_found(start_response, b'zoom out of bounds.')
@ -98,25 +100,25 @@ class TileServer:
cache_package = self.cache_package cache_package = self.cache_package
# check if bounds are valid # check if bounds are valid
x = int(match.group('x')) x = int(x)
y = int(match.group('y')) y = int(y)
minx, miny, maxx, maxy = get_tile_bounds(zoom, x, y) minx, miny, maxx, maxy = get_tile_bounds(zoom, x, y)
if not cache_package.bounds_valid(minx, miny, maxx, maxy): if not cache_package.bounds_valid(minx, miny, maxx, maxy):
return self.not_found(start_response, b'coordinates out of bounds.') return self.not_found(start_response, b'coordinates out of bounds.')
# get level # get level
level = int(match.group('level')) level = int(level)
level_data = cache_package.levels.get(level) level_data = cache_package.levels.get(level)
if level_data is None: if level_data is None:
return self.not_found(start_response, b'invalid level.') return self.not_found(start_response, b'invalid level.')
# decode access permissions # decode access permissions
try: cookie = env.get('HTTP_COOKIE', None)
cookie = SimpleCookie(env['HTTP_COOKIE'])['c3nav_tile_access'].value if cookie:
except KeyError: cookie = self.cookie_regex.match(cookie)
access_permissions = set() if cookie:
else: cookie = cookie.group(0)
access_permissions = parse_tile_access_cookie(cookie, self.tile_secret) access_permissions = parse_tile_access_cookie(cookie, self.tile_secret) if cookie else set()
# only access permissions that are affecting this tile # only access permissions that are affecting this tile
access_permissions &= set(level_data.restrictions[minx:miny, maxx:maxy]) access_permissions &= set(level_data.restrictions[minx:miny, maxx:maxy])
@ -127,8 +129,9 @@ class TileServer:
access_cache_key = build_access_cache_key(access_permissions) access_cache_key = build_access_cache_key(access_permissions)
# check browser cache # check browser cache
tile_etag = build_tile_etag(level, zoom, x, y, base_cache_key, access_cache_key, self.tile_secret)
if_none_match = env.get('HTTP_IF_NONE_MATCH') if_none_match = env.get('HTTP_IF_NONE_MATCH')
if if_none_match:
tile_etag = build_tile_etag(level, zoom, x, y, base_cache_key, access_cache_key, self.tile_secret)
if if_none_match == tile_etag: if if_none_match == tile_etag:
start_response('304 Not Modified', [('Content-Type', 'text/plain'), ('ETag', tile_etag)]) start_response('304 Not Modified', [('Content-Type', 'text/plain'), ('ETag', tile_etag)])
return [b''] return [b'']