Changeset View
Changeset View
Standalone View
Standalone View
src/misc/gravatarcache.cpp
Show All 12 Lines | 1 | /* | |||
---|---|---|---|---|---|
13 | 13 | | |||
14 | You should have received a copy of the GNU Library General Public License | 14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | 15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | Boston, MA 02110-1301, USA. | 17 | Boston, MA 02110-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | #include "gravatarcache.h" | 20 | #include "gravatarcache.h" | ||
21 | #include <QDir> | | |||
22 | #include "gravatar_debug.h" | 21 | #include "gravatar_debug.h" | ||
22 | #include "hash.h" | ||||
23 | 23 | | |||
24 | #include <QCache> | 24 | #include <QCache> | ||
25 | #include <QDir> | ||||
25 | #include <QFile> | 26 | #include <QFile> | ||
26 | #include <QFileInfo> | 27 | #include <QFileInfo> | ||
28 | #include <QSaveFile> | ||||
27 | #include <QStandardPaths> | 29 | #include <QStandardPaths> | ||
30 | | ||||
31 | #include <algorithm> | ||||
32 | #include <vector> | ||||
33 | | ||||
28 | using namespace Gravatar; | 34 | using namespace Gravatar; | ||
29 | 35 | | |||
30 | Q_GLOBAL_STATIC(GravatarCache, s_gravatarCache) | 36 | Q_GLOBAL_STATIC(GravatarCache, s_gravatarCache) | ||
31 | 37 | | |||
32 | class Gravatar::GravatarCachePrivate | 38 | class Gravatar::GravatarCachePrivate | ||
33 | { | 39 | { | ||
34 | public: | 40 | public: | ||
35 | GravatarCachePrivate() | 41 | template <typename T> | ||
42 | inline void insertMissingHash(std::vector<T> &vec, const T &hash) | ||||
43 | { | ||||
44 | auto it = std::lower_bound(vec.begin(), vec.end(), hash); | ||||
45 | if (it != vec.end() && *it == hash) | ||||
46 | return; // already present (shouldn't happen) | ||||
47 | vec.insert(it, hash); | ||||
48 | } | ||||
49 | | ||||
50 | template <typename T> | ||||
51 | inline void saveVector(const std::vector<T> &vec, const QString &fileName) | ||||
36 | { | 52 | { | ||
53 | QSaveFile f(mGravatarPath + fileName); | ||||
54 | if (!f.open(QFile::WriteOnly)) { | ||||
55 | qCWarning(GRAVATAR_LOG) << "Can't write missing hashes cache file:" << f.fileName() << f.errorString(); | ||||
mlaurent: qCWarning(..) | |||||
56 | return; | ||||
57 | } | ||||
58 | | ||||
59 | f.resize(vec.size() * sizeof(T)); | ||||
60 | f.write(reinterpret_cast<const char*>(vec.data()), vec.size() * sizeof(T)); | ||||
61 | f.commit(); | ||||
62 | } | ||||
63 | | ||||
64 | template <typename T> | ||||
65 | inline void loadVector(std::vector<T> &vec, const QString &fileName) | ||||
66 | { | ||||
67 | if (!vec.empty()) // already loaded | ||||
68 | return; | ||||
69 | | ||||
70 | QFile f(mGravatarPath + fileName); | ||||
71 | if (!f.open(QFile::ReadOnly)) | ||||
72 | return; // does not exist yet | ||||
73 | | ||||
74 | if (f.size() % sizeof(T) != 0) { | ||||
75 | qCWarning(GRAVATAR_LOG) << "Missing hash cache is corrupt:" << f.fileName(); | ||||
mlaurent: qCWarning(..) | |||||
76 | return; | ||||
77 | } | ||||
78 | vec.resize(f.size() / sizeof(T)); | ||||
79 | f.read(reinterpret_cast<char*>(vec.data()), f.size()); | ||||
37 | } | 80 | } | ||
38 | 81 | | |||
39 | QCache<QString, QPixmap> mCachePixmap; | 82 | QCache<Hash, QPixmap> mCachePixmap; | ||
40 | QString mGravatarPath; | 83 | QString mGravatarPath; | ||
84 | std::vector<Hash128> mMd5Misses; | ||||
85 | std::vector<Hash256> mSha256Misses; | ||||
41 | }; | 86 | }; | ||
42 | 87 | | |||
43 | GravatarCache::GravatarCache() | 88 | GravatarCache::GravatarCache() | ||
44 | : d(new Gravatar::GravatarCachePrivate) | 89 | : d(new Gravatar::GravatarCachePrivate) | ||
45 | { | 90 | { | ||
46 | d->mCachePixmap.setMaxCost(20); | 91 | d->mCachePixmap.setMaxCost(20); | ||
47 | //Make sure that this folder is created. Otherwise we can't store gravatar | 92 | //Make sure that this folder is created. Otherwise we can't store gravatar | ||
48 | d->mGravatarPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/gravatar/"); | 93 | d->mGravatarPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/gravatar/"); | ||
49 | QDir().mkpath(d->mGravatarPath); | 94 | QDir().mkpath(d->mGravatarPath); | ||
50 | } | 95 | } | ||
51 | 96 | | |||
52 | GravatarCache::~GravatarCache() | 97 | GravatarCache::~GravatarCache() | ||
53 | { | 98 | { | ||
54 | delete d; | 99 | delete d; | ||
55 | } | 100 | } | ||
56 | 101 | | |||
57 | GravatarCache *GravatarCache::self() | 102 | GravatarCache *GravatarCache::self() | ||
58 | { | 103 | { | ||
59 | return s_gravatarCache; | 104 | return s_gravatarCache; | ||
60 | } | 105 | } | ||
61 | 106 | | |||
62 | void GravatarCache::saveGravatarPixmap(const QString &hashStr, const QPixmap &pixmap) | 107 | void GravatarCache::saveGravatarPixmap(const Hash &hash, const QPixmap &pixmap) | ||
63 | { | 108 | { | ||
64 | if (!hashStr.isEmpty() && !pixmap.isNull()) { | 109 | if (!hash.isValid() || pixmap.isNull()) | ||
65 | if (!d->mCachePixmap.contains(hashStr)) { | 110 | return; | ||
66 | const QString path = d->mGravatarPath + hashStr + QLatin1String(".png"); | 111 | | ||
112 | const QString path = d->mGravatarPath + hash.hexString() + QLatin1String(".png"); | ||||
67 | qCDebug(GRAVATAR_LOG) << " path " << path; | 113 | qCDebug(GRAVATAR_LOG) << " path " << path; | ||
68 | if (pixmap.save(path)) { | 114 | if (pixmap.save(path)) { | ||
69 | qCDebug(GRAVATAR_LOG) << " saved in cache " << hashStr << path; | 115 | qCDebug(GRAVATAR_LOG) << " saved in cache " << path; | ||
70 | d->mCachePixmap.insert(hashStr, new QPixmap(pixmap)); | 116 | d->mCachePixmap.insert(hash, new QPixmap(pixmap)); | ||
71 | } | 117 | } | ||
72 | } | 118 | } | ||
119 | | ||||
120 | void GravatarCache::saveMissingGravatar(const Hash &hash) | ||||
121 | { | ||||
122 | switch (hash.type()) { | ||||
123 | case Hash::Invalid: | ||||
124 | break; | ||||
125 | case Hash::Md5: | ||||
126 | d->insertMissingHash(d->mMd5Misses, hash.md5()); | ||||
127 | d->saveVector(d->mMd5Misses, QStringLiteral("missing.md5")); | ||||
128 | break; | ||||
129 | case Hash::Sha256: | ||||
130 | d->insertMissingHash(d->mSha256Misses, hash.sha256()); | ||||
131 | d->saveVector(d->mSha256Misses, QStringLiteral("missing.sha256")); | ||||
132 | break; | ||||
73 | } | 133 | } | ||
74 | } | 134 | } | ||
75 | 135 | | |||
76 | QPixmap GravatarCache::loadGravatarPixmap(const QString &hashStr, bool &gravatarStored) | 136 | QPixmap GravatarCache::loadGravatarPixmap(const Hash &hash, bool &gravatarStored) | ||
77 | { | 137 | { | ||
78 | gravatarStored = false; | 138 | gravatarStored = false; | ||
79 | qCDebug(GRAVATAR_LOG) << " hashStr" << hashStr; | 139 | qCDebug(GRAVATAR_LOG) << " hashStr" << hash.hexString(); | ||
80 | if (!hashStr.isEmpty()) { | 140 | if (!hash.isValid()) | ||
81 | if (d->mCachePixmap.contains(hashStr)) { | 141 | return QPixmap(); | ||
82 | qCDebug(GRAVATAR_LOG) << " contains in cache " << hashStr; | 142 | | ||
143 | // in-memory cache | ||||
144 | if (d->mCachePixmap.contains(hash)) { | ||||
145 | qCDebug(GRAVATAR_LOG) << " contains in cache " << hash.hexString(); | ||||
83 | gravatarStored = true; | 146 | gravatarStored = true; | ||
84 | return *(d->mCachePixmap.object(hashStr)); | 147 | return *(d->mCachePixmap.object(hash)); | ||
85 | } else { | 148 | } | ||
86 | const QString path = d->mGravatarPath + hashStr + QLatin1String(".png"); | 149 | | ||
150 | // file-system cache | ||||
151 | const QString path = d->mGravatarPath + hash.hexString() + QLatin1String(".png"); | ||||
87 | if (QFileInfo::exists(path)) { | 152 | if (QFileInfo::exists(path)) { | ||
88 | QPixmap pix; | 153 | QPixmap pix; | ||
89 | if (pix.load(path)) { | 154 | if (pix.load(path)) { | ||
90 | qCDebug(GRAVATAR_LOG) << " add to cache " << hashStr << path; | 155 | qCDebug(GRAVATAR_LOG) << " add to cache " << hash.hexString() << path; | ||
91 | d->mCachePixmap.insert(hashStr, new QPixmap(pix)); | 156 | d->mCachePixmap.insert(hash, new QPixmap(pix)); | ||
92 | gravatarStored = true; | 157 | gravatarStored = true; | ||
93 | return pix; | 158 | return pix; | ||
94 | } | 159 | } | ||
95 | } else { | | |||
96 | return QPixmap(); | | |||
97 | } | | |||
98 | } | 160 | } | ||
161 | | ||||
162 | // missing gravatar cache (ie. known to not exist one) | ||||
163 | switch (hash.type()) { | ||||
164 | case Hash::Invalid: | ||||
165 | break; | ||||
166 | case Hash::Md5: | ||||
167 | d->loadVector(d->mMd5Misses, QStringLiteral("missing.md5")); | ||||
168 | gravatarStored = std::binary_search(d->mMd5Misses.begin(), d->mMd5Misses.end(), hash.md5()); | ||||
169 | break; | ||||
170 | case Hash::Sha256: | ||||
171 | d->loadVector(d->mSha256Misses, QStringLiteral("missing.sha256")); | ||||
172 | gravatarStored = std::binary_search(d->mSha256Misses.begin(), d->mSha256Misses.end(), hash.sha256()); | ||||
173 | break; | ||||
99 | } | 174 | } | ||
175 | | ||||
100 | return QPixmap(); | 176 | return QPixmap(); | ||
101 | } | 177 | } | ||
102 | 178 | | |||
103 | int GravatarCache::maximumSize() const | 179 | int GravatarCache::maximumSize() const | ||
104 | { | 180 | { | ||
105 | return d->mCachePixmap.maxCost(); | 181 | return d->mCachePixmap.maxCost(); | ||
106 | } | 182 | } | ||
107 | 183 | | |||
Show All 17 Lines | 199 | if (!path.isEmpty()) { | |||
125 | if (dir.exists()) { | 201 | if (dir.exists()) { | ||
126 | const QFileInfoList list = dir.entryInfoList(); // get list of matching files and delete all | 202 | const QFileInfoList list = dir.entryInfoList(); // get list of matching files and delete all | ||
127 | for (const QFileInfo &it : list) { | 203 | for (const QFileInfo &it : list) { | ||
128 | dir.remove(it.fileName()); | 204 | dir.remove(it.fileName()); | ||
129 | } | 205 | } | ||
130 | } | 206 | } | ||
131 | } | 207 | } | ||
132 | clear(); | 208 | clear(); | ||
209 | d->mMd5Misses.clear(); | ||||
210 | d->mSha256Misses.clear(); | ||||
133 | } | 211 | } |
qCWarning(..)