annotate src/memory/cache.py @ 2509:d485e9416493

core (memory/cache): common cache: host has now a common_cache attribute for data which can be shared between profiles. client.cache is for private data
author Goffi <goffi@goffi.org>
date Fri, 02 Mar 2018 17:40:09 +0100
parents 516bf5309517
children cd7a53c31eb6
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python2
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # SAT: a jabber client
2483
0046283a285d dates update
Goffi <goffi@goffi.org>
parents: 2414
diff changeset
5 # Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.log import getLogger
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 log = getLogger(__name__)
2166
1b3fbb76984b core (memory/cache): escape profile when creating cache dir
Goffi <goffi@goffi.org>
parents: 2116
diff changeset
22 from sat.tools.common import regex
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from sat.core import exceptions
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from sat.core.constants import Const as C
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 import cPickle as pickle
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 import mimetypes
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 import os.path
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 import time
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
30 DEFAULT_EXT = '.raw'
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
31
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
32
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 class Cache(object):
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34 """generic file caching"""
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
36 def __init__(self, host, profile):
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
37 """
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
38 @param profile(unicode, None): ame of the profile to set the cache for
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
39 if None, the cache will be common for all profiles
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
40 """
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 self.profile = profile
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
42 path_elts = [host.memory.getConfig('', 'local_dir'), C.CACHE_DIR]
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
43 if profile:
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
44 path_elts.extend([u'profiles',regex.pathEscape(profile)])
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
45 else:
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
46 path_elts.append(u'common')
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
47 self.cache_dir = os.path.join(*path_elts)
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
48
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 if not os.path.exists(self.cache_dir):
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 os.makedirs(self.cache_dir)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 def getPath(self, filename):
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 """return cached file URL
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 @param filename(unicode): cached file name (cache data or actual file)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 """
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 if not filename or u'/' in filename:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 log.error(u"invalid char found in file name, hack attempt? name:{}".format(filename))
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 raise exceptions.DataError(u"Invalid char found")
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 return os.path.join(self.cache_dir, filename)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
61
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 def getFilePath(self, uid):
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 """retrieve absolute path to file
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 @param uid(unicode): unique identifier of file
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 @return (unicode, None): absolute path to cached file
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 None if file is not in cache (or cache is invalid)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 """
2116
766dbbec56f2 core (memory/cache): geFilePath now return None when uid is empty
Goffi <goffi@goffi.org>
parents: 2109
diff changeset
69 uid = uid.strip()
766dbbec56f2 core (memory/cache): geFilePath now return None when uid is empty
Goffi <goffi@goffi.org>
parents: 2109
diff changeset
70 if not uid:
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
71 raise exceptions.InternalError(u"uid must not be empty")
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 cache_url = self.getPath(uid)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 if not os.path.exists(cache_url):
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 return None
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
75
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 try:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 with open(cache_url, 'rb') as f:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 cache_data = pickle.load(f)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 except IOError:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 log.warning(u"can't read cache at {}".format(cache_url))
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 return None
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 except pickle.UnpicklingError:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 log.warning(u'invalid cache found at {}'.format(cache_url))
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 return None
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 try:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 eol = cache_data['eol']
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 except KeyError:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 log.warning(u'no End Of Life found for cached file {}'.format(uid))
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 eol = 0
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 if eol < time.time():
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 log.debug(u"removing expired cache (expired for {}s)".format(
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 time.time() - eol))
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 return None
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
95
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 return self.getPath(cache_data['filename'])
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
97
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
98 def cacheData(self, source, uid, mime_type=None, max_age=None, filename=None):
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 """create cache metadata and file object to use for actual data
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 @param source(unicode): source of the cache (should be plugin's import_name)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 @param uid(unicode): an identifier of the file which must be unique
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 @param mime_type(unicode): MIME type of the file to cache
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 it will be used notably to guess file extension
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 @param max_age(int, None): maximum age in seconds
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 the cache metadata will have an "eol" (end of life)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 None to use default value
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 0 to ignore cache (file will be re-downloaded on each access)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 @param filename: if not None, will be used as filename
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 else one will be generated from uid and guessed extension
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 @return(file): file object opened in write mode
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 you have to close it yourself (hint: use with statement)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 """
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 cache_url = self.getPath(uid)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 if filename is None:
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
116 if mime_type:
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
117 ext = mimetypes.guess_extension(mime_type, strict=False)
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
118 if ext is None:
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
119 log.warning(u"can't find extension for MIME type {}".format(mime_type))
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
120 ext = DEFAULT_EXT
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
121 elif ext == u'.jpe':
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
122 ext = u'.jpg'
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
123 else:
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
124 ext = DEFAULT_EXT
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
125 mime_type = None
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 filename = uid + ext
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 if max_age is None:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
128 max_age = C.DEFAULT_MAX_AGE
2509
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
129 cache_data = {u'source': source,
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
130 u'filename': filename,
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
131 u'eol': int(time.time()) + max_age,
d485e9416493 core (memory/cache): common cache:
Goffi <goffi@goffi.org>
parents: 2506
diff changeset
132 u'mime_type': mime_type,
2109
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 }
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 file_path = self.getPath(filename)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
135
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 with open(cache_url, 'wb') as f:
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 pickle.dump(cache_data, f, protocol=2)
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
138
85f3e12e984d core (memory/cache): file caching handling, first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 return open(file_path, 'wb')