-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
caching.py
86 lines (80 loc) · 3.05 KB
/
caching.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from md5 import md5
import json
from google.appengine.api import urlfetch
from google.appengine.api import memcache
import logging
STATION_INFO_TTL = 86400
STATION_STATUS_TTL = 20
ALERTS_TTL = 600
def hashed_key(url):
return md5(url).hexdigest()
def cache(ttl):
def decorator(fn):
def wrapper(*args, **kwargs):
key = hashed_key(args[0])
value = memcache.get(key)
if value is None:
value = fn(*args, **kwargs)
try:
added = memcache.add(key, value, ttl)
if not added:
logging.error('Memcache set failed.')
except ValueError:
logging.error('Memcache set failed - data larger than 1MB')
return value
return wrapper
return decorator
class MemcacheHolder:
def __init__(self,etag,content_type,data):
self.etag = etag
self.content_type = content_type
self.data = data
def http_purge(uri):
try:
key = hashed_key(uri)
memcache.delete(key)
except Exception:
logging.error('Memcache remove failed %s' % url)
def http_cached(etag=False, ttl=0):
def decorator(handler_func):
def wrapper(*args, **kwargs):
handler = args[0]
request = handler.request
response = handler.response
uri = request.path
key = hashed_key(uri)
response.headers['Cache-Control'] = 'public,max-age=%d' % ttl
holder = None
if ttl > 0:
holder = memcache.get(key)
if holder is None:
handler_func(*args, **kwargs)
if response.status_int != 200:
return
body = response.body
holder = MemcacheHolder(md5(body).hexdigest(),handler.response.headers['Content-Type'],body)
try:
if ttl > 0:
added = memcache.add(key, holder, ttl)
if not added:
logging.error('Memcache set failed.')
except ValueError:
logging.error('Memcache set failed - data larger than 1MB')
else:
response.headers['Content-Type'] = holder.content_type
response.write(holder.data)
if etag:
response_etag = holder.etag
response.headers['ETag'] = '"%s"' % response_etag
request_etag = None
if 'If-None-Match' in request.headers:
request_etag = request.headers['If-None-Match']
if request_etag.startswith('"') and request_etag.endswith('"'):
request_etag = request_etag[1:-1]
if request_etag is not None and request_etag == response_etag:
response.status_int = 304
response.status_message = "Not Modified"
response.status = "304 Not Modified"
return
return wrapper
return decorator