Просмотр исходного кода

Finished first complete version of Cache object, tested only in live environment.

Taddeus Kroes 14 лет назад
Родитель
Сommit
bd10e62e94
1 измененных файлов с 71 добавлено и 24 удалено
  1. 71 24
      cache.py

+ 71 - 24
cache.py

@@ -1,9 +1,11 @@
 import web
 import web
+import cPickle as pickle
 from time import gmtime
 from time import gmtime
 from datetime import datetime, timedelta
 from datetime import datetime, timedelta
 from os import mkdir
 from os import mkdir
 from os.path import getmtime, exists
 from os.path import getmtime, exists
-from cPickle import load, dump
+from hashlib import md5
+from copy import copy
 
 
 
 
 ADMINISTRATION_FILE = 'administration.py'
 ADMINISTRATION_FILE = 'administration.py'
@@ -29,7 +31,7 @@ def assert_file_exists(path):
 
 
 
 
 def seconds_to_datetime(seconds):
 def seconds_to_datetime(seconds):
-    return datetime(gmtime(seconds)[:7])
+    return datetime(*gmtime(seconds)[:7])
 
 
 
 
 class Cache:
 class Cache:
@@ -59,6 +61,10 @@ class Cache:
     def assert_files_exist(self):
     def assert_files_exist(self):
         map(assert_file_exists, self.files)
         map(assert_file_exists, self.files)
 
 
+    def __str__(self):
+        return '<Cache filename=%s files=[%s]>' \
+               % (self.filename(), ','.join(self.files))
+
     def add(self, path, absolute=False):
     def add(self, path, absolute=False):
         """
         """
         Add a file to the cache object. Requires the full path to the file,
         Add a file to the cache object. Requires the full path to the file,
@@ -101,18 +107,35 @@ class Cache:
         if not exists(self.cached):
         if not exists(self.cached):
             mkdir(self.cached)
             mkdir(self.cached)
 
 
-    def save_administration(self):
+    def save_administration(self, old_admin={}):
         """
         """
         Generate a Python file containing the modification dates of the cached
         Generate a Python file containing the modification dates of the cached
-        file list.
+        file list. The old_admin paramter can contain additional files which
+        are not in this cache object, but do need to be kept in the
+        administration for other cache objects.
         """
         """
         self.assert_modification_dates_exist()
         self.assert_modification_dates_exist()
         self.assert_cached_folder_exist()
         self.assert_cached_folder_exist()
 
 
+        admin = copy(old_admin)
+        admin.update(self.modified)
+
         f = open(self.cached + ADMINISTRATION_FILE, 'w')
         f = open(self.cached + ADMINISTRATION_FILE, 'w')
-        dump(self.modified, f)
+        pickle.dump(self.modified, f)
+        f.close()
+
+    def load_administration(self):
+        path = self.cached + ADMINISTRATION_FILE
+
+        if not exists(path):
+            return {}
+
+        f = open(path, 'r')
+        modified = pickle.load(f)
         f.close()
         f.close()
 
 
+        return modified
+
     def last_modified(self):
     def last_modified(self):
         self.assert_modification_dates_exist()
         self.assert_modification_dates_exist()
 
 
@@ -123,10 +146,16 @@ class Cache:
         Generate an Etag for the cache object, using the names of the files
         Generate an Etag for the cache object, using the names of the files
         included and the latest modification date.
         included and the latest modification date.
         """
         """
-        return self.filename() + str(self.last_modified())
+        h = md5()
+        h.update(','.join(self.files) + str(self.last_modified()))
+
+        return h.hexdigest()
 
 
     def filename(self):
     def filename(self):
-        return ','.join(self.files)
+        h = md5()
+        h.update(','.join(self.files))
+
+        return self.cached + h.hexdigest()
 
 
     def concatenate(self):
     def concatenate(self):
         contents = ''
         contents = ''
@@ -143,27 +172,45 @@ class Cache:
         # Update cached file
         # Update cached file
         last_modified = self.last_modified()
         last_modified = self.last_modified()
         path = self.filename()
         path = self.filename()
-        server_modified = not exists(path) or getmtime(path) < last_modified
+        admin = self.load_administration()
+
+        if not exists(path):
+            web.debug('Cached file "%s" does not exist yet, generating it...')
+            server_modified = True
+        else:
+            server_modified = False
+
+            for f_path, f_modified in self.modified.iteritems():
+                if f_path not in admin:
+                    web.debug('File "%s" has been added.' % f_path)
+                    server_modified = True
+                elif f_modified > admin[f_path]:
+                    web.debug('File "%s" has been updated.' % f_path)
+                    server_modified = True
 
 
         if server_modified:
         if server_modified:
-            content = self.concatenate()
+            self.save_administration(admin)
 
 
+            content = self.concatenate()
             f = open(path, 'w')
             f = open(path, 'w')
             f.write(content)
             f.write(content)
             f.close()
             f.close()
 
 
-        #try:
-        web.http.modified(seconds_to_datetime(last_modified), self.etag())
-        web.http.expires(timedelta(**self.expires))
-        web.header('Cache-Control', 'private')
-
-        if not server_modified:
-            # Concatenated content has not been loaded yet, read the cached
-            # file
-            f = open(path, 'r')
-            content = f.read()
-            f.close()
-
-        return content
-        #except web.NotModified as e:
-        #    web.header('Status', e.message)
+        try:
+            web.http.modified(seconds_to_datetime(last_modified), self.etag())
+            web.http.expires(timedelta(**self.expires))
+            web.header('Cache-Control', 'private')
+
+            if not server_modified:
+                # Concatenated content has not been loaded yet, read the cached
+                # file
+                web.debug('Cached file "%s" already exists, sending content...')
+                f = open(path, 'r')
+                content = f.read()
+                f.close()
+
+            return content
+        except web.NotModified as e:
+            web.debug('Cached file "%s" not modified, setting 304 header...' \
+                      % path)
+            raise e