1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """File based cache for the discovery document.
16
17 The cache is stored in a single file so that multiple processes can
18 share the same cache. It locks the file whenever accesing to the
19 file. When the cache content is corrupted, it will be initialized with
20 an empty cache.
21 """
22
23 from __future__ import division
24
25 import datetime
26 import json
27 import logging
28 import os
29 import tempfile
30 import threading
31
32 try:
33 from oauth2client.contrib.locked_file import LockedFile
34 except ImportError:
35
36 try:
37 from oauth2client.locked_file import LockedFile
38 except ImportError:
39
40 raise ImportError(
41 'file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth')
42
43 from . import base
44 from ..discovery_cache import DISCOVERY_DOC_MAX_AGE
45
46 LOGGER = logging.getLogger(__name__)
47
48 FILENAME = 'google-api-python-client-discovery-doc.cache'
49 EPOCH = datetime.datetime.utcfromtimestamp(0)
50
51
53 try:
54 return (date - EPOCH).total_seconds()
55 except AttributeError:
56
57
58 delta = date - EPOCH
59 return ((delta.microseconds + (delta.seconds + delta.days * 24 * 3600)
60 * 10**6) / 10**6)
61
62
64 f.file_handle().seek(0)
65 try:
66 cache = json.load(f.file_handle())
67 except Exception:
68
69
70 cache = {}
71 f.file_handle().truncate(0)
72 f.file_handle().seek(0)
73 json.dump(cache, f.file_handle())
74 return cache
75
76
78 """A file based cache for the discovery documents."""
79
81 """Constructor.
82
83 Args:
84 max_age: Cache expiration in seconds.
85 """
86 self._max_age = max_age
87 self._file = os.path.join(tempfile.gettempdir(), FILENAME)
88 f = LockedFile(self._file, 'a+', 'r')
89 try:
90 f.open_and_lock()
91 if f.is_locked():
92 _read_or_initialize_cache(f)
93
94
95 except Exception as e:
96 LOGGER.warning(e, exc_info=True)
97 finally:
98 f.unlock_and_close()
99
100 - def get(self, url):
101 f = LockedFile(self._file, 'r+', 'r')
102 try:
103 f.open_and_lock()
104 if f.is_locked():
105 cache = _read_or_initialize_cache(f)
106 if url in cache:
107 content, t = cache.get(url, (None, 0))
108 if _to_timestamp(datetime.datetime.now()) < t + self._max_age:
109 return content
110 return None
111 else:
112 LOGGER.debug('Could not obtain a lock for the cache file.')
113 return None
114 except Exception as e:
115 LOGGER.warning(e, exc_info=True)
116 finally:
117 f.unlock_and_close()
118
119 - def set(self, url, content):
120 f = LockedFile(self._file, 'r+', 'r')
121 try:
122 f.open_and_lock()
123 if f.is_locked():
124 cache = _read_or_initialize_cache(f)
125 cache[url] = (content, _to_timestamp(datetime.datetime.now()))
126
127 for k, (_, timestamp) in list(cache.items()):
128 if _to_timestamp(datetime.datetime.now()) >= timestamp + self._max_age:
129 del cache[k]
130 f.file_handle().truncate(0)
131 f.file_handle().seek(0)
132 json.dump(cache, f.file_handle())
133 else:
134 LOGGER.debug('Could not obtain a lock for the cache file.')
135 except Exception as e:
136 LOGGER.warning(e, exc_info=True)
137 finally:
138 f.unlock_and_close()
139
140
141 cache = Cache(max_age=DISCOVERY_DOC_MAX_AGE)
142