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