Package googleapiclient :: Package discovery_cache :: Module file_cache |
[hide private]
[frames] | no frames]

# Source Code for Module googleapiclient.discovery_cache.file_cache

      1  # Copyright 2014 Google Inc. All Rights Reserved.
      2  #
      3  # Licensed under the Apache License, Version 2.0 (the "License");
      4  # you may not use this file except in compliance with the License.
      5  # You may obtain a copy of the License at
      6  #
      7  #      http://www.apache.org/licenses/LICENSE-2.0
      8  #
      9  # Unless required by applicable law or agreed to in writing, software
     10  # distributed under the License is distributed on an "AS IS" BASIS,
     11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12  # See the License for the specific language governing permissions and
     13  # limitations under the License.
     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      # oauth2client < 2.0.0
     36      try:
     37          from oauth2client.locked_file import LockedFile
     38      except ImportError:
     39          # oauth2client > 4.0.0 or google-auth
     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
     53 -def _to_timestamp(date):
     54      try:
     55          return (date - EPOCH).total_seconds()
     56      except AttributeError:
     57          # The following is the equivalent of total_seconds() in Python2.6.
     58          # See also: https://docs.python.org/2/library/datetime.html
     59          delta = date - EPOCH
     60          return (
     61              delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10 ** 6
     62          ) / 10 ** 6
     63
     64
     65 -def _read_or_initialize_cache(f):
     66      f.file_handle().seek(0)
     67      try:
     68          cache = json.load(f.file_handle())
     69      except Exception:
     70          # This means it opens the file for the first time, or the cache is
     71          # corrupted, so initializing the file with an empty dict.
     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
     79 -class Cache(base.Cache):
     80      """A file based cache for the discovery documents."""
     81
     82 -    def __init__(self, max_age):
     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              # If we can not obtain the lock, other process or thread must
     96              # have initialized the file.
     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                  # Remove stale cache.
    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