File indexing completed on 2024-12-01 07:38:38
0001 /* This file is part of the KDE project 0002 0003 Copyright (C) 2008 Lukas Appelhans <l.appelhans@gmx.de> 0004 Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net> 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 */ 0011 #ifndef DATASOURCEFACTORY_H 0012 #define DATASOURCEFACTORY_H 0013 0014 #include "kget_export.h" 0015 0016 #include "job.h" 0017 #include "transferdatasource.h" 0018 0019 #include <kio/job.h> 0020 0021 #include <QDomElement> 0022 0023 class BitSet; 0024 class TransferDataSource; 0025 class QTimer; 0026 class Signature; 0027 class Verifier; 0028 0029 namespace KIO 0030 { 0031 class FileJob; 0032 } 0033 0034 /** 0035 This class manages multiple DataSources and saves the received data to the file 0036 */ 0037 class KGET_EXPORT DataSourceFactory : public QObject 0038 { 0039 Q_OBJECT 0040 0041 public: 0042 /** 0043 * In general use this constructor, if the size is 0, the datasourcefactory will try to 0044 * find the filesize 0045 * @note when you want to load a datasourcefactory you do not have to specify the url and segSize 0046 */ 0047 explicit DataSourceFactory(QObject *parent, const QUrl &dest = QUrl(), KIO::filesize_t size = 0, KIO::fileoffset_t segSize = 512000); 0048 0049 ~DataSourceFactory() override; 0050 0051 /** 0052 * The capabilities the DataSourceFactory supports 0053 */ 0054 Transfer::Capabilities capabilities() const 0055 { 0056 return m_capabilities; 0057 } 0058 0059 /** 0060 * Deletes the created (downloadInitialized() is true) file if the download was not finished 0061 * Does not delete anything if the download never got started 0062 * @see downloadInitialized() 0063 */ 0064 void deinit(); 0065 0066 /** 0067 * @return true if the DataSourceFactory has enough information to start a download 0068 */ 0069 bool isValid() const; 0070 0071 void start(); 0072 void stop(); 0073 KIO::filesize_t size() const 0074 { 0075 return m_size; 0076 } 0077 KIO::filesize_t downloadedSize() const 0078 { 0079 return m_downloadedSize; 0080 } 0081 ulong currentSpeed() const 0082 { 0083 return m_speed; 0084 } 0085 ulong percent() const 0086 { 0087 return m_percent; 0088 } 0089 0090 QUrl dest() const 0091 { 0092 return m_dest; 0093 } 0094 0095 /** 0096 * The maximum number of mirrors that will be used for downloading, default is 3 0097 */ 0098 int maxMirrorsUsed() const 0099 { 0100 return m_maxMirrorsUsed; 0101 } 0102 0103 /** 0104 * Change the maximum number off mirrors that will be used for downloading, 0105 * if the download started already some mirrors might be added or removed automatically 0106 */ 0107 void setMaxMirrorsUsed(int maxMirrorsUsed) 0108 { 0109 m_maxMirrorsUsed = maxMirrorsUsed; 0110 } 0111 0112 /** 0113 * Add a mirror that can be used for downloading 0114 * @param url the url to the file 0115 * @param used defines whether the mirror should initially be used for downloading or not, 0116 * if true m_maxMirrorsUsed might be increased if needed 0117 * @param numParallelConnections the number of simultaneous connections allowed to that mirror, 0118 * minimum is 1 0119 * @note when you add an already existing mirror only the numParallelConnections are adapted 0120 * to the new value, so to change the number of parallel connections of a mirror you are already 0121 * using simply call addMirror again 0122 */ 0123 void addMirror(const QUrl &url, bool used, int numParallelConnections = 1); 0124 0125 /** 0126 * Add a mirror that can be used for downloading, if it will be used depends if maxMirrorsUsed 0127 * has been reached yet 0128 * @param url the url to the file 0129 * @param numParallelConnections the number of simultaneous connections allowed to that mirror, 0130 * minimum is 1 0131 * @note when you add an already existing mirror only the numParallelConnections are adapted 0132 * to the new value, so to change the number of parallel connections of a mirror you are already 0133 * using simply call addMirror again 0134 */ 0135 void addMirror(const QUrl &url, int numParallelConnections = 1); 0136 0137 /** 0138 * Does not use the specified mirror for downloading the file 0139 * @note if the mirror has been used for downloading it will be moved to m_unusedMirrors, 0140 * otherwise nohting will happen 0141 * @param url the mirror that should not be used anymore 0142 */ 0143 void removeMirror(const QUrl &url); 0144 0145 /** 0146 * Sets the mirrors that should be used/not used for downloading 0147 * @param mirrors url of the mirror, if it should be used and its number of parallel connections 0148 * (minimum is 1) 0149 * @note if you want the download to work at least one entry should be set to true 0150 */ 0151 void setMirrors(const QHash<QUrl, QPair<bool, int>> &mirrors); 0152 0153 /** 0154 * Return all mirrors, where bool defines if the mirror is used, 0155 * while in defines the number of parallel connections for that mirror 0156 */ 0157 QHash<QUrl, QPair<bool, int>> mirrors() const; 0158 0159 /** 0160 * Returns whether the datasourcefactory should download the file or not, 0161 * true by default 0162 * @note can be used for multiple datasourcefactory downloads 0163 */ 0164 bool doDownload() const 0165 { 0166 return m_doDownload; 0167 } 0168 0169 /** 0170 * Set if the datasourcefactory should download the file or not, 0171 * if set to false the download will be stopped if needed 0172 * @note can be used for multiple datasourcefactory downloads 0173 */ 0174 void setDoDownload(bool doDownload); 0175 0176 bool setNewDestination(const QUrl &newDest); 0177 0178 Job::Status status() const 0179 { 0180 return m_status; 0181 } 0182 0183 /** 0184 * @return true if the download was already initialized, i.e. a file has been 0185 * created and maybe even written to 0186 * @see deinit() 0187 */ 0188 bool downloadInitialized() const 0189 { 0190 return m_downloadInitialized; 0191 } 0192 0193 /** 0194 * Tries to repair a broken download, via completely redownloading it 0195 * or only the borken parts 0196 * @note call this if verification returned NotVerified 0197 */ 0198 void repair(); 0199 0200 Verifier *verifier(); 0201 Signature *signature(); 0202 0203 Q_SIGNALS: 0204 void capabilitiesChanged(); 0205 void dataSourceFactoryChange(Transfer::ChangesFlags change); 0206 void log(const QString &message, Transfer::LogLevel logLevel); 0207 0208 public Q_SLOTS: 0209 void save(const QDomElement &element); 0210 void load(const QDomElement *e); 0211 0212 private Q_SLOTS: 0213 void slotUpdateCapabilities(); 0214 0215 void slotRemovedFile(); 0216 0217 /** 0218 * Tries to find the size of the file, automatically called 0219 * by start if no file size has been specified 0220 */ 0221 void findFileSize(); 0222 0223 void slotFoundFileSize(TransferDataSource *source, KIO::filesize_t fileSize, const QPair<int, int> &segmentRange); 0224 0225 void assignSegments(TransferDataSource *source); 0226 /** 0227 * Called when segments are broken 0228 */ 0229 void brokenSegments(TransferDataSource *source, const QPair<int, int> &segmentRange); 0230 void finishedSegment(TransferDataSource *source, int segmentNumber, bool connectionFinished = true); 0231 0232 /** 0233 * A TransferDataSource is broken 0234 */ 0235 void broken(TransferDataSource *source, TransferDataSource::Error error); 0236 /** 0237 * Emitted when a Datasource itself decides to not download a specific segmentRange, 0238 * e.g. when there are too many connections for this TransferDataSource 0239 */ 0240 void slotFreeSegments(TransferDataSource *source, QPair<int, int> segmentRange); 0241 void slotWriteData(KIO::fileoffset_t offset, const QByteArray &data, bool &worked); 0242 void slotOffset(KIO::Job *job, KIO::filesize_t offset); 0243 void slotDataWritten(KIO::Job *job, KIO::filesize_t offset); 0244 void slotPercent(KJob *job, ulong percent); 0245 void slotOpen(KIO::Job *job); 0246 void speedChanged(); 0247 /** 0248 * Kills the putjob and starts the moving of files 0249 */ 0250 void startMove(); 0251 void slotPutJobDestroyed(QObject *job); 0252 void newDestResult(KJob *job); 0253 0254 void slotRepair(const QList<KIO::fileoffset_t> &offsets, KIO::filesize_t length); 0255 0256 void slotFinishedDownload(TransferDataSource *source, KIO::filesize_t size); 0257 0258 void slotUrlChanged(const QUrl &, const QUrl &); 0259 0260 private: 0261 /** 0262 * Add a mirror that can be used for downloading 0263 * @param used always true if usedDefined is false 0264 * @param usedDefined true if the user defined used, otherwise false, 0265 * needed to know if m_maxMirrorsUsed should be changed or not 0266 */ 0267 void addMirror(const QUrl &url, bool used, int numParallelConnections, bool usedDefined); 0268 0269 /** 0270 * Checks if an assign is needed, i.e. there are no (running) TransferDataSources, 0271 * yet some segments are still not finished 0272 */ 0273 bool assignNeeded() const; 0274 0275 bool checkLocalFile(); 0276 0277 void init(); 0278 void killPutJob(); 0279 void changeStatus(Job::Status status); 0280 0281 private: 0282 Transfer::Capabilities m_capabilities; 0283 QUrl m_dest; 0284 QUrl m_newDest; 0285 KIO::filesize_t m_size; 0286 KIO::filesize_t m_downloadedSize; 0287 QList<KIO::filesize_t> m_prevDownloadedSizes; 0288 KIO::fileoffset_t m_segSize; 0289 ulong m_speed; 0290 ulong m_percent; 0291 0292 /** 0293 * the cache of data that could not be written yet 0294 */ 0295 QHash<KIO::fileoffset_t, QByteArray> m_cache; 0296 0297 KIO::filesize_t m_tempOffset; 0298 QByteArray m_tempData; 0299 0300 BitSet *m_startedChunks; 0301 BitSet *m_finishedChunks; 0302 KIO::FileJob *m_putJob; 0303 bool m_doDownload; 0304 bool m_open; 0305 /** 0306 * the write access is currently blocked, the data gets cached in m_cache 0307 */ 0308 bool m_blocked; 0309 /** 0310 * If start() was called but did not work this is true, once the conditions changed 0311 * start() could be recalled 0312 */ 0313 bool m_startTried; 0314 bool m_findFilesizeTried; 0315 0316 bool m_assignTried; 0317 bool m_movingFile; 0318 0319 bool m_finished; 0320 0321 /** 0322 * True if download gets started the first time, if it gets never started there 0323 * is no reason to remove any -- maybe preexisting -- file 0324 */ 0325 bool m_downloadInitialized; 0326 0327 /** 0328 * Whether the file-size has been initially defined (it is to be trusted) or not 0329 */ 0330 bool m_sizeInitiallyDefined; 0331 0332 /** 0333 * Downloadsize has only been found out once the download was finished 0334 */ 0335 bool m_sizeFoundOnFinish; 0336 0337 int m_maxMirrorsUsed; 0338 QHash<QUrl, TransferDataSource *> m_sources; 0339 QList<QUrl> m_unusedUrls; 0340 QList<int> m_unusedConnections; 0341 QTimer *m_speedTimer; 0342 Job::Status m_status; 0343 Job::Status m_statusBeforeMove; 0344 0345 Verifier *m_verifier; 0346 Signature *m_signature; 0347 }; 0348 0349 #endif