Mercurial > hg > svcore
comparison data/fileio/RemoteFile.cpp @ 208:8a3d68910b37
* Framework for retrieving files from remote locations
author | Chris Cannam |
---|---|
date | Mon, 08 Jan 2007 17:04:35 +0000 |
parents | |
children | a06afefe45ee |
comparison
equal
deleted
inserted
replaced
207:8ee6cf529c4e | 208:8a3d68910b37 |
---|---|
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 | |
27 #include <iostream> | |
28 | |
29 int | |
30 RemoteFile::m_count = 0; | |
31 | |
32 QMutex | |
33 RemoteFile::m_fileCreationMutex; | |
34 | |
35 RemoteFile::RemoteFile(QUrl url) : | |
36 m_ftp(0), | |
37 m_http(0), | |
38 m_localFile(0), | |
39 m_ok(false), | |
40 m_done(false), | |
41 m_progressDialog(0) | |
42 { | |
43 if (!canHandleScheme(url)) { | |
44 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl; | |
45 return; | |
46 } | |
47 | |
48 m_localFilename = createLocalFile(url); | |
49 if (m_localFilename == "") return; | |
50 m_localFile = new QFile(m_localFilename); | |
51 m_localFile->open(QFile::WriteOnly); | |
52 | |
53 QString scheme = url.scheme().toLower(); | |
54 | |
55 if (scheme == "http") { | |
56 | |
57 m_http = new QHttp(url.host(), url.port(80)); | |
58 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
59 connect(m_http, SIGNAL(dataReadProgress(int, int)), | |
60 this, SLOT(dataReadProgress(int, int))); | |
61 m_http->get(url.path(), m_localFile); | |
62 m_ok = true; | |
63 | |
64 } else if (scheme == "ftp") { | |
65 | |
66 m_ftp = new QFtp; | |
67 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); | |
68 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), | |
69 this, SLOT(dataTransferProgress(qint64, qint64))); | |
70 m_ftp->connectToHost(url.host(), url.port(21)); | |
71 | |
72 QString username = url.userName(); | |
73 if (username == "") { | |
74 username = "anonymous"; | |
75 } | |
76 | |
77 QString password = url.password(); | |
78 if (password == "") { | |
79 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST")); | |
80 } | |
81 | |
82 QStringList path = url.path().split('/'); | |
83 for (QStringList::iterator i = path.begin(); i != path.end(); ) { | |
84 QString bit = *i; | |
85 ++i; | |
86 if (i != path.end()) { | |
87 m_ftp->cd(*i); | |
88 } else { | |
89 m_ftp->get(*i, m_localFile); | |
90 } | |
91 } | |
92 | |
93 m_ok = true; | |
94 } | |
95 | |
96 if (m_ok) { | |
97 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100); | |
98 m_progressDialog->show(); | |
99 } | |
100 } | |
101 | |
102 RemoteFile::~RemoteFile() | |
103 { | |
104 delete m_ftp; | |
105 delete m_http; | |
106 delete m_localFile; | |
107 delete m_progressDialog; | |
108 } | |
109 | |
110 bool | |
111 RemoteFile::canHandleScheme(QUrl url) | |
112 { | |
113 QString scheme = url.scheme().toLower(); | |
114 return (scheme == "http" || scheme == "ftp"); | |
115 } | |
116 | |
117 void | |
118 RemoteFile::wait() | |
119 { | |
120 while (!m_done) { | |
121 QApplication::processEvents(); | |
122 } | |
123 } | |
124 | |
125 bool | |
126 RemoteFile::isOK() const | |
127 { | |
128 return m_ok; | |
129 } | |
130 | |
131 bool | |
132 RemoteFile::isDone() const | |
133 { | |
134 return m_done; | |
135 } | |
136 | |
137 QString | |
138 RemoteFile::getLocalFilename() const | |
139 { | |
140 return m_localFilename; | |
141 } | |
142 | |
143 QString | |
144 RemoteFile::getErrorString() const | |
145 { | |
146 return m_errorString; | |
147 } | |
148 | |
149 void | |
150 RemoteFile::dataReadProgress(int done, int total) | |
151 { | |
152 dataTransferProgress(done, total); | |
153 } | |
154 | |
155 void | |
156 RemoteFile::dataTransferProgress(qint64 done, qint64 total) | |
157 { | |
158 int percent = int((double(done) / double(total)) * 100.0 - 0.1); | |
159 emit progress(percent); | |
160 | |
161 m_progressDialog->setValue(percent); | |
162 } | |
163 | |
164 void | |
165 RemoteFile::done(bool error) | |
166 { | |
167 //!!! need to identify 404s etc in the return headers | |
168 | |
169 emit progress(100); | |
170 m_ok = !error; | |
171 if (error) { | |
172 if (m_http) { | |
173 m_errorString = m_http->errorString(); | |
174 } else if (m_ftp) { | |
175 m_errorString = m_ftp->errorString(); | |
176 } | |
177 } | |
178 | |
179 delete m_localFile; | |
180 m_localFile = 0; | |
181 | |
182 delete m_progressDialog; | |
183 m_progressDialog = 0; | |
184 | |
185 if (m_ok) { | |
186 QFileInfo fi(m_localFilename); | |
187 if (!fi.exists()) { | |
188 m_errorString = tr("Failed to create local file %1").arg(m_localFilename); | |
189 m_ok = false; | |
190 } else if (fi.size() == 0) { | |
191 m_errorString = tr("File contains no data!"); | |
192 m_ok = false; | |
193 } | |
194 } | |
195 m_done = true; | |
196 } | |
197 | |
198 QString | |
199 RemoteFile::createLocalFile(QUrl url) | |
200 { | |
201 //!!! should we actually put up dialogs for these errors? or propagate an exception? | |
202 | |
203 QDir dir; | |
204 try { | |
205 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); | |
206 } catch (DirectoryCreationFailed f) { | |
207 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; | |
208 return ""; | |
209 } | |
210 | |
211 QString filepart = url.path().section('/', -1, -1, | |
212 QString::SectionSkipEmpty); | |
213 | |
214 QString extension = filepart.section('.', -1); | |
215 QString base = filepart; | |
216 if (extension != "") { | |
217 base = base.left(base.length() - extension.length() - 1); | |
218 } | |
219 if (base == "") base = "remote"; | |
220 | |
221 QString filename; | |
222 | |
223 if (extension == "") { | |
224 filename = base; | |
225 } else { | |
226 filename = QString("%1.%2").arg(base).arg(extension); | |
227 } | |
228 | |
229 QString filepath(dir.filePath(filename)); | |
230 | |
231 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; | |
232 | |
233 m_fileCreationMutex.lock(); | |
234 ++m_count; | |
235 | |
236 if (QFileInfo(filepath).exists() || | |
237 !QFile(filepath).open(QFile::WriteOnly)) { | |
238 | |
239 std::cerr << "RemoteFile::createLocalFile: Failed to create local file \"" | |
240 << filepath.toStdString() << "\" for URL \"" | |
241 << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; | |
242 | |
243 | |
244 if (extension == "") { | |
245 filename = QString("%1_%2").arg(base).arg(m_count); | |
246 } else { | |
247 filename = QString("%1_%2.%3").arg(base).arg(m_count).arg(extension); | |
248 } | |
249 filepath = dir.filePath(filename); | |
250 | |
251 if (QFileInfo(filepath).exists() || | |
252 !QFile(filepath).open(QFile::WriteOnly)) { | |
253 | |
254 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \"" | |
255 << filepath.toStdString() << "\" for URL \"" | |
256 << url.toString().toStdString() << "\" (or file already exists)" << std::endl; | |
257 | |
258 m_fileCreationMutex.unlock(); | |
259 return ""; | |
260 } | |
261 } | |
262 | |
263 m_fileCreationMutex.unlock(); | |
264 | |
265 std::cerr << "RemoteFile::createLocalFile: url " | |
266 << url.toString().toStdString() << " -> local filename " | |
267 << filepath.toStdString() << std::endl; | |
268 | |
269 return filepath; | |
270 } |