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') 
 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