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 from oauth2client.locked_file import LockedFile
37
38 from . import base
39 from ..discovery_cache import DISCOVERY_DOC_MAX_AGE
40
41 LOGGER = logging.getLogger(__name__)
42
43 FILENAME = 'google-api-python-client-discovery-doc.cache'
44 EPOCH = datetime.datetime.utcfromtimestamp(0)
45
46
48 try:
49 return (date - EPOCH).total_seconds()
50 except AttributeError:
51
52
53 delta = date - EPOCH
54 return ((delta.microseconds + (delta.seconds + delta.days * 24 * 3600)
55 * 10**6) / 10**6)
56
57
59 f.file_handle().seek(0)
60 try:
61 cache = json.load(f.file_handle())
62 except Exception:
63
64
65 cache = {}
66 f.file_handle().truncate(0)
67 f.file_handle().seek(0)
68 json.dump(cache, f.file_handle())
69 return cache
70
71
73 """A file based cache for the discovery documents."""
74
76 """Constructor.
77
78 Args:
79 max_age: Cache expiration in seconds.
80 """
81 self._max_age = max_age
82 self._file = os.path.join(tempfile.gettempdir(), FILENAME)
83 f = LockedFile(self._file, 'a+', 'r')
84 try:
85 f.open_and_lock()
86 if f.is_locked():
87 _read_or_initialize_cache(f)
88
89
90 except Exception as e:
91 LOGGER.warning(e, exc_info=True)
92 finally:
93 f.unlock_and_close()
94
96 f = LockedFile(self._file, 'r+', 'r')
97 try:
98 f.open_and_lock()
99 if f.is_locked():
100 cache = _read_or_initialize_cache(f)
101 if url in cache:
102 content, t = cache.get(url, (None, 0))
103 if _to_timestamp(datetime.datetime.now()) < t + self._max_age:
104 return content
105 return None
106 else:
107 LOGGER.debug('Could not obtain a lock for the cache file.')
108 return None
109 except Exception as e:
110 LOGGER.warning(e, exc_info=True)
111 finally:
112 f.unlock_and_close()
113
114 - def set(self, url, content):
115 f = LockedFile(self._file, 'r+', 'r')
116 try:
117 f.open_and_lock()
118 if f.is_locked():
119 cache = _read_or_initialize_cache(f)
120 cache[url] = (content, _to_timestamp(datetime.datetime.now()))
121
122 for k, (_, timestamp) in list(cache.items()):
123 if _to_timestamp(datetime.datetime.now()) >= timestamp + self._max_age:
124 del cache[k]
125 f.file_handle().truncate(0)
126 f.file_handle().seek(0)
127 json.dump(cache, f.file_handle())
128 else:
129 LOGGER.debug('Could not obtain a lock for the cache file.')
130 except Exception as e:
131 LOGGER.warning(e, exc_info=True)
132 finally:
133 f.unlock_and_close()
134
135
136 cache = Cache(max_age=DISCOVERY_DOC_MAX_AGE)
137