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;