1 /* This file is part of the KDE project 2 3 Copyright (C) 2008 Lukas Appelhans <l.appelhans@gmx.de> 4 Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net> 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public 8 License as published by the Free Software Foundation; either 9 version 2 of the License, or (at your option) any later version. 10 */ 11 #ifndef DATASOURCEFACTORY_H 12 #define DATASOURCEFACTORY_H 13 14 #include "kget_export.h" 15 16 #include "transferdatasource.h" 17 #include "job.h" 18 19 #include <kio/job.h> 20 21 #include <QDomElement> 22 23 class BitSet; 24 class TransferDataSource; 25 class QTimer; 26 class Signature; 27 class Verifier; 28 29 namespace KIO 30 { 31 class FileJob; 32 } 33 34 /** 35 This class manages multiple DataSources and saves the received data to the file 36 */ 37 class KGET_EXPORT DataSourceFactory : public QObject 38 { 39 Q_OBJECT 40 41 public: 42 /** 43 * In general use this constructor, if the size is 0, the datasourcefactory will try to 44 * find the filesize 45 * @note when you want to load a datasourcefactory you do not have to specify the url and segSize 46 */ 47 explicit DataSourceFactory(QObject *parent, const QUrl &dest = QUrl(), KIO::filesize_t size = 0, KIO::fileoffset_t segSize = 512000); 48 49 ~DataSourceFactory() override; 50 51 /** 52 * The capabilities the DataSourceFactory supports 53 */ capabilities()54 Transfer::Capabilities capabilities() const {return m_capabilities;} 55 56 /** 57 * Deletes the created (downloadInitialized() is true) file if the download was not finished 58 * Does not delete anything if the download never got started 59 * @see downloadInitialized() 60 */ 61 void deinit(); 62 63 /** 64 * @return true if the DataSourceFactory has enough information to start a download 65 */ 66 bool isValid() const; 67 68 void start(); 69 void stop(); size()70 KIO::filesize_t size() const {return m_size;} downloadedSize()71 KIO::filesize_t downloadedSize() const {return m_downloadedSize;} currentSpeed()72 ulong currentSpeed() const {return m_speed;} percent()73 ulong percent() const {return m_percent;} 74 dest()75 QUrl dest() const {return m_dest;} 76 77 /** 78 * The maximum number of mirrors that will be used for downloading, default is 3 79 */ maxMirrorsUsed()80 int maxMirrorsUsed() const {return m_maxMirrorsUsed;} 81 82 /** 83 * Change the maximum number off mirrors that will be used for downloading, 84 * if the download started already some mirrors might be added or removed automatically 85 */ setMaxMirrorsUsed(int maxMirrorsUsed)86 void setMaxMirrorsUsed(int maxMirrorsUsed) {m_maxMirrorsUsed = maxMirrorsUsed;} 87 88 /** 89 * Add a mirror that can be used for downloading 90 * @param url the url to the file 91 * @param used defines whether the mirror should initially be used for downloading or not, 92 * if true m_maxMirrorsUsed might be increased if needed 93 * @param numParallelConnections the number of simultaneous connections allowed to that mirror, 94 * minimum is 1 95 * @note when you add an already existing mirror only the numParallelConnections are adapted 96 * to the new value, so to change the number of parallel connections of a mirror you are already 97 * using simply call addMirror again 98 */ 99 void addMirror(const QUrl &url, bool used, int numParallelConnections = 1); 100 101 /** 102 * Add a mirror that can be used for downloading, if it will be used depends if maxMirrorsUsed 103 * has been reached yet 104 * @param url the url to the file 105 * @param numParallelConnections the number of simultaneous connections allowed to that mirror, 106 * minimum is 1 107 * @note when you add an already existing mirror only the numParallelConnections are adapted 108 * to the new value, so to change the number of parallel connections of a mirror you are already 109 * using simply call addMirror again 110 */ 111 void addMirror(const QUrl &url, int numParallelConnections = 1); 112 113 /** 114 * Does not use the specified mirror for downloading the file 115 * @note if the mirror has been used for downloading it will be moved to m_unusedMirrors, 116 * otherwise nohting will happen 117 * @param url the mirror that should not be used anymore 118 */ 119 void removeMirror(const QUrl &url); 120 121 /** 122 * Sets the mirrors that should be used/not used for downloading 123 * @param mirrors url of the mirror, if it should be used and its number of parallel connections 124 * (minimum is 1) 125 * @note if you want the download to work at least one entry should be set to true 126 */ 127 void setMirrors(const QHash<QUrl, QPair<bool, int> > &mirrors); 128 129 /** 130 * Return all mirrors, where bool defines if the mirror is used, 131 * while in defines the number of parallel connections for that mirror 132 */ 133 QHash<QUrl, QPair<bool, int> > mirrors() const; 134 135 /** 136 * Returns whether the datasourcefactory should download the file or not, 137 * true by default 138 * @note can be used for multiple datasourcefactory downloads 139 */ doDownload()140 bool doDownload() const {return m_doDownload;} 141 142 /** 143 * Set if the datasourcefactory should download the file or not, 144 * if set to false the download will be stopped if needed 145 * @note can be used for multiple datasourcefactory downloads 146 */ 147 void setDoDownload(bool doDownload); 148 149 bool setNewDestination(const QUrl &newDest); 150 status()151 Job::Status status() const {return m_status;} 152 153 /** 154 * @return true if the download was already initialized, i.e. a file has been 155 * created and maybe even written to 156 * @see deinit() 157 */ downloadInitialized()158 bool downloadInitialized() const {return m_downloadInitialized;} 159 160 /** 161 * Tries to repair a broken download, via completely redownloading it 162 * or only the borken parts 163 * @note call this if verification returned NotVerified 164 */ 165 void repair(); 166 167 Verifier *verifier(); 168 Signature *signature(); 169 170 Q_SIGNALS: 171 void capabilitiesChanged(); 172 void dataSourceFactoryChange(Transfer::ChangesFlags change); 173 void log(const QString &message, Transfer::LogLevel logLevel); 174 175 public Q_SLOTS: 176 void save(const QDomElement &element); 177 void load(const QDomElement *e); 178 179 private Q_SLOTS: 180 void slotUpdateCapabilities(); 181 182 void slotRemovedFile(); 183 184 /** 185 * Tries to find the size of the file, automatically called 186 * by start if no file size has been specified 187 */ 188 void findFileSize(); 189 190 void slotFoundFileSize(TransferDataSource *source, KIO::filesize_t fileSize, const QPair<int,int> &segmentRange); 191 192 void assignSegments(TransferDataSource *source); 193 /** 194 * Called when segments are broken 195 */ 196 void brokenSegments(TransferDataSource *source, const QPair<int, int> &segmentRange); 197 void finishedSegment(TransferDataSource *source, int segmentNumber, bool connectionFinished = true); 198 199 /** 200 * A TransferDataSource is broken 201 */ 202 void broken(TransferDataSource *source, TransferDataSource::Error error); 203 /** 204 * Emitted when a Datasource itself decides to not download a specific segmentRange, 205 * e.g. when there are too many connections for this TransferDataSource 206 */ 207 void slotFreeSegments(TransferDataSource *source, QPair<int, int> segmentRange); 208 void slotWriteData(KIO::fileoffset_t offset, const QByteArray &data, bool &worked); 209 void slotOffset(KIO::Job *job, KIO::filesize_t offset); 210 void slotDataWritten(KIO::Job *job, KIO::filesize_t offset); 211 void slotPercent(KJob *job, ulong percent); 212 void slotOpen(KIO::Job *job); 213 void speedChanged(); 214 /** 215 * Kills the putjob and starts the moving of files 216 */ 217 void startMove(); 218 void slotPutJobDestroyed(QObject *job); 219 void newDestResult(KJob *job); 220 221 void slotRepair(const QList<KIO::fileoffset_t> &offsets, KIO::filesize_t length); 222 223 void slotFinishedDownload(TransferDataSource *source, KIO::filesize_t size); 224 225 void slotUrlChanged(const QUrl &, const QUrl &); 226 227 private: 228 /** 229 * Add a mirror that can be used for downloading 230 * @param used always true if usedDefined is false 231 * @param usedDefined true if the user defined used, otherwise false, 232 * needed to know if m_maxMirrorsUsed should be changed or not 233 */ 234 void addMirror(const QUrl &url, bool used, int numParallelConnections, bool usedDefined); 235 236 /** 237 * Checks if an assign is needed, i.e. there are no (running) TransferDataSources, 238 * yet some segments are still not finished 239 */ 240 bool assignNeeded() const; 241 242 bool checkLocalFile(); 243 244 void init(); 245 void killPutJob(); 246 void changeStatus(Job::Status status); 247 248 private: 249 Transfer::Capabilities m_capabilities; 250 QUrl m_dest; 251 QUrl m_newDest; 252 KIO::filesize_t m_size; 253 KIO::filesize_t m_downloadedSize; 254 QList<KIO::filesize_t> m_prevDownloadedSizes; 255 KIO::fileoffset_t m_segSize; 256 ulong m_speed; 257 ulong m_percent; 258 259 /** 260 * the cache of data that could not be written yet 261 */ 262 QHash<KIO::fileoffset_t, QByteArray> m_cache; 263 264 KIO::filesize_t m_tempOffset; 265 QByteArray m_tempData; 266 267 BitSet *m_startedChunks; 268 BitSet *m_finishedChunks; 269 KIO::FileJob* m_putJob; 270 bool m_doDownload; 271 bool m_open; 272 /** 273 * the write access is currently blocked, the data gets cached in m_cache 274 */ 275 bool m_blocked; 276 /** 277 * If start() was called but did not work this is true, once the conditions changed 278 * start() could be recalled 279 */ 280 bool m_startTried; 281 bool m_findFilesizeTried; 282 283 bool m_assignTried; 284 bool m_movingFile; 285 286 bool m_finished; 287 288 /** 289 * True if download gets started the first time, if it gets never started there 290 * is no reason to remove any -- maybe preexisting -- file 291 */ 292 bool m_downloadInitialized; 293 294 /** 295 * Whether the file-size has been initially defined (it is to be trusted) or not 296 */ 297 bool m_sizeInitiallyDefined; 298 299 /** 300 * Downloadsize has only been found out once the download was finished 301 */ 302 bool m_sizeFoundOnFinish; 303 304 int m_maxMirrorsUsed; 305 QHash<QUrl, TransferDataSource*> m_sources; 306 QList<QUrl> m_unusedUrls; 307 QList<int> m_unusedConnections; 308 QTimer *m_speedTimer; 309 Job::Status m_status; 310 Job::Status m_statusBeforeMove; 311 312 Verifier *m_verifier; 313 Signature *m_signature; 314 }; 315 316 #endif 317