Mercurial > hg > easaier-soundaccess
comparison data/fileio/RemoteFile.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2007 QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "RemoteFile.h" | |
17 #include "base/TempDirectory.h" | |
18 #include "base/Exceptions.h" | |
19 | |
20 #include <QHttp> | |
21 #include <QFtp> | |
22 #include <QFileInfo> | |
23 #include <QDir> | |
24 #include <QApplication> | |
25 #include <QProgressDialog> | |
26 #include <QHttpResponseHeader> | |
27 | |
28 #include <iostream> | |
29 | |
30 int | |
31 RemoteFile::m_count = 0; | |
32 | |
33 QMutex | |
34 RemoteFile::m_fileCreationMutex; | |
35 | |
36 RemoteFile::RemoteFile(QUrl url) : | |
37 m_ftp(0), | |
38 m_http(0), | |
39 m_localFile(0), | |
40 m_ok(false), | |
41 m_lastStatus(0), | |
42 m_done(false), | |
43 m_progressDialog(0), | |
44 m_progressShowTimer(this) | |
45 { | |
46 if (!canHandleScheme(url)) { | |
47 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl; | |
48 return; | |
49 } | |
50 | |
51 m_localFilename = createLocalFile(url); | |
52 if (m_localFilename == "") return; | |
53 m_localFile = new QFile(m_localFilename); | |
54 m_localFile->open(QFile::WriteOnly); | |
55 | |
56 QString scheme = url.scheme().toLower(); | |
57 | |
58 if (scheme == "http") { | |
59 | |
60 m_ok = true; | |
61 m_http = new QHttp(url.host(), url.port(80)); | |
62 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
63 connect(m_http, SIGNAL(dataReadProgress(int, int)), | |
64 this, SLOT(dataReadProgress(int, int))); | |
65 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), | |
66 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &))); | |
67 m_http->get(url.path(), m_localFile); | |
68 | |
69 } else if (scheme == "ftp") { | |
70 | |
71 m_ok = true; | |
72 m_ftp = new QFtp; | |
73 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
74 connect(m_ftp, SIGNAL(commandFinished(int, bool)), | |
75 this, SLOT(ftpCommandFinished(int, bool))); | |
76 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), | |
77 this, SLOT(dataTransferProgress(qint64, qint64))); | |
78 m_ftp->connectToHost(url.host(), url.port(21)); | |
79 | |
80 QString username = url.userName(); | |
81 if (username == "") { | |
82 username = "anonymous"; | |
83 } | |
84 | |
85 QString password = url.password(); | |
86 if (password == "") { | |
87 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST")); | |
88 } | |
89 | |
90 m_ftp->login(username, password); | |
91 | |
92 QString dirpath = url.path().section('/', 0, -2); | |
93 QString filename = url.path().section('/', -1); | |
94 | |
95 if (dirpath == "") dirpath = "/"; | |
96 m_ftp->cd(dirpath); | |
97 m_ftp->get(filename, m_localFile); | |
98 } | |
99 | |
100 if (m_ok) { | |
101 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100); | |
102 m_progressDialog->hide(); | |
103 connect(&m_progressShowTimer, SIGNAL(timeout()), | |
104 this, SLOT(showProgressDialog())); | |
105 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); | |
106 m_progressShowTimer.setSingleShot(true); | |
107 m_progressShowTimer.start(2000); | |
108 } | |
109 } | |
110 | |
111 RemoteFile::~RemoteFile() | |
112 { | |
113 cleanup(); | |
114 } | |
115 | |
116 void | |
117 RemoteFile::cleanup() | |
118 { | |
119 // std::cerr << "RemoteFile::cleanup" << std::endl; | |
120 m_done = true; | |
121 if (m_http) { | |
122 delete m_http; | |
123 m_http = 0; | |
124 } | |
125 if (m_ftp) { | |
126 m_ftp->abort(); | |
127 m_ftp->deleteLater(); | |
128 m_ftp = 0; | |
129 } | |
130 delete m_progressDialog; | |
131 m_progressDialog = 0; | |
132 delete m_localFile; | |
133 m_localFile = 0; | |
134 } | |
135 | |
136 bool | |
137 RemoteFile::canHandleScheme(QUrl url) | |
138 { | |
139 QString scheme = url.scheme().toLower(); | |
140 return (scheme == "http" || scheme == "ftp"); | |
141 } | |
142 | |
143 bool | |
144 RemoteFile::isAvailable() | |
145 { | |
146 while (m_ok && (!m_done && m_lastStatus == 0)) { | |
147 QApplication::processEvents(); | |
148 } | |
149 bool available = true; | |
150 if (!m_ok) available = false; | |
151 else available = (m_lastStatus / 100 == 2); | |
152 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no") | |
153 << std::endl; | |
154 return available; | |
155 } | |
156 | |
157 void | |
158 RemoteFile::wait() | |
159 { | |
160 while (m_ok && !m_done) { | |
161 QApplication::processEvents(); | |
162 } | |
163 } | |
164 | |
165 bool | |
166 RemoteFile::isOK() const | |
167 { | |
168 return m_ok; | |
169 } | |
170 | |
171 bool | |
172 RemoteFile::isDone() const | |
173 { | |
174 return m_done; | |
175 } | |
176 | |
177 QString | |
178 RemoteFile::getLocalFilename() const | |
179 { | |
180 return m_localFilename; | |
181 } | |
182 | |
183 QString | |
184 RemoteFile::getErrorString() const | |
185 { | |
186 return m_errorString; | |
187 } | |
188 | |
189 void | |
190 RemoteFile::dataReadProgress(int done, int total) | |
191 { | |
192 dataTransferProgress(done, total); | |
193 } | |
194 | |
195 void | |
196 RemoteFile::httpResponseHeaderReceived(const QHttpResponseHeader &resp) | |
197 { | |
198 m_lastStatus = resp.statusCode(); | |
199 if (m_lastStatus / 100 >= 4) { | |
200 m_errorString = QString("%1 %2") | |
201 .arg(resp.statusCode()).arg(resp.reasonPhrase()); | |
202 std::cerr << "RemoteFile::responseHeaderReceived: " | |
203 << m_errorString.toStdString() << std::endl; | |
204 } else { | |
205 std::cerr << "RemoteFile::responseHeaderReceived: " | |
206 << m_lastStatus << std::endl; | |
207 } | |
208 } | |
209 | |
210 void | |
211 RemoteFile::ftpCommandFinished(int id, bool error) | |
212 { | |
213 std::cerr << "RemoteFile::ftpCommandFinished(" << id << ", " << error << ")" << std::endl; | |
214 | |
215 if (!m_ftp) return; | |
216 | |
217 QFtp::Command command = m_ftp->currentCommand(); | |
218 | |
219 if (!error) { | |
220 std::cerr << "RemoteFile::ftpCommandFinished: success for command " | |
221 << command << std::endl; | |
222 return; | |
223 } | |
224 | |
225 if (command == QFtp::ConnectToHost) { | |
226 m_errorString = tr("Failed to connect to FTP server"); | |
227 } else if (command == QFtp::Login) { | |
228 m_errorString = tr("Login failed"); | |
229 } else if (command == QFtp::Cd) { | |
230 m_errorString = tr("Failed to change to correct directory"); | |
231 } else if (command == QFtp::Get) { | |
232 m_errorString = tr("FTP download aborted"); | |
233 } | |
234 | |
235 m_lastStatus = 400; // for done() | |
236 } | |
237 | |
238 void | |
239 RemoteFile::dataTransferProgress(qint64 done, qint64 total) | |
240 { | |
241 if (!m_progressDialog) return; | |
242 | |
243 int percent = int((double(done) / double(total)) * 100.0 - 0.1); | |
244 emit progress(percent); | |
245 | |
246 if (percent > 0) { | |
247 m_progressDialog->setValue(percent); | |
248 m_progressDialog->show(); | |
249 } | |
250 } | |
251 | |
252 void | |
253 RemoteFile::cancelled() | |
254 { | |
255 deleteLocalFile(); | |
256 m_done = true; | |
257 m_ok = false; | |
258 m_errorString = tr("Download cancelled"); | |
259 } | |
260 | |
261 void | |
262 RemoteFile::done(bool error) | |
263 { | |
264 std::cerr << "RemoteFile::done(" << error << ")" << std::endl; | |
265 | |
266 if (m_done) return; | |
267 | |
268 emit progress(100); | |
269 | |
270 if (error) { | |
271 if (m_http) { | |
272 m_errorString = m_http->errorString(); | |
273 } else if (m_ftp) { | |
274 m_errorString = m_ftp->errorString(); | |
275 } | |
276 } | |
277 | |
278 if (m_lastStatus / 100 >= 4) { | |
279 error = true; | |
280 } | |
281 | |
282 cleanup(); | |
283 | |
284 if (!error) { | |
285 QFileInfo fi(m_localFilename); | |
286 if (!fi.exists()) { | |
287 m_errorString = tr("Failed to create local file %1").arg(m_localFilename); | |
288 error = true; | |
289 } else if (fi.size() == 0) { | |
290 m_errorString = tr("File contains no data!"); | |
291 error = true; | |
292 } | |
293 } | |
294 | |
295 if (error) { | |
296 deleteLocalFile(); | |
297 } | |
298 | |
299 m_ok = !error; | |
300 m_done = true; | |
301 } | |
302 | |
303 void | |
304 RemoteFile::deleteLocalFile() | |
305 { | |
306 // std::cerr << "RemoteFile::deleteLocalFile" << std::endl; | |
307 | |
308 cleanup(); | |
309 | |
310 if (m_localFilename == "") return; | |
311 | |
312 m_fileCreationMutex.lock(); | |
313 | |
314 if (!QFile(m_localFilename).remove()) { | |
315 std::cerr << "RemoteFile::deleteLocalFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; | |
316 } else { | |
317 m_localFilename = ""; | |
318 } | |
319 | |
320 m_fileCreationMutex.unlock(); | |
321 | |
322 m_done = true; | |
323 } | |
324 | |
325 void | |
326 RemoteFile::showProgressDialog() | |
327 { | |
328 if (m_progressDialog) m_progressDialog->show(); | |
329 } | |
330 | |
331 QString | |
332 RemoteFile::createLocalFile(QUrl url) | |
333 { | |
334 QDir dir; | |
335 try { | |
336 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); | |
337 } catch (DirectoryCreationFailed f) { | |
338 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; | |
339 return ""; | |
340 } | |
341 | |
342 QString filepart = url.path().section('/', -1, -1, | |
343 QString::SectionSkipEmpty); | |
344 | |
345 QString extension = filepart.section('.', -1); | |
346 QString base = filepart; | |
347 if (extension != "") { | |
348 base = base.left(base.length() - extension.length() - 1); | |
349 } | |
350 if (base == "") base = "remote"; | |
351 | |
352 QString filename; | |
353 | |
354 if (extension == "") { | |
355 filename = base; | |
356 } else { | |
357 filename = QString("%1.%2").arg(base).arg(extension); | |
358 } | |
359 | |
360 QString filepath(dir.filePath(filename)); | |
361 | |
362 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; | |
363 | |
364 m_fileCreationMutex.lock(); | |
365 ++m_count; | |
366 | |
367 if (QFileInfo(filepath).exists() || | |
368 !QFile(filepath).open(QFile::WriteOnly)) { | |
369 | |
370 std::cerr << "RemoteFile::createLocalFile: Failed to create local file \"" | |
371 << filepath.toStdString() << "\" for URL \"" | |
372 << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; | |
373 | |
374 | |
375 if (extension == "") { | |
376 filename = QString("%1_%2").arg(base).arg(m_count); | |
377 } else { | |
378 filename = QString("%1_%2.%3").arg(base).arg(m_count).arg(extension); | |
379 } | |
380 filepath = dir.filePath(filename); | |
381 | |
382 if (QFileInfo(filepath).exists() || | |
383 !QFile(filepath).open(QFile::WriteOnly)) { | |
384 | |
385 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \"" | |
386 << filepath.toStdString() << "\" for URL \"" | |
387 << url.toString().toStdString() << "\" (or file already exists)" << std::endl; | |
388 | |
389 m_fileCreationMutex.unlock(); | |
390 return ""; | |
391 } | |
392 } | |
393 | |
394 m_fileCreationMutex.unlock(); | |
395 | |
396 std::cerr << "RemoteFile::createLocalFile: url " | |
397 << url.toString().toStdString() << " -> local filename " | |
398 << filepath.toStdString() << std::endl; | |
399 | |
400 return filepath; | |
401 } |