Mercurial > hg > svcore
comparison data/fileio/RemoteFile.cpp @ 316:3a6725f285d6
* Make RemoteFile far more pervasive, and use it for local files as well
so that we can handle both transparently. Make it shallow copy with
reference counting, so it can be used by value without having to worry
about the cache file lifetime. Use RemoteFile for MainWindow file-open
functions, etc
author | Chris Cannam |
---|---|
date | Thu, 18 Oct 2007 15:31:20 +0000 |
parents | 96ef9746c560 |
children |
comparison
equal
deleted
inserted
replaced
315:96ef9746c560 | 316:3a6725f285d6 |
---|---|
40 RemoteFile::m_remoteLocalMap; | 40 RemoteFile::m_remoteLocalMap; |
41 | 41 |
42 QMutex | 42 QMutex |
43 RemoteFile::m_mapMutex; | 43 RemoteFile::m_mapMutex; |
44 | 44 |
45 RemoteFile::RemoteFile(QUrl url) : | 45 RemoteFile::RemoteFile(QString fileOrUrl, bool showProgress) : |
46 m_url(fileOrUrl), | |
47 m_ftp(0), | |
48 m_http(0), | |
49 m_localFile(0), | |
50 m_ok(false), | |
51 m_lastStatus(0), | |
52 m_remote(isRemote(fileOrUrl)), | |
53 m_done(false), | |
54 m_leaveLocalFile(false), | |
55 m_progressDialog(0), | |
56 m_progressShowTimer(this), | |
57 m_refCounted(false) | |
58 { | |
59 std::cerr << "RemoteFile::RemoteFile(" << fileOrUrl.toStdString() << ")" << std::endl; | |
60 | |
61 if (!canHandleScheme(m_url)) { | |
62 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | |
63 m_errorString = tr("Unsupported scheme in URL"); | |
64 return; | |
65 } | |
66 | |
67 init(showProgress); | |
68 | |
69 if (isRemote() && | |
70 (fileOrUrl.contains('%') || | |
71 fileOrUrl.contains("--"))) { // for IDNA | |
72 | |
73 waitForStatus(); | |
74 | |
75 if (!isAvailable()) { | |
76 // The URL was created on the assumption that the string | |
77 // was human-readable. Let's try again, this time | |
78 // assuming it was already encoded. | |
79 std::cerr << "RemoteFile::RemoteFile: Failed to retrieve URL \"" | |
80 << fileOrUrl.toStdString() | |
81 << "\" as human-readable URL; " | |
82 << "trying again treating it as encoded URL" | |
83 << std::endl; | |
84 m_url.setEncodedUrl(fileOrUrl.toAscii()); | |
85 init(showProgress); | |
86 } | |
87 } | |
88 } | |
89 | |
90 RemoteFile::RemoteFile(QUrl url, bool showProgress) : | |
46 m_url(url), | 91 m_url(url), |
47 m_ftp(0), | 92 m_ftp(0), |
48 m_http(0), | 93 m_http(0), |
49 m_localFile(0), | 94 m_localFile(0), |
50 m_ok(false), | 95 m_ok(false), |
51 m_lastStatus(0), | 96 m_lastStatus(0), |
97 m_remote(isRemote(url.toString())), | |
52 m_done(false), | 98 m_done(false), |
99 m_leaveLocalFile(false), | |
53 m_progressDialog(0), | 100 m_progressDialog(0), |
54 m_progressShowTimer(this), | 101 m_progressShowTimer(this), |
55 m_referenced(false) | 102 m_refCounted(false) |
56 { | 103 { |
57 if (!canHandleScheme(url)) { | 104 std::cerr << "RemoteFile::RemoteFile(" << url.toString().toStdString() << ") [as url]" << std::endl; |
58 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl; | 105 |
106 if (!canHandleScheme(m_url)) { | |
107 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | |
108 m_errorString = tr("Unsupported scheme in URL"); | |
59 return; | 109 return; |
60 } | 110 } |
61 | 111 |
62 QMutexLocker locker(&m_mapMutex); | 112 init(showProgress); |
63 | 113 } |
64 std::cerr << "RemoteFile::RemoteFile: refcount is " << m_refCountMap[m_url] << std::endl; | 114 |
65 | 115 RemoteFile::RemoteFile(const RemoteFile &rf) : |
66 if (m_refCountMap[m_url] > 0) { | 116 QObject(), |
67 m_refCountMap[m_url]++; | 117 m_url(rf.m_url), |
68 m_localFilename = m_remoteLocalMap[m_url]; | 118 m_ftp(0), |
69 std::cerr << "raising it" << std::endl; | 119 m_http(0), |
120 m_localFile(0), | |
121 m_ok(rf.m_ok), | |
122 m_lastStatus(rf.m_lastStatus), | |
123 m_remote(rf.m_remote), | |
124 m_done(false), | |
125 m_leaveLocalFile(false), | |
126 m_progressDialog(0), | |
127 m_progressShowTimer(0), | |
128 m_refCounted(false) | |
129 { | |
130 std::cerr << "RemoteFile::RemoteFile(" << m_url.toString().toStdString() << ") [copy ctor]" << std::endl; | |
131 | |
132 if (!canHandleScheme(m_url)) { | |
133 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; | |
134 m_errorString = tr("Unsupported scheme in URL"); | |
135 return; | |
136 } | |
137 | |
138 if (!isRemote()) { | |
139 m_localFilename = rf.m_localFilename; | |
140 } else { | |
141 QMutexLocker locker(&m_mapMutex); | |
142 std::cerr << "RemoteFile::RemoteFile(copy ctor): ref count is " | |
143 << m_refCountMap[m_url] << std::endl; | |
144 if (m_refCountMap[m_url] > 0) { | |
145 m_refCountMap[m_url]++; | |
146 std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl; | |
147 m_localFilename = m_remoteLocalMap[m_url]; | |
148 m_refCounted = true; | |
149 } else { | |
150 m_ok = false; | |
151 m_lastStatus = 404; | |
152 } | |
153 } | |
154 | |
155 m_done = true; | |
156 } | |
157 | |
158 RemoteFile::~RemoteFile() | |
159 { | |
160 std::cerr << "RemoteFile(" << m_url.toString().toStdString() << ")::~RemoteFile" << std::endl; | |
161 | |
162 cleanup(); | |
163 | |
164 if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); | |
165 } | |
166 | |
167 void | |
168 RemoteFile::init(bool showProgress) | |
169 { | |
170 if (!isRemote()) { | |
171 m_localFilename = m_url.toLocalFile(); | |
70 m_ok = true; | 172 m_ok = true; |
173 if (!QFileInfo(m_localFilename).exists()) { | |
174 m_lastStatus = 404; | |
175 } else { | |
176 m_lastStatus = 200; | |
177 } | |
71 m_done = true; | 178 m_done = true; |
72 m_referenced = true; | |
73 return; | 179 return; |
74 } | 180 } |
75 | 181 |
76 m_localFilename = createLocalFile(url); | 182 if (createCacheFile()) { |
183 std::cerr << "RemoteFile::init: Already have this one" << std::endl; | |
184 m_ok = true; | |
185 if (!QFileInfo(m_localFilename).exists()) { | |
186 m_lastStatus = 404; | |
187 } else { | |
188 m_lastStatus = 200; | |
189 } | |
190 m_done = true; | |
191 return; | |
192 } | |
193 | |
77 if (m_localFilename == "") return; | 194 if (m_localFilename == "") return; |
78 m_localFile = new QFile(m_localFilename); | 195 m_localFile = new QFile(m_localFilename); |
79 m_localFile->open(QFile::WriteOnly); | 196 m_localFile->open(QFile::WriteOnly); |
80 | 197 |
81 QString scheme = url.scheme().toLower(); | 198 QString scheme = m_url.scheme().toLower(); |
199 | |
200 std::cerr << "RemoteFile::init: Don't have local copy of \"" | |
201 << m_url.toString().toStdString() << "\", retrieving" << std::endl; | |
82 | 202 |
83 if (scheme == "http") { | 203 if (scheme == "http") { |
84 | 204 initHttp(); |
85 m_ok = true; | 205 } else if (scheme == "ftp") { |
86 m_http = new QHttp(url.host(), url.port(80)); | 206 initFtp(); |
87 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); | 207 } else { |
88 connect(m_http, SIGNAL(dataReadProgress(int, int)), | 208 m_remote = false; |
89 this, SLOT(dataReadProgress(int, int))); | 209 m_ok = false; |
90 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), | 210 } |
91 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &))); | 211 |
92 | 212 if (m_ok) { |
93 // I don't quite understand this. url.path() returns a path | 213 |
94 // without percent encoding; for example, spaces appear as | 214 QMutexLocker locker(&m_mapMutex); |
95 // literal spaces. This generally won't work if sent to the | 215 |
96 // server directly. You can retrieve a correctly encoded URL | 216 if (m_refCountMap[m_url] > 0) { |
97 // from QUrl using url.toEncoded(), but that gives you the | 217 // someone else has been doing the same thing at the same time, |
98 // whole URL; there doesn't seem to be any way to retrieve | 218 // but has got there first |
99 // only an encoded path. Furthermore there doesn't seem to be | 219 cleanup(); |
100 // any way to convert a retrieved path into an encoded path | 220 m_refCountMap[m_url]++; |
101 // without explicitly specifying that you don't want the path | 221 std::cerr << "RemoteFile::init: Another RemoteFile has got there first, abandoning our download and using theirs" << std::endl; |
102 // separators ("/") to be encoded. (Besides being painful to | 222 m_localFilename = m_remoteLocalMap[m_url]; |
103 // manage, I don't see how this can work correctly in any case | 223 m_refCounted = true; |
104 // where a percent-encoded "/" is supposed to appear within a | 224 m_ok = true; |
105 // path element?) There also seems to be no way to retrieve | 225 if (!QFileInfo(m_localFilename).exists()) { |
106 // the path plus query string, i.e. everything that I need to | 226 m_lastStatus = 404; |
107 // send to the HTTP server. And no way for QHttp to take a | |
108 // QUrl argument. I'm obviously missing something. | |
109 | |
110 // So, two ways to do this: query the bits from the URL, | |
111 // encode them individually, and glue them back together | |
112 // again... | |
113 /* | |
114 QString path = QUrl::toPercentEncoding(url.path(), "/"); | |
115 QList<QPair<QString, QString> > query = url.queryItems(); | |
116 if (!query.empty()) { | |
117 QStringList q2; | |
118 for (QList<QPair<QString, QString> >::iterator i = query.begin(); | |
119 i != query.end(); ++i) { | |
120 q2.push_back(QString("%1=%3") | |
121 .arg(QString(QUrl::toPercentEncoding(i->first))) | |
122 .arg(QString(QUrl::toPercentEncoding(i->second)))); | |
123 } | 227 } |
124 path = QString("%1%2%3") | 228 m_done = true; |
125 .arg(path).arg("?") | 229 return; |
126 .arg(q2.join("&")); | 230 } |
127 } | |
128 */ | |
129 | |
130 // ...or, much simpler but relying on knowledge about the | |
131 // scheme://host/path/path/query etc format of the URL, we can | |
132 // get the whole URL ready-encoded and then split it on "/" as | |
133 // appropriate... | |
134 | |
135 QString path = "/" + QString(url.toEncoded()).section('/', 3); | |
136 | |
137 std::cerr << "RemoteFile: path is \"" | |
138 << path.toStdString() << "\"" << std::endl; | |
139 | |
140 m_http->get(path, m_localFile); | |
141 | |
142 } else if (scheme == "ftp") { | |
143 | |
144 m_ok = true; | |
145 m_ftp = new QFtp; | |
146 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
147 connect(m_ftp, SIGNAL(commandFinished(int, bool)), | |
148 this, SLOT(ftpCommandFinished(int, bool))); | |
149 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), | |
150 this, SLOT(dataTransferProgress(qint64, qint64))); | |
151 m_ftp->connectToHost(url.host(), url.port(21)); | |
152 | |
153 QString username = url.userName(); | |
154 if (username == "") { | |
155 username = "anonymous"; | |
156 } | |
157 | |
158 QString password = url.password(); | |
159 if (password == "") { | |
160 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST")); | |
161 } | |
162 | |
163 m_ftp->login(username, password); | |
164 | |
165 QString dirpath = url.path().section('/', 0, -2); | |
166 QString filename = url.path().section('/', -1); | |
167 | |
168 if (dirpath == "") dirpath = "/"; | |
169 m_ftp->cd(dirpath); | |
170 m_ftp->get(filename, m_localFile); | |
171 } | |
172 | |
173 if (m_ok) { | |
174 | 231 |
175 m_remoteLocalMap[m_url] = m_localFilename; | 232 m_remoteLocalMap[m_url] = m_localFilename; |
176 m_refCountMap[m_url]++; | 233 m_refCountMap[m_url]++; |
177 m_referenced = true; | 234 m_refCounted = true; |
178 | 235 |
179 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100); | 236 if (showProgress) { |
180 m_progressDialog->hide(); | 237 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(m_url.toString()), tr("Cancel"), 0, 100); |
181 connect(&m_progressShowTimer, SIGNAL(timeout()), | 238 m_progressDialog->hide(); |
182 this, SLOT(showProgressDialog())); | 239 connect(&m_progressShowTimer, SIGNAL(timeout()), |
183 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); | 240 this, SLOT(showProgressDialog())); |
184 m_progressShowTimer.setSingleShot(true); | 241 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); |
185 m_progressShowTimer.start(2000); | 242 m_progressShowTimer.setSingleShot(true); |
186 } | 243 m_progressShowTimer.start(2000); |
187 } | 244 } |
188 | 245 } |
189 RemoteFile::~RemoteFile() | 246 } |
190 { | 247 |
191 cleanup(); | 248 void |
249 RemoteFile::initHttp() | |
250 { | |
251 m_ok = true; | |
252 m_http = new QHttp(m_url.host(), m_url.port(80)); | |
253 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
254 connect(m_http, SIGNAL(dataReadProgress(int, int)), | |
255 this, SLOT(dataReadProgress(int, int))); | |
256 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), | |
257 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &))); | |
258 | |
259 // I don't quite understand this. url.path() returns a path | |
260 // without percent encoding; for example, spaces appear as | |
261 // literal spaces. This generally won't work if sent to the | |
262 // server directly. You can retrieve a correctly encoded URL | |
263 // from QUrl using url.toEncoded(), but that gives you the | |
264 // whole URL; there doesn't seem to be any way to retrieve | |
265 // only an encoded path. Furthermore there doesn't seem to be | |
266 // any way to convert a retrieved path into an encoded path | |
267 // without explicitly specifying that you don't want the path | |
268 // separators ("/") to be encoded. (Besides being painful to | |
269 // manage, I don't see how this can work correctly in any case | |
270 // where a percent-encoded "/" is supposed to appear within a | |
271 // path element?) There also seems to be no way to retrieve | |
272 // the path plus query string, i.e. everything that I need to | |
273 // send to the HTTP server. And no way for QHttp to take a | |
274 // QUrl argument. I'm obviously missing something. | |
275 | |
276 // So, two ways to do this: query the bits from the URL, | |
277 // encode them individually, and glue them back together | |
278 // again... | |
279 /* | |
280 QString path = QUrl::toPercentEncoding(m_url.path(), "/"); | |
281 QList<QPair<QString, QString> > query = m_url.queryItems(); | |
282 if (!query.empty()) { | |
283 QStringList q2; | |
284 for (QList<QPair<QString, QString> >::iterator i = query.begin(); | |
285 i != query.end(); ++i) { | |
286 q2.push_back(QString("%1=%3") | |
287 .arg(QString(QUrl::toPercentEncoding(i->first))) | |
288 .arg(QString(QUrl::toPercentEncoding(i->second)))); | |
289 } | |
290 path = QString("%1%2%3") | |
291 .arg(path).arg("?") | |
292 .arg(q2.join("&")); | |
293 } | |
294 */ | |
295 | |
296 // ...or, much simpler but relying on knowledge about the | |
297 // scheme://host/path/path/query etc format of the URL, we can | |
298 // get the whole URL ready-encoded and then split it on "/" as | |
299 // appropriate... | |
300 | |
301 QString path = "/" + QString(m_url.toEncoded()).section('/', 3); | |
302 | |
303 std::cerr << "RemoteFile: path is \"" | |
304 << path.toStdString() << "\"" << std::endl; | |
305 | |
306 m_http->get(path, m_localFile); | |
307 } | |
308 | |
309 void | |
310 RemoteFile::initFtp() | |
311 { | |
312 m_ok = true; | |
313 m_ftp = new QFtp; | |
314 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
315 connect(m_ftp, SIGNAL(commandFinished(int, bool)), | |
316 this, SLOT(ftpCommandFinished(int, bool))); | |
317 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), | |
318 this, SLOT(dataTransferProgress(qint64, qint64))); | |
319 m_ftp->connectToHost(m_url.host(), m_url.port(21)); | |
320 | |
321 QString username = m_url.userName(); | |
322 if (username == "") { | |
323 username = "anonymous"; | |
324 } | |
325 | |
326 QString password = m_url.password(); | |
327 if (password == "") { | |
328 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST")); | |
329 } | |
330 | |
331 m_ftp->login(username, password); | |
332 | |
333 QString dirpath = m_url.path().section('/', 0, -2); | |
334 QString filename = m_url.path().section('/', -1); | |
335 | |
336 if (dirpath == "") dirpath = "/"; | |
337 m_ftp->cd(dirpath); | |
338 m_ftp->get(filename, m_localFile); | |
192 } | 339 } |
193 | 340 |
194 void | 341 void |
195 RemoteFile::cleanup() | 342 RemoteFile::cleanup() |
196 { | 343 { |
214 } | 361 } |
215 | 362 |
216 bool | 363 bool |
217 RemoteFile::isRemote(QString fileOrUrl) | 364 RemoteFile::isRemote(QString fileOrUrl) |
218 { | 365 { |
219 return (fileOrUrl.startsWith("http:") || fileOrUrl.startsWith("ftp:")); | 366 QString scheme = QUrl(fileOrUrl).scheme().toLower(); |
367 return (scheme == "http" || scheme == "ftp"); | |
220 } | 368 } |
221 | 369 |
222 bool | 370 bool |
223 RemoteFile::canHandleScheme(QUrl url) | 371 RemoteFile::canHandleScheme(QUrl url) |
224 { | 372 { |
225 QString scheme = url.scheme().toLower(); | 373 QString scheme = url.scheme().toLower(); |
226 return (scheme == "http" || scheme == "ftp"); | 374 return (scheme == "http" || scheme == "ftp" || |
375 scheme == "file" || scheme == ""); | |
227 } | 376 } |
228 | 377 |
229 bool | 378 bool |
230 RemoteFile::isAvailable() | 379 RemoteFile::isAvailable() |
231 { | 380 { |
232 while (m_ok && (!m_done && m_lastStatus == 0)) { | 381 waitForStatus(); |
233 QApplication::processEvents(); | |
234 } | |
235 bool available = true; | 382 bool available = true; |
236 if (!m_ok) available = false; | 383 if (!m_ok) available = false; |
237 else available = (m_lastStatus / 100 == 2); | 384 else available = (m_lastStatus / 100 == 2); |
238 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no") | 385 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no") |
239 << std::endl; | 386 << std::endl; |
240 return available; | 387 return available; |
241 } | 388 } |
242 | 389 |
243 void | 390 void |
244 RemoteFile::wait() | 391 RemoteFile::waitForStatus() |
392 { | |
393 while (m_ok && (!m_done && m_lastStatus == 0)) { | |
394 // std::cerr << "waitForStatus: processing (last status " << m_lastStatus << ")" << std::endl; | |
395 QApplication::processEvents(); | |
396 } | |
397 } | |
398 | |
399 void | |
400 RemoteFile::waitForData() | |
245 { | 401 { |
246 while (m_ok && !m_done) { | 402 while (m_ok && !m_done) { |
247 QApplication::processEvents(); | 403 QApplication::processEvents(); |
248 } | 404 } |
249 } | 405 } |
250 | 406 |
407 void | |
408 RemoteFile::setLeaveLocalFile(bool leave) | |
409 { | |
410 m_leaveLocalFile = leave; | |
411 } | |
412 | |
251 bool | 413 bool |
252 RemoteFile::isOK() const | 414 RemoteFile::isOK() const |
253 { | 415 { |
254 return m_ok; | 416 return m_ok; |
255 } | 417 } |
258 RemoteFile::isDone() const | 420 RemoteFile::isDone() const |
259 { | 421 { |
260 return m_done; | 422 return m_done; |
261 } | 423 } |
262 | 424 |
425 bool | |
426 RemoteFile::isRemote() const | |
427 { | |
428 return m_remote; | |
429 } | |
430 | |
431 QString | |
432 RemoteFile::getLocation() const | |
433 { | |
434 return m_url.toString(); | |
435 } | |
436 | |
263 QString | 437 QString |
264 RemoteFile::getLocalFilename() const | 438 RemoteFile::getLocalFilename() const |
265 { | 439 { |
266 return m_localFilename; | 440 return m_localFilename; |
441 } | |
442 | |
443 QString | |
444 RemoteFile::getContentType() const | |
445 { | |
446 return m_contentType; | |
447 } | |
448 | |
449 QString | |
450 RemoteFile::getExtension() const | |
451 { | |
452 if (m_localFilename != "") { | |
453 return QFileInfo(m_localFilename).suffix().toLower(); | |
454 } else { | |
455 return QFileInfo(m_url.toLocalFile()).suffix().toLower(); | |
456 } | |
267 } | 457 } |
268 | 458 |
269 QString | 459 QString |
270 RemoteFile::getErrorString() const | 460 RemoteFile::getErrorString() const |
271 { | 461 { |
337 } | 527 } |
338 | 528 |
339 void | 529 void |
340 RemoteFile::cancelled() | 530 RemoteFile::cancelled() |
341 { | 531 { |
342 deleteLocalFile(); | |
343 m_done = true; | 532 m_done = true; |
533 cleanup(); | |
534 | |
344 m_ok = false; | 535 m_ok = false; |
345 m_errorString = tr("Download cancelled"); | 536 m_errorString = tr("Download cancelled"); |
346 } | 537 } |
347 | 538 |
348 void | 539 void |
378 error = true; | 569 error = true; |
379 } | 570 } |
380 } | 571 } |
381 | 572 |
382 if (error) { | 573 if (error) { |
383 deleteLocalFile(); | 574 std::cerr << "RemoteFile::done: error is " << error << ", deleting cache file" << std::endl; |
575 deleteCacheFile(); | |
384 } | 576 } |
385 | 577 |
386 m_ok = !error; | 578 m_ok = !error; |
387 m_done = true; | 579 m_done = true; |
388 emit ready(); | 580 emit ready(); |
389 } | 581 } |
390 | 582 |
391 void | 583 void |
392 RemoteFile::deleteLocalFile() | 584 RemoteFile::deleteCacheFile() |
393 { | 585 { |
394 // std::cerr << "RemoteFile::deleteLocalFile" << std::endl; | 586 std::cerr << "RemoteFile::deleteCacheFile(\"" << m_localFilename.toStdString() << "\")" << std::endl; |
395 | 587 |
396 cleanup(); | 588 cleanup(); |
397 | 589 |
398 if (m_localFilename == "") return; | 590 if (m_localFilename == "") { |
399 | 591 return; |
400 if (m_referenced) { | 592 } |
593 | |
594 if (!isRemote()) { | |
595 std::cerr << "not a cache file" << std::endl; | |
596 return; | |
597 } | |
598 | |
599 if (m_refCounted) { | |
401 | 600 |
402 QMutexLocker locker(&m_mapMutex); | 601 QMutexLocker locker(&m_mapMutex); |
403 m_referenced = false; | 602 m_refCounted = false; |
404 | 603 |
405 if (m_refCountMap[m_url] > 0) { | 604 if (m_refCountMap[m_url] > 0) { |
406 m_refCountMap[m_url]--; | 605 m_refCountMap[m_url]--; |
606 std::cerr << "reduced ref count to " << m_refCountMap[m_url] << std::endl; | |
407 if (m_refCountMap[m_url] > 0) { | 607 if (m_refCountMap[m_url] > 0) { |
408 m_done = true; | 608 m_done = true; |
409 return; | 609 return; |
410 } | 610 } |
411 } | 611 } |
412 } | 612 } |
413 | 613 |
414 m_fileCreationMutex.lock(); | 614 m_fileCreationMutex.lock(); |
415 | 615 |
416 if (!QFile(m_localFilename).remove()) { | 616 if (!QFile(m_localFilename).remove()) { |
417 std::cerr << "RemoteFile::deleteLocalFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; | 617 std::cerr << "RemoteFile::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; |
418 } else { | 618 } else { |
619 std::cerr << "RemoteFile::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl; | |
419 m_localFilename = ""; | 620 m_localFilename = ""; |
420 } | 621 } |
421 | 622 |
422 m_fileCreationMutex.unlock(); | 623 m_fileCreationMutex.unlock(); |
423 | 624 |
428 RemoteFile::showProgressDialog() | 629 RemoteFile::showProgressDialog() |
429 { | 630 { |
430 if (m_progressDialog) m_progressDialog->show(); | 631 if (m_progressDialog) m_progressDialog->show(); |
431 } | 632 } |
432 | 633 |
433 QString | 634 bool |
434 RemoteFile::createLocalFile(QUrl url) | 635 RemoteFile::createCacheFile() |
435 { | 636 { |
637 { | |
638 QMutexLocker locker(&m_mapMutex); | |
639 | |
640 std::cerr << "RemoteFile::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl; | |
641 | |
642 if (m_refCountMap[m_url] > 0) { | |
643 m_refCountMap[m_url]++; | |
644 m_localFilename = m_remoteLocalMap[m_url]; | |
645 std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl; | |
646 m_refCounted = true; | |
647 return true; | |
648 } | |
649 } | |
650 | |
436 QDir dir; | 651 QDir dir; |
437 try { | 652 try { |
438 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); | 653 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); |
439 } catch (DirectoryCreationFailed f) { | 654 } catch (DirectoryCreationFailed f) { |
440 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; | 655 std::cerr << "RemoteFile::createCacheFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; |
441 return ""; | 656 return ""; |
442 } | 657 } |
443 | 658 |
444 QString filepart = url.path().section('/', -1, -1, | 659 QString filepart = m_url.path().section('/', -1, -1, |
445 QString::SectionSkipEmpty); | 660 QString::SectionSkipEmpty); |
446 | 661 |
447 QString extension = filepart.section('.', -1); | 662 QString extension = filepart.section('.', -1); |
448 QString base = filepart; | 663 QString base = filepart; |
449 if (extension != "") { | 664 if (extension != "") { |
450 base = base.left(base.length() - extension.length() - 1); | 665 base = base.left(base.length() - extension.length() - 1); |
459 filename = QString("%1.%2").arg(base).arg(extension); | 674 filename = QString("%1.%2").arg(base).arg(extension); |
460 } | 675 } |
461 | 676 |
462 QString filepath(dir.filePath(filename)); | 677 QString filepath(dir.filePath(filename)); |
463 | 678 |
464 std::cerr << "RemoteFile::createLocalFile: URL is \"" << url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl; | 679 std::cerr << "RemoteFile::createCacheFile: URL is \"" << m_url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl; |
465 | 680 |
466 m_fileCreationMutex.lock(); | 681 QMutexLocker fcLocker(&m_fileCreationMutex); |
682 | |
467 ++m_count; | 683 ++m_count; |
468 | 684 |
469 if (QFileInfo(filepath).exists() || | 685 if (QFileInfo(filepath).exists() || |
470 !QFile(filepath).open(QFile::WriteOnly)) { | 686 !QFile(filepath).open(QFile::WriteOnly)) { |
471 | 687 |
472 std::cerr << "RemoteFile::createLocalFile: Failed to create local file \"" | 688 std::cerr << "RemoteFile::createCacheFile: Failed to create local file \"" |
473 << filepath.toStdString() << "\" for URL \"" | 689 << filepath.toStdString() << "\" for URL \"" |
474 << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; | 690 << m_url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; |
475 | 691 |
476 | 692 |
477 if (extension == "") { | 693 if (extension == "") { |
478 filename = QString("%1_%2").arg(base).arg(m_count); | 694 filename = QString("%1_%2").arg(base).arg(m_count); |
479 } else { | 695 } else { |
482 filepath = dir.filePath(filename); | 698 filepath = dir.filePath(filename); |
483 | 699 |
484 if (QFileInfo(filepath).exists() || | 700 if (QFileInfo(filepath).exists() || |
485 !QFile(filepath).open(QFile::WriteOnly)) { | 701 !QFile(filepath).open(QFile::WriteOnly)) { |
486 | 702 |
487 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \"" | 703 std::cerr << "RemoteFile::createCacheFile: ERROR: Failed to create local file \"" |
488 << filepath.toStdString() << "\" for URL \"" | 704 << filepath.toStdString() << "\" for URL \"" |
489 << url.toString().toStdString() << "\" (or file already exists)" << std::endl; | 705 << m_url.toString().toStdString() << "\" (or file already exists)" << std::endl; |
490 | 706 |
491 m_fileCreationMutex.unlock(); | |
492 return ""; | 707 return ""; |
493 } | 708 } |
494 } | 709 } |
495 | 710 |
496 m_fileCreationMutex.unlock(); | 711 std::cerr << "RemoteFile::createCacheFile: url " |
497 | 712 << m_url.toString().toStdString() << " -> local filename " |
498 std::cerr << "RemoteFile::createLocalFile: url " | |
499 << url.toString().toStdString() << " -> local filename " | |
500 << filepath.toStdString() << std::endl; | 713 << filepath.toStdString() << std::endl; |
501 | 714 |
502 return filepath; | 715 m_localFilename = filepath; |
503 } | 716 |
717 return false; | |
718 } |