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