Mercurial > hg > svcore
comparison data/fileio/FileSource.cpp @ 460:93fb1ebff76b
* Add persistent cache file support to FileSource (e.g. for RDF
descriptions)
* Query RDF plugin data in a background thread on startup
author | Chris Cannam |
---|---|
date | Fri, 17 Oct 2008 13:32:55 +0000 |
parents | ef14acd6d102 |
children | 2019d89ebcf9 |
comparison
equal
deleted
inserted
replaced
459:6441b31b37ac | 460:93fb1ebff76b |
---|---|
22 #include <QHttp> | 22 #include <QHttp> |
23 #include <QFtp> | 23 #include <QFtp> |
24 #include <QFileInfo> | 24 #include <QFileInfo> |
25 #include <QDir> | 25 #include <QDir> |
26 #include <QCoreApplication> | 26 #include <QCoreApplication> |
27 #include <QCryptographicHash> | |
27 #include <QHttpResponseHeader> | 28 #include <QHttpResponseHeader> |
28 | 29 |
29 #include <iostream> | 30 #include <iostream> |
30 #include <cstdlib> | 31 #include <cstdlib> |
31 | 32 |
32 //#define DEBUG_FILE_SOURCE 1 | 33 #define DEBUG_FILE_SOURCE 1 |
33 | 34 |
34 int | 35 int |
35 FileSource::m_count = 0; | 36 FileSource::m_count = 0; |
36 | 37 |
37 QMutex | 38 QMutex |
44 FileSource::m_remoteLocalMap; | 45 FileSource::m_remoteLocalMap; |
45 | 46 |
46 QMutex | 47 QMutex |
47 FileSource::m_mapMutex; | 48 FileSource::m_mapMutex; |
48 | 49 |
49 FileSource::FileSource(QString fileOrUrl, ProgressReporter *reporter) : | 50 FileSource::FileSource(QString fileOrUrl, ProgressReporter *reporter, |
51 LocalCacheMode cacheMode) : | |
50 m_url(fileOrUrl), | 52 m_url(fileOrUrl), |
53 m_cacheMode(cacheMode), | |
51 m_ftp(0), | 54 m_ftp(0), |
52 m_http(0), | 55 m_http(0), |
53 m_localFile(0), | 56 m_localFile(0), |
54 m_ok(false), | 57 m_ok(false), |
55 m_lastStatus(0), | 58 m_lastStatus(0), |
58 m_leaveLocalFile(false), | 61 m_leaveLocalFile(false), |
59 m_reporter(reporter), | 62 m_reporter(reporter), |
60 m_refCounted(false) | 63 m_refCounted(false) |
61 { | 64 { |
62 #ifdef DEBUG_FILE_SOURCE | 65 #ifdef DEBUG_FILE_SOURCE |
63 std::cerr << "FileSource::FileSource(" << fileOrUrl.toStdString() << ")" << std::endl; | 66 std::cerr << "FileSource::FileSource(" << fileOrUrl.toStdString() << ", " << cacheMode << ")" << std::endl; |
64 #endif | 67 #endif |
65 | 68 |
66 if (!canHandleScheme(m_url)) { | 69 if (!canHandleScheme(m_url)) { |
67 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | 70 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; |
68 m_errorString = tr("Unsupported scheme in URL"); | 71 m_errorString = tr("Unsupported scheme in URL"); |
108 emit statusAvailable(); | 111 emit statusAvailable(); |
109 emit ready(); | 112 emit ready(); |
110 } | 113 } |
111 } | 114 } |
112 | 115 |
113 FileSource::FileSource(QUrl url, ProgressReporter *reporter) : | 116 FileSource::FileSource(QUrl url, ProgressReporter *reporter, |
117 LocalCacheMode cacheMode) : | |
114 m_url(url), | 118 m_url(url), |
119 m_cacheMode(cacheMode), | |
115 m_ftp(0), | 120 m_ftp(0), |
116 m_http(0), | 121 m_http(0), |
117 m_localFile(0), | 122 m_localFile(0), |
118 m_ok(false), | 123 m_ok(false), |
119 m_lastStatus(0), | 124 m_lastStatus(0), |
137 } | 142 } |
138 | 143 |
139 FileSource::FileSource(const FileSource &rf) : | 144 FileSource::FileSource(const FileSource &rf) : |
140 QObject(), | 145 QObject(), |
141 m_url(rf.m_url), | 146 m_url(rf.m_url), |
147 m_cacheMode(rf.m_cacheMode), | |
142 m_ftp(0), | 148 m_ftp(0), |
143 m_http(0), | 149 m_http(0), |
144 m_localFile(0), | 150 m_localFile(0), |
145 m_ok(rf.m_ok), | 151 m_ok(rf.m_ok), |
146 m_lastStatus(rf.m_lastStatus), | 152 m_lastStatus(rf.m_lastStatus), |
158 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | 164 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; |
159 m_errorString = tr("Unsupported scheme in URL"); | 165 m_errorString = tr("Unsupported scheme in URL"); |
160 return; | 166 return; |
161 } | 167 } |
162 | 168 |
163 if (!isRemote()) { | 169 if (m_cacheMode == PersistentCache) { |
170 | |
164 m_localFilename = rf.m_localFilename; | 171 m_localFilename = rf.m_localFilename; |
172 | |
173 } else if (!isRemote()) { | |
174 | |
175 m_localFilename = rf.m_localFilename; | |
176 | |
165 } else { | 177 } else { |
166 QMutexLocker locker(&m_mapMutex); | 178 QMutexLocker locker(&m_mapMutex); |
167 #ifdef DEBUG_FILE_SOURCE | 179 #ifdef DEBUG_FILE_SOURCE |
168 std::cerr << "FileSource::FileSource(copy ctor): ref count is " | 180 std::cerr << "FileSource::FileSource(copy ctor): ref count is " |
169 << m_refCountMap[m_url] << std::endl; | 181 << m_refCountMap[m_url] << std::endl; |
190 std::cerr << "FileSource(" << m_url.toString().toStdString() << ")::~FileSource" << std::endl; | 202 std::cerr << "FileSource(" << m_url.toString().toStdString() << ")::~FileSource" << std::endl; |
191 #endif | 203 #endif |
192 | 204 |
193 cleanup(); | 205 cleanup(); |
194 | 206 |
195 if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); | 207 if (isRemote() && (m_cacheMode == TemporaryCache) && !m_leaveLocalFile) { |
208 deleteCacheFile(); | |
209 } | |
196 } | 210 } |
197 | 211 |
198 void | 212 void |
199 FileSource::init() | 213 FileSource::init() |
200 { | 214 { |
236 return; | 250 return; |
237 } | 251 } |
238 | 252 |
239 if (createCacheFile()) { | 253 if (createCacheFile()) { |
240 #ifdef DEBUG_FILE_SOURCE | 254 #ifdef DEBUG_FILE_SOURCE |
241 std::cerr << "FileSource::init: Already have this one" << std::endl; | 255 std::cerr << "FileSource::init: Already have this one at " |
256 << m_localFilename.toStdString() << std::endl; | |
242 #endif | 257 #endif |
243 m_ok = true; | 258 m_ok = true; |
244 if (!QFileInfo(m_localFilename).exists()) { | 259 if (!QFileInfo(m_localFilename).exists()) { |
245 m_lastStatus = 404; | 260 m_lastStatus = 404; |
246 } else { | 261 } else { |
256 | 271 |
257 QString scheme = m_url.scheme().toLower(); | 272 QString scheme = m_url.scheme().toLower(); |
258 | 273 |
259 #ifdef DEBUG_FILE_SOURCE | 274 #ifdef DEBUG_FILE_SOURCE |
260 std::cerr << "FileSource::init: Don't have local copy of \"" | 275 std::cerr << "FileSource::init: Don't have local copy of \"" |
261 << m_url.toString().toStdString() << "\", retrieving" << std::endl; | 276 << m_url.toString().toStdString() << "\", retrieving to " |
277 << m_localFilename.toStdString() << std::endl; | |
262 #endif | 278 #endif |
263 | 279 |
264 if (scheme == "http") { | 280 if (scheme == "http") { |
265 initHttp(); | 281 initHttp(); |
266 std::cerr << "FileSource: initHttp succeeded" << std::endl; | 282 std::cerr << "FileSource: initHttp succeeded" << std::endl; |
691 } | 707 } |
692 } | 708 } |
693 | 709 |
694 m_fileCreationMutex.lock(); | 710 m_fileCreationMutex.lock(); |
695 | 711 |
712 // We always delete the file here, even in PersistentCache mode, | |
713 // because this function is also used if retrieval failed (in | |
714 // which case we want to delete the cache so that subsequent users | |
715 // won't trust it). It's up to the calling code to determine | |
716 // whether we actually want to delete the cache or not, e.g. on | |
717 // destruction. | |
718 | |
696 if (!QFile(m_localFilename).remove()) { | 719 if (!QFile(m_localFilename).remove()) { |
697 #ifdef DEBUG_FILE_SOURCE | |
698 std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; | 720 std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; |
699 #endif | |
700 } else { | 721 } else { |
701 #ifdef DEBUG_FILE_SOURCE | 722 #ifdef DEBUG_FILE_SOURCE |
702 std::cerr << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl; | 723 std::cerr << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl; |
703 #endif | 724 #endif |
704 m_localFilename = ""; | 725 m_localFilename = ""; |
705 } | 726 } |
706 | 727 |
707 m_fileCreationMutex.unlock(); | 728 m_fileCreationMutex.unlock(); |
708 | 729 |
709 m_done = true; | 730 m_done = true; |
731 } | |
732 | |
733 QString | |
734 FileSource::getPersistentCacheDirectory() | |
735 { | |
736 QDir dir = TempDirectory::getInstance()->getContainingPath(); | |
737 | |
738 QString cacheDirName("cache"); | |
739 | |
740 QFileInfo fi(dir.filePath(cacheDirName)); | |
741 | |
742 if ((fi.exists() && !fi.isDir()) || | |
743 (!fi.exists() && !dir.mkdir(cacheDirName))) { | |
744 | |
745 throw DirectoryCreationFailed(fi.filePath()); | |
746 } | |
747 | |
748 return fi.filePath(); | |
749 } | |
750 | |
751 QString | |
752 FileSource::getPersistentCacheFilePath(QUrl url) | |
753 { | |
754 QDir dir(getPersistentCacheDirectory()); | |
755 | |
756 QString filename = | |
757 QString::fromLocal8Bit | |
758 (QCryptographicHash::hash(url.toString().toLocal8Bit(), | |
759 QCryptographicHash::Sha1).toBase64()); | |
760 | |
761 return dir.filePath(filename); | |
710 } | 762 } |
711 | 763 |
712 bool | 764 bool |
713 FileSource::createCacheFile() | 765 FileSource::createCacheFile() |
714 { | 766 { |
767 if (m_cacheMode == PersistentCache) { | |
768 m_localFilename = getPersistentCacheFilePath(m_url); | |
769 if (QFileInfo(m_localFilename).exists()) return true; | |
770 else return false; | |
771 } | |
772 | |
715 { | 773 { |
716 QMutexLocker locker(&m_mapMutex); | 774 QMutexLocker locker(&m_mapMutex); |
717 | 775 |
718 #ifdef DEBUG_FILE_SOURCE | 776 #ifdef DEBUG_FILE_SOURCE |
719 std::cerr << "FileSource::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl; | 777 std::cerr << "FileSource::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl; |