2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04:00
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2015-10-03 16:16:42 +03:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 22:31:31 +04:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
2017-03-04 13:23:56 +03:00
# include "storage/file_download.h"
2016-03-23 21:43:12 +03:00
2014-05-30 12:53:19 +04:00
# include "mainwidget.h"
2016-04-13 00:31:28 +03:00
# include "mainwindow.h"
2017-02-23 13:59:19 +03:00
# include "messenger.h"
2017-03-04 13:23:56 +03:00
# include "storage/localstorage.h"
2017-02-28 17:05:30 +03:00
# include "platform/platform_file_utilities.h"
2017-03-04 22:36:59 +03:00
# include "auth_session.h"
namespace Storage {
void Downloader : : clearPriorities ( ) {
+ + _priority ;
}
} // namespace Storage
2014-10-30 19:23:44 +03:00
2014-05-30 12:53:19 +04:00
namespace {
2017-02-27 21:33:42 +03:00
struct DataRequested {
DataRequested ( ) {
memset ( v , 0 , sizeof ( v ) ) ;
}
int64 v [ MTPDownloadSessionsCount ] ;
} ;
QMap < int32 , DataRequested > DataRequestedMap ;
2017-03-05 20:33:32 +03:00
constexpr auto kDownloadPhotoPartSize = 64 * 1024 ; // 64kb for photo
constexpr auto kDownloadDocumentPartSize = 128 * 1024 ; // 128kb for document
2017-03-04 22:36:59 +03:00
} // namespace
2015-12-31 03:09:20 +08:00
struct FileLoaderQueue {
2017-03-04 22:36:59 +03:00
FileLoaderQueue ( int32 limit ) : limit ( limit ) {
2014-05-30 12:53:19 +04:00
}
2017-03-04 22:36:59 +03:00
int queries = 0 ;
int limit = 0 ;
FileLoader * start = nullptr ;
FileLoader * end = nullptr ;
2014-05-30 12:53:19 +04:00
} ;
namespace {
2015-12-31 03:09:20 +08:00
typedef QMap < int32 , FileLoaderQueue > LoaderQueues ;
2014-05-30 12:53:19 +04:00
LoaderQueues queues ;
2015-12-31 03:09:20 +08:00
FileLoaderQueue _webQueue ( MaxWebFileQueries ) ;
QThread * _webLoadThread = 0 ;
WebLoadManager * _webLoadManager = 0 ;
WebLoadManager * webLoadManager ( ) {
return ( _webLoadManager & & _webLoadManager ! = FinishedWebLoadManager ) ? _webLoadManager : 0 ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
WebLoadMainManager * _webLoadMainManager = 0 ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 13:34:43 +08:00
FileLoader : : FileLoader ( const QString & toFile , int32 size , LocationType locationType , LoadToCacheSetting toCache , LoadFromCloudSetting fromCloud , bool autoLoading )
2017-03-15 19:24:06 +03:00
: _downloader ( & AuthSession : : Current ( ) . downloader ( ) )
2017-03-04 22:36:59 +03:00
, _autoLoading ( autoLoading )
2015-12-31 23:28:54 +08:00
, _file ( toFile )
, _fname ( toFile )
2015-12-31 13:34:43 +08:00
, _toCache ( toCache )
2015-12-24 22:26:28 +03:00
, _fromCloud ( fromCloud )
, _size ( size )
2016-10-12 22:34:25 +03:00
, _locationType ( locationType ) {
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
QByteArray FileLoader : : imageFormat ( const QSize & shrinkBox ) const {
2015-09-29 21:44:31 +03:00
if ( _imageFormat . isEmpty ( ) & & _locationType = = UnknownFileLocation ) {
2016-04-10 18:53:01 +04:00
readImage ( shrinkBox ) ;
2015-09-29 21:44:31 +03:00
}
return _imageFormat ;
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
QPixmap FileLoader : : imagePixmap ( const QSize & shrinkBox ) const {
2015-09-29 21:44:31 +03:00
if ( _imagePixmap . isNull ( ) & & _locationType = = UnknownFileLocation ) {
2016-04-10 18:53:01 +04:00
readImage ( shrinkBox ) ;
2015-09-29 21:44:31 +03:00
}
return _imagePixmap ;
2014-05-30 12:53:19 +04:00
}
2016-04-10 18:53:01 +04:00
void FileLoader : : readImage ( const QSize & shrinkBox ) const {
2017-03-04 14:28:21 +03:00
auto format = QByteArray ( ) ;
auto image = App : : readImage ( _data , & format , false ) ;
2016-04-10 18:53:01 +04:00
if ( ! image . isNull ( ) ) {
if ( ! shrinkBox . isEmpty ( ) & & ( image . width ( ) > shrinkBox . width ( ) | | image . height ( ) > shrinkBox . height ( ) ) ) {
2016-07-13 20:34:57 +03:00
_imagePixmap = App : : pixmapFromImageInPlace ( image . scaled ( shrinkBox , Qt : : KeepAspectRatio , Qt : : SmoothTransformation ) ) ;
} else {
2017-02-21 16:45:56 +03:00
_imagePixmap = App : : pixmapFromImageInPlace ( std : : move ( image ) ) ;
2016-04-10 18:53:01 +04:00
}
2015-09-29 21:44:31 +03:00
_imageFormat = format ;
}
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
float64 FileLoader : : currentProgress ( ) const {
2017-03-04 14:28:21 +03:00
if ( _finished ) return 1. ;
2016-10-13 12:12:12 +03:00
if ( ! fullSize ( ) ) return 0. ;
return snap ( float64 ( currentOffset ( ) ) / fullSize ( ) , 0. , 1. ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
int32 FileLoader : : fullSize ( ) const {
2015-12-24 22:26:28 +03:00
return _size ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
bool FileLoader : : setFileName ( const QString & fileName ) {
2016-10-12 22:34:25 +03:00
if ( _toCache ! = LoadToCacheAsWell | | ! _fname . isEmpty ( ) ) {
return fileName . isEmpty ( ) | | ( fileName = = _fname ) ;
}
2015-12-24 22:26:28 +03:00
_fname = fileName ;
_file . setFileName ( _fname ) ;
return true ;
}
2015-12-31 03:09:20 +08:00
void FileLoader : : permitLoadFromCloud ( ) {
2015-12-24 22:26:28 +03:00
_fromCloud = LoadFromCloudOrLocal ;
2014-09-04 11:33:44 +04:00
}
2015-12-31 03:09:20 +08:00
void FileLoader : : loadNext ( ) {
if ( _queue - > queries > = _queue - > limit ) return ;
for ( FileLoader * i = _queue - > start ; i ; ) {
if ( i - > loadPart ( ) ) {
if ( _queue - > queries > = _queue - > limit ) return ;
} else {
i = i - > _next ;
}
}
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
void FileLoader : : removeFromQueue ( ) {
if ( ! _inQueue ) return ;
if ( _next ) {
_next - > _prev = _prev ;
}
if ( _prev ) {
_prev - > _next = _next ;
}
if ( _queue - > end = = this ) {
_queue - > end = _prev ;
}
if ( _queue - > start = = this ) {
_queue - > start = _next ;
}
_next = _prev = 0 ;
_inQueue = false ;
}
void FileLoader : : pause ( ) {
removeFromQueue ( ) ;
_paused = true ;
}
FileLoader : : ~ FileLoader ( ) {
if ( _localTaskId ) {
Local : : cancelTask ( _localTaskId ) ;
}
removeFromQueue ( ) ;
}
void FileLoader : : localLoaded ( const StorageImageSaved & result , const QByteArray & imageFormat , const QPixmap & imagePixmap ) {
_localTaskId = 0 ;
2017-03-04 14:28:21 +03:00
if ( result . data . isEmpty ( ) ) {
2015-12-31 03:09:20 +08:00
_localStatus = LocalFailed ;
start ( true ) ;
return ;
}
_data = result . data ;
if ( ! imagePixmap . isNull ( ) ) {
_imageFormat = imageFormat ;
_imagePixmap = imagePixmap ;
}
_localStatus = LocalLoaded ;
if ( ! _fname . isEmpty ( ) & & _toCache = = LoadToCacheAsWell ) {
if ( ! _fileIsOpen ) _fileIsOpen = _file . open ( QIODevice : : WriteOnly ) ;
if ( ! _fileIsOpen ) {
cancel ( true ) ;
return ;
}
if ( _file . write ( _data ) ! = qint64 ( _data . size ( ) ) ) {
cancel ( true ) ;
return ;
}
}
2017-03-04 14:28:21 +03:00
_finished = true ;
2015-12-31 03:09:20 +08:00
if ( _fileIsOpen ) {
_file . close ( ) ;
_fileIsOpen = false ;
2017-02-28 17:05:30 +03:00
Platform : : File : : PostprocessDownloaded ( QFileInfo ( _file ) . absoluteFilePath ( ) ) ;
2015-12-31 03:09:20 +08:00
}
2017-03-04 22:36:59 +03:00
_downloader - > taskFinished ( ) . notify ( ) ;
2017-02-27 21:33:42 +03:00
emit progress ( this ) ;
2015-12-31 03:09:20 +08:00
loadNext ( ) ;
}
void FileLoader : : start ( bool loadFirst , bool prior ) {
if ( _paused ) {
_paused = false ;
}
2017-03-04 14:28:21 +03:00
if ( _finished | | tryLoadLocal ( ) ) return ;
2015-12-31 03:09:20 +08:00
if ( _fromCloud = = LoadFromLocalOnly ) {
cancel ( ) ;
return ;
}
if ( ! _fname . isEmpty ( ) & & _toCache = = LoadToFileOnly & & ! _fileIsOpen ) {
_fileIsOpen = _file . open ( QIODevice : : WriteOnly ) ;
if ( ! _fileIsOpen ) {
return cancel ( true ) ;
}
}
2017-03-04 22:36:59 +03:00
auto currentPriority = _downloader - > currentPriority ( ) ;
2015-12-31 03:09:20 +08:00
FileLoader * before = 0 , * after = 0 ;
if ( prior ) {
2017-03-04 22:36:59 +03:00
if ( _inQueue & & _priority = = currentPriority ) {
2015-12-31 03:09:20 +08:00
if ( loadFirst ) {
if ( ! _prev ) return startLoading ( loadFirst , prior ) ;
before = _queue - > start ;
} else {
2017-03-04 22:36:59 +03:00
if ( ! _next | | _next - > _priority < currentPriority ) return startLoading ( loadFirst , prior ) ;
2015-12-31 03:09:20 +08:00
after = _next ;
2017-03-04 22:36:59 +03:00
while ( after - > _next & & after - > _next - > _priority = = currentPriority ) {
2015-12-31 03:09:20 +08:00
after = after - > _next ;
}
}
2014-10-30 19:23:44 +03:00
} else {
2017-03-04 22:36:59 +03:00
_priority = currentPriority ;
2015-12-31 03:09:20 +08:00
if ( loadFirst ) {
if ( _inQueue & & ! _prev ) return startLoading ( loadFirst , prior ) ;
before = _queue - > start ;
} else {
if ( _inQueue ) {
2017-03-04 22:36:59 +03:00
if ( _next & & _next - > _priority = = currentPriority ) {
2015-12-31 03:09:20 +08:00
after = _next ;
2017-03-04 22:36:59 +03:00
} else if ( _prev & & _prev - > _priority < currentPriority ) {
2015-12-31 03:09:20 +08:00
before = _prev ;
2017-03-04 22:36:59 +03:00
while ( before - > _prev & & before - > _prev - > _priority < currentPriority ) {
2015-12-31 03:09:20 +08:00
before = before - > _prev ;
}
} else {
return startLoading ( loadFirst , prior ) ;
}
} else {
2017-03-04 22:36:59 +03:00
if ( _queue - > start & & _queue - > start - > _priority = = currentPriority ) {
2015-12-31 03:09:20 +08:00
after = _queue - > start ;
} else {
before = _queue - > start ;
}
}
if ( after ) {
2017-03-04 22:36:59 +03:00
while ( after - > _next & & after - > _next - > _priority = = currentPriority ) {
2015-12-31 03:09:20 +08:00
after = after - > _next ;
}
}
}
}
} else {
if ( loadFirst ) {
2017-03-04 22:36:59 +03:00
if ( _inQueue & & ( ! _prev | | _prev - > _priority = = currentPriority ) ) return startLoading ( loadFirst , prior ) ;
2015-12-31 03:09:20 +08:00
before = _prev ;
2017-03-04 22:36:59 +03:00
while ( before - > _prev & & before - > _prev - > _priority ! = currentPriority ) {
2015-12-31 03:09:20 +08:00
before = before - > _prev ;
}
} else {
if ( _inQueue & & ! _next ) return startLoading ( loadFirst , prior ) ;
after = _queue - > end ;
}
}
removeFromQueue ( ) ;
_inQueue = true ;
if ( ! _queue - > start ) {
_queue - > start = _queue - > end = this ;
} else if ( before ) {
if ( before ! = _next ) {
_prev = before - > _prev ;
_next = before ;
_next - > _prev = this ;
if ( _prev ) {
_prev - > _next = this ;
}
if ( _queue - > start - > _prev ) _queue - > start = _queue - > start - > _prev ;
}
} else if ( after ) {
if ( after ! = _prev ) {
_next = after - > _next ;
_prev = after ;
after - > _next = this ;
if ( _next ) {
_next - > _prev = this ;
}
if ( _queue - > end - > _next ) _queue - > end = _queue - > end - > _next ;
2014-10-30 19:23:44 +03:00
}
2015-12-31 03:09:20 +08:00
} else {
LOG ( ( " Queue Error: _start && !before && !after " ) ) ;
}
return startLoading ( loadFirst , prior ) ;
}
void FileLoader : : cancel ( ) {
cancel ( false ) ;
}
void FileLoader : : cancel ( bool fail ) {
bool started = currentOffset ( true ) > 0 ;
cancelRequests ( ) ;
2017-03-04 14:28:21 +03:00
_cancelled = true ;
_finished = true ;
2015-12-31 03:09:20 +08:00
if ( _fileIsOpen ) {
_file . close ( ) ;
_fileIsOpen = false ;
_file . remove ( ) ;
}
_data = QByteArray ( ) ;
2017-02-27 21:33:42 +03:00
_fname = QString ( ) ;
_file . setFileName ( _fname ) ;
2015-12-31 03:09:20 +08:00
if ( fail ) {
emit failed ( this , started ) ;
} else {
emit progress ( this ) ;
}
2017-02-27 21:33:42 +03:00
2015-12-31 03:09:20 +08:00
loadNext ( ) ;
}
void FileLoader : : startLoading ( bool loadFirst , bool prior ) {
2017-03-04 14:28:21 +03:00
if ( ( _queue - > queries > = _queue - > limit & & ( ! loadFirst | | ! prior ) ) | | _finished ) return ;
2015-12-31 03:09:20 +08:00
loadPart ( ) ;
}
mtpFileLoader : : mtpFileLoader ( const StorageImageLocation * location , int32 size , LoadFromCloudSetting fromCloud , bool autoLoading )
2015-12-31 13:34:43 +08:00
: FileLoader ( QString ( ) , size , UnknownFileLocation , LoadToCacheAsWell , fromCloud , autoLoading )
2015-12-31 03:09:20 +08:00
, _dc ( location - > dc ( ) )
2016-07-08 16:56:53 +03:00
, _location ( location ) {
2017-02-25 19:44:02 +03:00
auto shiftedDcId = MTP : : downloadDcId ( _dc , 0 ) ;
auto i = queues . find ( shiftedDcId ) ;
2015-12-31 03:09:20 +08:00
if ( i = = queues . cend ( ) ) {
2017-02-25 19:44:02 +03:00
i = queues . insert ( shiftedDcId , FileLoaderQueue ( MaxFileQueries ) ) ;
2015-12-31 03:09:20 +08:00
}
_queue = & i . value ( ) ;
}
2017-03-05 20:33:32 +03:00
mtpFileLoader : : mtpFileLoader ( int32 dc , uint64 id , uint64 accessHash , int32 version , LocationType type , const QString & to , int32 size , LoadToCacheSetting toCache , LoadFromCloudSetting fromCloud , bool autoLoading )
2015-12-31 13:34:43 +08:00
: FileLoader ( to , size , type , toCache , fromCloud , autoLoading )
2015-12-31 03:09:20 +08:00
, _dc ( dc )
, _id ( id )
2017-03-05 20:33:32 +03:00
, _accessHash ( accessHash )
2016-07-08 16:56:53 +03:00
, _version ( version ) {
2017-02-25 19:44:02 +03:00
auto shiftedDcId = MTP : : downloadDcId ( _dc , 0 ) ;
auto i = queues . find ( shiftedDcId ) ;
2015-12-31 03:09:20 +08:00
if ( i = = queues . cend ( ) ) {
2017-02-25 19:44:02 +03:00
i = queues . insert ( shiftedDcId , FileLoaderQueue ( MaxFileQueries ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
_queue = & i . value ( ) ;
}
2017-03-05 20:33:32 +03:00
mtpFileLoader : : mtpFileLoader ( const WebFileImageLocation * location , int32 size , LoadFromCloudSetting fromCloud , bool autoLoading )
: FileLoader ( QString ( ) , size , UnknownFileLocation , LoadToCacheAsWell , fromCloud , autoLoading )
, _dc ( location - > dc ( ) )
, _urlLocation ( location ) {
auto shiftedDcId = MTP : : downloadDcId ( _dc , 0 ) ;
auto i = queues . find ( shiftedDcId ) ;
if ( i = = queues . cend ( ) ) {
i = queues . insert ( shiftedDcId , FileLoaderQueue ( MaxFileQueries ) ) ;
}
_queue = & i . value ( ) ;
}
2015-12-31 03:09:20 +08:00
int32 mtpFileLoader : : currentOffset ( bool includeSkipped ) const {
return ( _fileIsOpen ? _file . size ( ) : _data . size ( ) ) - ( includeSkipped ? 0 : _skippedBytes ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-17 21:03:08 +03:00
namespace {
QString serializereqs ( const QMap < mtpRequestId , int32 > & reqs ) { // serialize requests map in json-like format
QString result ;
result . reserve ( reqs . size ( ) * 16 + 4 ) ;
result . append ( qsl ( " { " ) ) ;
for ( auto i = reqs . cbegin ( ) , e = reqs . cend ( ) ; i ! = e ; ) {
result . append ( QString : : number ( i . key ( ) ) ) . append ( qsl ( " : " ) ) . append ( QString : : number ( i . value ( ) ) ) ;
if ( + + i = = e ) {
break ;
} else {
result . append ( qsl ( " , " ) ) ;
}
}
result . append ( qsl ( " } " ) ) ;
return result ;
}
}
2014-05-30 12:53:19 +04:00
bool mtpFileLoader : : loadPart ( ) {
2017-03-05 20:33:32 +03:00
if ( _finished | | _lastComplete | | ( ! _dcIndexByRequest . isEmpty ( ) & & ! _size ) ) {
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
2017-03-05 20:33:32 +03:00
DEBUG_LOG ( ( " FileLoader(%1): loadPart() returned, _finished=%2, _lastComplete=%3, _requests.size()=%4, _size=%5 " ) . arg ( _id ) . arg ( Logs : : b ( _finished ) ) . arg ( Logs : : b ( _lastComplete ) ) . arg ( _dcIndexByRequest . size ( ) ) . arg ( _size ) ) ;
2017-02-27 21:33:42 +03:00
}
2016-03-17 21:03:08 +03:00
return false ;
}
if ( _size & & _nextRequestOffset > = _size ) {
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
2017-03-05 20:33:32 +03:00
DEBUG_LOG ( ( " FileLoader(%1): loadPart() returned, _size=%2, _nextRequestOffset=%3, _requests=%4 " ) . arg ( _id ) . arg ( _size ) . arg ( _nextRequestOffset ) . arg ( serializereqs ( _dcIndexByRequest ) ) ) ;
2017-02-27 21:33:42 +03:00
}
2016-03-17 21:03:08 +03:00
return false ;
}
2014-05-30 12:53:19 +04:00
2017-03-05 20:33:32 +03:00
auto offset = _nextRequestOffset ;
auto dcIndex = 0 ;
auto & dr = DataRequestedMap [ _dc ] ;
2015-12-24 22:26:28 +03:00
if ( _size ) {
2017-03-05 20:33:32 +03:00
for ( auto i = 1 ; i ! = MTPDownloadSessionsCount ; + + i ) {
2014-10-30 19:23:44 +03:00
if ( dr . v [ i ] < dr . v [ dcIndex ] ) {
dcIndex = i ;
}
}
}
2015-12-24 22:26:28 +03:00
App : : app ( ) - > killDownloadSessionsStop ( _dc ) ;
2014-10-30 19:23:44 +03:00
2017-03-05 20:33:32 +03:00
auto requestId = makeRequest ( offset , dcIndex ) ;
_dcIndexByRequest . insert ( requestId , dcIndex ) ;
2014-10-30 19:23:44 +03:00
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
2017-03-05 20:33:32 +03:00
DEBUG_LOG ( ( " FileLoader(%1): requested part with offset=%2, _queue->queries=%3, _nextRequestOffset=%4, _requests=%5 " ) . arg ( _id ) . arg ( offset ) . arg ( _queue - > queries ) . arg ( _nextRequestOffset ) . arg ( serializereqs ( _dcIndexByRequest ) ) ) ;
2017-02-27 21:33:42 +03:00
}
2016-03-17 21:03:08 +03:00
2014-05-30 12:53:19 +04:00
return true ;
}
2017-03-05 20:33:32 +03:00
int mtpFileLoader : : partSize ( ) const {
if ( _locationType = = UnknownFileLocation ) {
return kDownloadPhotoPartSize ;
}
return kDownloadDocumentPartSize ;
}
mtpRequestId mtpFileLoader : : makeRequest ( int offset , int dcIndex ) {
auto limit = partSize ( ) ;
DataRequestedMap [ _dc ] . v [ dcIndex ] + = limit ;
+ + _queue - > queries ;
_nextRequestOffset + = limit ;
if ( _urlLocation ) {
return MTP : : send ( MTPupload_GetWebFile ( MTP_inputWebFileLocation ( MTP_bytes ( _urlLocation - > url ( ) ) , MTP_long ( _urlLocation - > accessHash ( ) ) ) , MTP_int ( offset ) , MTP_int ( limit ) ) , rpcDone ( & mtpFileLoader : : webPartLoaded , offset ) , rpcFail ( & mtpFileLoader : : partFailed ) , MTP : : downloadDcId ( _dc , dcIndex ) , 50 ) ;
}
MTPInputFileLocation loc ;
if ( _location ) {
loc = MTP_inputFileLocation ( MTP_long ( _location - > volume ( ) ) , MTP_int ( _location - > local ( ) ) , MTP_long ( _location - > secret ( ) ) ) ;
} else {
loc = MTP_inputDocumentFileLocation ( MTP_long ( _id ) , MTP_long ( _accessHash ) , MTP_int ( _version ) ) ;
}
return MTP : : send ( MTPupload_GetFile ( loc , MTP_int ( offset ) , MTP_int ( limit ) ) , rpcDone ( & mtpFileLoader : : normalPartLoaded , offset ) , rpcFail ( & mtpFileLoader : : partFailed ) , MTP : : downloadDcId ( _dc , dcIndex ) , 50 ) ;
}
void mtpFileLoader : : normalPartLoaded ( int offset , const MTPupload_File & result , mtpRequestId req ) {
if ( result . type ( ) ! = mtpc_upload_file ) {
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
2017-03-05 20:33:32 +03:00
DEBUG_LOG ( ( " FileLoader(%1): bad cons received! %2 " ) . arg ( _id ) . arg ( result . type ( ) ) ) ;
2017-02-27 21:33:42 +03:00
}
2017-03-05 20:33:32 +03:00
return cancel ( true ) ;
2016-03-17 21:03:08 +03:00
}
2017-03-05 20:33:32 +03:00
auto bytes = gsl : : as_bytes ( gsl : : make_span ( result . c_upload_file ( ) . vbytes . v ) ) ;
return partLoaded ( offset , bytes , req ) ;
}
void mtpFileLoader : : webPartLoaded ( int offset , const MTPupload_WebFile & result , mtpRequestId req ) {
if ( result . type ( ) ! = mtpc_upload_webFile ) {
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
DEBUG_LOG ( ( " FileLoader(%1): bad cons received! %2 " ) . arg ( _id ) . arg ( result . type ( ) ) ) ;
}
2016-03-17 21:03:08 +03:00
return cancel ( true ) ;
}
2017-03-05 20:33:32 +03:00
auto & webFile = result . c_upload_webFile ( ) ;
2017-03-06 11:08:59 +03:00
if ( ! _size ) {
_size = webFile . vsize . v ;
} else if ( webFile . vsize . v ! = _size ) {
2017-03-05 20:33:32 +03:00
LOG ( ( " MTP Error: Bad size provided by bot for webDocument: %1, real: %2 " ) . arg ( _size ) . arg ( webFile . vsize . v ) ) ;
return cancel ( true ) ;
}
auto bytes = gsl : : as_bytes ( gsl : : make_span ( webFile . vbytes . v ) ) ;
return partLoaded ( offset , bytes , req ) ;
}
2014-10-30 19:23:44 +03:00
2017-03-05 20:33:32 +03:00
void mtpFileLoader : : partLoaded ( int offset , base : : const_byte_span bytes , mtpRequestId req ) {
auto i = _dcIndexByRequest . find ( req ) ;
if ( i = = _dcIndexByRequest . cend ( ) ) {
if ( DebugLogging : : FileLoader ( ) & & _id ) {
DEBUG_LOG ( ( " FileLoader(%1): request req=%2 for offset=%3 not found in _requests=%4 " ) . arg ( _id ) . arg ( req ) . arg ( offset ) . arg ( serializereqs ( _dcIndexByRequest ) ) ) ;
}
return loadNext ( ) ;
}
auto limit = partSize ( ) ;
auto dcIndex = i . value ( ) ;
2015-12-24 22:26:28 +03:00
DataRequestedMap [ _dc ] . v [ dcIndex ] - = limit ;
2014-10-30 19:23:44 +03:00
2015-12-31 03:09:20 +08:00
- - _queue - > queries ;
2017-03-05 20:33:32 +03:00
_dcIndexByRequest . erase ( i ) ;
2016-03-17 21:03:08 +03:00
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
2017-03-05 20:33:32 +03:00
DEBUG_LOG ( ( " FileLoader(%1): got part with offset=%2, bytes=%3, _queue->queries=%4, _nextRequestOffset=%5, _requests=%6 " ) . arg ( _id ) . arg ( offset ) . arg ( bytes . size ( ) ) . arg ( _queue - > queries ) . arg ( _nextRequestOffset ) . arg ( serializereqs ( _dcIndexByRequest ) ) ) ;
2017-02-27 21:33:42 +03:00
}
2016-03-17 21:03:08 +03:00
2014-10-30 19:23:44 +03:00
if ( bytes . size ( ) ) {
2015-12-24 22:26:28 +03:00
if ( _fileIsOpen ) {
int64 fsize = _file . size ( ) ;
2014-10-30 19:23:44 +03:00
if ( offset < fsize ) {
2015-12-24 22:26:28 +03:00
_skippedBytes - = bytes . size ( ) ;
2014-10-30 19:23:44 +03:00
} else if ( offset > fsize ) {
2015-12-24 22:26:28 +03:00
_skippedBytes + = offset - fsize ;
2014-10-30 19:23:44 +03:00
}
2015-12-24 22:26:28 +03:00
_file . seek ( offset ) ;
2017-03-05 20:33:32 +03:00
if ( _file . write ( reinterpret_cast < const char * > ( bytes . data ( ) ) , bytes . size ( ) ) ! = qint64 ( bytes . size ( ) ) ) {
2015-12-24 22:26:28 +03:00
return cancel ( true ) ;
2014-05-30 12:53:19 +04:00
}
} else {
2015-12-24 22:26:28 +03:00
_data . reserve ( offset + bytes . size ( ) ) ;
if ( offset > _data . size ( ) ) {
_skippedBytes + = offset - _data . size ( ) ;
_data . resize ( offset ) ;
2014-10-30 19:23:44 +03:00
}
2015-12-24 22:26:28 +03:00
if ( offset = = _data . size ( ) ) {
2017-03-05 20:33:32 +03:00
_data . append ( reinterpret_cast < const char * > ( bytes . data ( ) ) , bytes . size ( ) ) ;
2014-10-30 19:23:44 +03:00
} else {
2015-12-24 22:26:28 +03:00
_skippedBytes - = bytes . size ( ) ;
if ( int64 ( offset + bytes . size ( ) ) > _data . size ( ) ) {
_data . resize ( offset + bytes . size ( ) ) ;
2014-09-04 11:33:44 +04:00
}
2017-03-05 20:33:32 +03:00
auto src = bytes ;
auto dst = gsl : : make_span ( _data ) . subspan ( offset , bytes . size ( ) ) ;
base : : copy_bytes ( gsl : : as_writeable_bytes ( dst ) , src ) ;
2014-09-04 11:33:44 +04:00
}
2014-10-30 19:23:44 +03:00
}
}
if ( ! bytes . size ( ) | | ( bytes . size ( ) % 1024 ) ) { // bad next offset
2015-12-24 22:26:28 +03:00
_lastComplete = true ;
2014-10-30 19:23:44 +03:00
}
2017-03-05 20:33:32 +03:00
if ( _dcIndexByRequest . isEmpty ( ) & & ( _lastComplete | | ( _size & & _nextRequestOffset > = _size ) ) ) {
2015-12-24 22:26:28 +03:00
if ( ! _fname . isEmpty ( ) & & ( _toCache = = LoadToCacheAsWell ) ) {
if ( ! _fileIsOpen ) _fileIsOpen = _file . open ( QIODevice : : WriteOnly ) ;
if ( ! _fileIsOpen ) {
return cancel ( true ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-24 22:26:28 +03:00
if ( _file . write ( _data ) ! = qint64 ( _data . size ( ) ) ) {
return cancel ( true ) ;
2014-10-30 19:23:44 +03:00
}
}
2017-03-04 14:28:21 +03:00
_finished = true ;
2015-12-24 22:26:28 +03:00
if ( _fileIsOpen ) {
_file . close ( ) ;
_fileIsOpen = false ;
2017-02-28 17:05:30 +03:00
Platform : : File : : PostprocessDownloaded ( QFileInfo ( _file ) . absoluteFilePath ( ) ) ;
2014-10-30 19:23:44 +03:00
}
removeFromQueue ( ) ;
2015-05-19 18:46:45 +03:00
2015-12-31 03:09:20 +08:00
if ( ! _queue - > queries ) {
2015-12-24 22:26:28 +03:00
App : : app ( ) - > killDownloadSessionsStart ( _dc ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-22 12:45:04 +03:00
2015-09-29 18:29:21 +03:00
if ( _localStatus = = LocalNotFound | | _localStatus = = LocalFailed ) {
2017-03-05 20:33:32 +03:00
if ( _urlLocation ) {
Local : : writeImage ( storageKey ( * _urlLocation ) , StorageImageSaved ( _data ) ) ;
} else if ( _locationType ! = UnknownFileLocation ) { // audio, video, document
2016-07-08 16:56:53 +03:00
MediaKey mkey = mediaKey ( _locationType , _dc , _id , _version ) ;
2015-12-24 22:26:28 +03:00
if ( ! _fname . isEmpty ( ) ) {
2017-03-04 14:28:21 +03:00
Local : : writeFileLocation ( mkey , FileLocation ( _fname ) ) ;
2015-01-02 17:55:24 +03:00
}
2015-12-24 22:26:28 +03:00
if ( _toCache = = LoadToCacheAsWell ) {
2015-09-29 18:29:21 +03:00
if ( _locationType = = DocumentFileLocation ) {
2015-12-24 22:26:28 +03:00
Local : : writeStickerImage ( mkey , _data ) ;
2015-09-29 18:29:21 +03:00
} else if ( _locationType = = AudioFileLocation ) {
2015-12-24 22:26:28 +03:00
Local : : writeAudio ( mkey , _data ) ;
2015-09-29 18:29:21 +03:00
}
}
} else {
2017-03-04 14:28:21 +03:00
Local : : writeImage ( storageKey ( * _location ) , StorageImageSaved ( _data ) ) ;
2015-01-02 17:55:24 +03:00
}
2014-11-22 12:45:04 +03:00
}
2016-03-17 21:03:08 +03:00
} else {
2017-02-27 21:33:42 +03:00
if ( DebugLogging : : FileLoader ( ) & & _id ) {
2017-03-05 20:33:32 +03:00
DEBUG_LOG ( ( " FileLoader(%1): not done yet, _lastComplete=%2, _size=%3, _nextRequestOffset=%4, _requests=%5 " ) . arg ( _id ) . arg ( Logs : : b ( _lastComplete ) ) . arg ( _size ) . arg ( _nextRequestOffset ) . arg ( serializereqs ( _dcIndexByRequest ) ) ) ;
2017-02-27 21:33:42 +03:00
}
2014-05-30 12:53:19 +04:00
}
2017-03-04 14:28:21 +03:00
if ( _finished ) {
2017-03-04 22:36:59 +03:00
_downloader - > taskFinished ( ) . notify ( ) ;
2016-05-25 20:59:21 +03:00
}
2017-02-27 21:33:42 +03:00
emit progress ( this ) ;
2014-05-30 12:53:19 +04:00
loadNext ( ) ;
}
bool mtpFileLoader : : partFailed ( const RPCError & error ) {
2016-04-08 14:44:35 +04:00
if ( MTP : : isDefaultHandledError ( error ) ) return false ;
2015-04-04 23:01:34 +03:00
2015-12-24 22:26:28 +03:00
cancel ( true ) ;
2014-05-30 12:53:19 +04:00
return true ;
}
2015-12-31 03:09:20 +08:00
void mtpFileLoader : : cancelRequests ( ) {
2017-03-05 20:33:32 +03:00
if ( _dcIndexByRequest . isEmpty ( ) ) return ;
2015-12-31 03:09:20 +08:00
2017-03-05 20:33:32 +03:00
auto limit = partSize ( ) ;
2015-12-31 03:09:20 +08:00
DataRequested & dr ( DataRequestedMap [ _dc ] ) ;
2017-03-05 20:33:32 +03:00
for ( auto i = _dcIndexByRequest . cbegin ( ) , e = _dcIndexByRequest . cend ( ) ; i ! = e ; + + i ) {
2015-12-31 03:09:20 +08:00
MTP : : cancel ( i . key ( ) ) ;
int32 dcIndex = i . value ( ) ;
dr . v [ dcIndex ] - = limit ;
2014-05-30 12:53:19 +04:00
}
2017-03-05 20:33:32 +03:00
_queue - > queries - = _dcIndexByRequest . size ( ) ;
_dcIndexByRequest . clear ( ) ;
2014-05-30 12:53:19 +04:00
2017-02-23 13:59:19 +03:00
if ( ! _queue - > queries ) {
Messenger : : Instance ( ) . killDownloadSessionsStart ( _dc ) ;
2015-12-31 03:09:20 +08:00
}
2014-05-30 12:53:19 +04:00
}
2015-09-29 18:29:21 +03:00
bool mtpFileLoader : : tryLoadLocal ( ) {
if ( _localStatus = = LocalNotFound | | _localStatus = = LocalLoaded | | _localStatus = = LocalFailed ) {
return false ;
}
if ( _localStatus = = LocalLoading ) {
return true ;
}
2017-03-05 20:33:32 +03:00
if ( _urlLocation ) {
_localTaskId = Local : : startImageLoad ( storageKey ( * _urlLocation ) , this ) ;
} else if ( _location ) {
2015-12-24 22:26:28 +03:00
_localTaskId = Local : : startImageLoad ( storageKey ( * _location ) , this ) ;
2015-09-29 18:29:21 +03:00
} else {
2015-12-24 22:26:28 +03:00
if ( _toCache = = LoadToCacheAsWell ) {
2016-07-08 16:56:53 +03:00
MediaKey mkey = mediaKey ( _locationType , _dc , _id , _version ) ;
2015-09-29 18:29:21 +03:00
if ( _locationType = = DocumentFileLocation ) {
2015-10-01 17:05:05 +03:00
_localTaskId = Local : : startStickerImageLoad ( mkey , this ) ;
2015-09-29 18:29:21 +03:00
} else if ( _locationType = = AudioFileLocation ) {
2015-10-01 17:05:05 +03:00
_localTaskId = Local : : startAudioLoad ( mkey , this ) ;
2015-01-02 17:55:24 +03:00
}
2014-11-22 12:45:04 +03:00
}
}
2017-02-27 21:33:42 +03:00
2016-10-12 22:34:25 +03:00
emit progress ( this ) ;
2014-05-30 12:53:19 +04:00
2015-12-24 22:26:28 +03:00
if ( _localStatus ! = LocalNotTried ) {
2017-03-04 14:28:21 +03:00
return _finished ;
2015-12-24 22:26:28 +03:00
} else if ( _localTaskId ) {
_localStatus = LocalLoading ;
return true ;
2015-09-29 18:29:21 +03:00
}
2015-12-24 22:26:28 +03:00
_localStatus = LocalNotFound ;
return false ;
2015-09-29 18:29:21 +03:00
}
2015-12-31 03:09:20 +08:00
mtpFileLoader : : ~ mtpFileLoader ( ) {
cancelRequests ( ) ;
}
webFileLoader : : webFileLoader ( const QString & url , const QString & to , LoadFromCloudSetting fromCloud , bool autoLoading )
2015-12-31 13:34:43 +08:00
: FileLoader ( QString ( ) , 0 , UnknownFileLocation , LoadToCacheAsWell , fromCloud , autoLoading )
2015-12-31 03:09:20 +08:00
, _url ( url )
, _requestSent ( false )
, _already ( 0 ) {
_queue = & _webQueue ;
}
bool webFileLoader : : loadPart ( ) {
2017-03-04 14:28:21 +03:00
if ( _finished | | _requestSent | | _webLoadManager = = FinishedWebLoadManager ) return false ;
2015-12-31 03:09:20 +08:00
if ( ! _webLoadManager ) {
_webLoadMainManager = new WebLoadMainManager ( ) ;
_webLoadThread = new QThread ( ) ;
_webLoadManager = new WebLoadManager ( _webLoadThread ) ;
_webLoadThread - > start ( ) ;
2015-09-29 21:44:31 +03:00
}
2015-12-31 03:09:20 +08:00
_requestSent = true ;
_webLoadManager - > append ( this , _url ) ;
return false ;
}
int32 webFileLoader : : currentOffset ( bool includeSkipped ) const {
return _already ;
}
void webFileLoader : : onProgress ( qint64 already , qint64 size ) {
_size = size ;
_already = already ;
2017-02-27 21:33:42 +03:00
2015-12-31 03:09:20 +08:00
emit progress ( this ) ;
}
void webFileLoader : : onFinished ( const QByteArray & data ) {
if ( _fileIsOpen ) {
if ( _file . write ( data . constData ( ) , data . size ( ) ) ! = qint64 ( data . size ( ) ) ) {
return cancel ( true ) ;
}
} else {
_data = data ;
2015-09-29 21:44:31 +03:00
}
2015-12-31 03:09:20 +08:00
if ( ! _fname . isEmpty ( ) & & ( _toCache = = LoadToCacheAsWell ) ) {
2015-12-24 22:26:28 +03:00
if ( ! _fileIsOpen ) _fileIsOpen = _file . open ( QIODevice : : WriteOnly ) ;
if ( ! _fileIsOpen ) {
2015-12-31 03:09:20 +08:00
return cancel ( true ) ;
2015-09-29 21:44:31 +03:00
}
2015-12-24 22:26:28 +03:00
if ( _file . write ( _data ) ! = qint64 ( _data . size ( ) ) ) {
2015-12-31 03:09:20 +08:00
return cancel ( true ) ;
2015-09-29 21:44:31 +03:00
}
}
2017-03-04 14:28:21 +03:00
_finished = true ;
2015-12-24 22:26:28 +03:00
if ( _fileIsOpen ) {
_file . close ( ) ;
_fileIsOpen = false ;
2017-02-28 17:05:30 +03:00
Platform : : File : : PostprocessDownloaded ( QFileInfo ( _file ) . absoluteFilePath ( ) ) ;
2015-09-29 21:44:31 +03:00
}
2015-12-31 03:09:20 +08:00
removeFromQueue ( ) ;
if ( _localStatus = = LocalNotFound | | _localStatus = = LocalFailed ) {
2015-12-31 23:27:21 +08:00
Local : : writeWebFile ( _url , _data ) ;
2015-12-31 03:09:20 +08:00
}
2017-03-04 22:36:59 +03:00
_downloader - > taskFinished ( ) . notify ( ) ;
2017-02-27 21:33:42 +03:00
emit progress ( this ) ;
2015-09-29 21:44:31 +03:00
loadNext ( ) ;
}
2015-12-31 03:09:20 +08:00
void webFileLoader : : onError ( ) {
cancel ( true ) ;
}
bool webFileLoader : : tryLoadLocal ( ) {
if ( _localStatus = = LocalNotFound | | _localStatus = = LocalLoaded | | _localStatus = = LocalFailed ) {
return false ;
}
if ( _localStatus = = LocalLoading ) {
return true ;
2015-12-23 19:48:44 +03:00
}
2015-12-24 22:26:28 +03:00
2015-12-31 23:27:21 +08:00
_localTaskId = Local : : startWebFileLoad ( _url , this ) ;
2015-12-31 03:09:20 +08:00
if ( _localStatus ! = LocalNotTried ) {
2017-03-04 14:28:21 +03:00
return _finished ;
2015-12-31 03:09:20 +08:00
} else if ( _localTaskId ) {
_localStatus = LocalLoading ;
return true ;
2015-12-24 22:26:28 +03:00
}
2015-12-31 03:09:20 +08:00
_localStatus = LocalNotFound ;
return false ;
}
2015-09-29 18:29:21 +03:00
2015-12-31 03:09:20 +08:00
void webFileLoader : : cancelRequests ( ) {
if ( ! webLoadManager ( ) ) return ;
webLoadManager ( ) - > stop ( this ) ;
}
webFileLoader : : ~ webFileLoader ( ) {
}
class webFileLoaderPrivate {
public :
webFileLoaderPrivate ( webFileLoader * loader , const QString & url )
: _interface ( loader )
, _url ( url )
2017-03-06 11:08:59 +03:00
, _redirectsLeft ( kMaxHttpRedirects ) {
2015-12-31 03:09:20 +08:00
}
QNetworkReply * reply ( ) {
return _reply ;
}
QNetworkReply * request ( QNetworkAccessManager & manager , const QString & redirect ) {
if ( ! redirect . isEmpty ( ) ) _url = redirect ;
QNetworkRequest req ( _url ) ;
QByteArray rangeHeaderValue = " bytes= " + QByteArray : : number ( _already ) + " - " ;
req . setRawHeader ( " Range " , rangeHeaderValue ) ;
_reply = manager . get ( req ) ;
return _reply ;
}
bool oneMoreRedirect ( ) {
if ( _redirectsLeft ) {
- - _redirectsLeft ;
return true ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
return false ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
void setData ( const QByteArray & data ) {
_data = data ;
}
void addData ( const QByteArray & data ) {
_data . append ( data ) ;
}
const QByteArray & data ( ) {
return _data ;
}
void setProgress ( qint64 already , qint64 size ) {
_already = already ;
_size = qMax ( size , 0LL ) ;
}
qint64 size ( ) const {
return _size ;
}
qint64 already ( ) const {
return _already ;
}
private :
2017-03-06 11:08:59 +03:00
static constexpr auto kMaxHttpRedirects = 5 ;
webFileLoader * _interface = nullptr ;
2015-12-31 03:09:20 +08:00
QUrl _url ;
2017-03-06 11:08:59 +03:00
qint64 _already = 0 ;
qint64 _size = 0 ;
QNetworkReply * _reply = nullptr ;
int32 _redirectsLeft = kMaxHttpRedirects ;
2015-12-31 03:09:20 +08:00
QByteArray _data ;
friend class WebLoadManager ;
} ;
void reinitWebLoadManager ( ) {
2016-03-20 11:16:35 +03:00
# ifndef TDESKTOP_DISABLE_NETWORK_PROXY
2015-12-31 03:09:20 +08:00
if ( webLoadManager ( ) ) {
webLoadManager ( ) - > setProxySettings ( App : : getHttpProxySettings ( ) ) ;
}
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_NETWORK_PROXY
2015-12-31 03:09:20 +08:00
}
void stopWebLoadManager ( ) {
if ( webLoadManager ( ) ) {
_webLoadThread - > quit ( ) ;
2016-03-01 05:36:23 +03:00
DEBUG_LOG ( ( " Waiting for webloadThread to finish " ) ) ;
2015-12-31 03:09:20 +08:00
_webLoadThread - > wait ( ) ;
delete _webLoadManager ;
delete _webLoadMainManager ;
delete _webLoadThread ;
_webLoadThread = 0 ;
_webLoadMainManager = 0 ;
_webLoadManager = FinishedWebLoadManager ;
}
}
2016-03-20 11:16:35 +03:00
# ifndef TDESKTOP_DISABLE_NETWORK_PROXY
2015-12-31 03:09:20 +08:00
void WebLoadManager : : setProxySettings ( const QNetworkProxy & proxy ) {
QMutexLocker lock ( & _loaderPointersMutex ) ;
_proxySettings = proxy ;
emit proxyApplyDelayed ( ) ;
}
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_NETWORK_PROXY
2015-12-31 03:09:20 +08:00
WebLoadManager : : WebLoadManager ( QThread * thread ) {
moveToThread ( thread ) ;
_manager . moveToThread ( thread ) ;
connect ( thread , SIGNAL ( started ( ) ) , this , SLOT ( process ( ) ) ) ;
connect ( thread , SIGNAL ( finished ( ) ) , this , SLOT ( finish ( ) ) ) ;
connect ( this , SIGNAL ( processDelayed ( ) ) , this , SLOT ( process ( ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( proxyApplyDelayed ( ) ) , this , SLOT ( proxyApply ( ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( progress ( webFileLoader * , qint64 , qint64 ) ) , _webLoadMainManager , SLOT ( progress ( webFileLoader * , qint64 , qint64 ) ) ) ;
connect ( this , SIGNAL ( finished ( webFileLoader * , QByteArray ) ) , _webLoadMainManager , SLOT ( finished ( webFileLoader * , QByteArray ) ) ) ;
connect ( this , SIGNAL ( error ( webFileLoader * ) ) , _webLoadMainManager , SLOT ( error ( webFileLoader * ) ) ) ;
connect ( & _manager , SIGNAL ( authenticationRequired ( QNetworkReply * , QAuthenticator * ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
2016-09-15 14:08:45 +03:00
# ifndef OS_MAC_OLD
2015-12-31 03:09:20 +08:00
connect ( & _manager , SIGNAL ( sslErrors ( QNetworkReply * , const QList < QSslError > & ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
2016-09-15 14:08:45 +03:00
# endif // OS_MAC_OLD
2015-12-31 03:09:20 +08:00
}
void WebLoadManager : : append ( webFileLoader * loader , const QString & url ) {
loader - > _private = new webFileLoaderPrivate ( loader , url ) ;
QMutexLocker lock ( & _loaderPointersMutex ) ;
_loaderPointers . insert ( loader , loader - > _private ) ;
emit processDelayed ( ) ;
}
void WebLoadManager : : stop ( webFileLoader * loader ) {
QMutexLocker lock ( & _loaderPointersMutex ) ;
_loaderPointers . remove ( loader ) ;
emit processDelayed ( ) ;
}
bool WebLoadManager : : carries ( webFileLoader * loader ) const {
QMutexLocker lock ( & _loaderPointersMutex ) ;
return _loaderPointers . contains ( loader ) ;
}
bool WebLoadManager : : handleReplyResult ( webFileLoaderPrivate * loader , WebReplyProcessResult result ) {
QMutexLocker lock ( & _loaderPointersMutex ) ;
LoaderPointers : : iterator it = _loaderPointers . find ( loader - > _interface ) ;
if ( it ! = _loaderPointers . cend ( ) & & it . key ( ) - > _private ! = loader ) {
it = _loaderPointers . end ( ) ; // it is a new loader which was realloced in the same address
}
if ( it = = _loaderPointers . cend ( ) ) {
return false ;
}
if ( result = = WebReplyProcessProgress ) {
if ( loader - > size ( ) > AnimationInMemory ) {
LOG ( ( " API Error: too large file is loaded to cache: %1 " ) . arg ( loader - > size ( ) ) ) ;
result = WebReplyProcessError ;
}
}
if ( result = = WebReplyProcessError ) {
if ( it ! = _loaderPointers . cend ( ) ) {
emit error ( it . key ( ) ) ;
}
return false ;
}
if ( loader - > already ( ) < loader - > size ( ) | | ! loader - > size ( ) ) {
emit progress ( it . key ( ) , loader - > already ( ) , loader - > size ( ) ) ;
return true ;
}
emit finished ( it . key ( ) , loader - > data ( ) ) ;
return false ;
}
void WebLoadManager : : onFailed ( QNetworkReply : : NetworkError error ) {
onFailed ( qobject_cast < QNetworkReply * > ( QObject : : sender ( ) ) ) ;
}
void WebLoadManager : : onFailed ( QNetworkReply * reply ) {
if ( ! reply ) return ;
reply - > deleteLater ( ) ;
Replies : : iterator j = _replies . find ( reply ) ;
if ( j = = _replies . cend ( ) ) { // handled already
return ;
}
webFileLoaderPrivate * loader = j . value ( ) ;
_replies . erase ( j ) ;
2015-12-31 13:34:43 +08:00
LOG ( ( " Network Error: Failed to request '%1', error %2 (%3) " ) . arg ( QString : : fromLatin1 ( loader - > _url . toEncoded ( ) ) ) . arg ( int ( reply - > error ( ) ) ) . arg ( reply - > errorString ( ) ) ) ;
2015-12-31 03:09:20 +08:00
if ( ! handleReplyResult ( loader , WebReplyProcessError ) ) {
_loaders . remove ( loader ) ;
delete loader ;
}
}
void WebLoadManager : : onProgress ( qint64 already , qint64 size ) {
QNetworkReply * reply = qobject_cast < QNetworkReply * > ( QObject : : sender ( ) ) ;
if ( ! reply ) return ;
Replies : : iterator j = _replies . find ( reply ) ;
if ( j = = _replies . cend ( ) ) { // handled already
return ;
}
webFileLoaderPrivate * loader = j . value ( ) ;
WebReplyProcessResult result = WebReplyProcessProgress ;
QVariant statusCode = reply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) ;
int32 status = statusCode . isValid ( ) ? statusCode . toInt ( ) : 200 ;
if ( status ! = 200 & & status ! = 206 & & status ! = 416 ) {
if ( status = = 301 | | status = = 302 ) {
QString loc = reply - > header ( QNetworkRequest : : LocationHeader ) . toString ( ) ;
if ( ! loc . isEmpty ( ) ) {
if ( loader - > oneMoreRedirect ( ) ) {
sendRequest ( loader , loc ) ;
return ;
2014-05-30 12:53:19 +04:00
} else {
2015-12-31 03:09:20 +08:00
LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for web file loader: %1 " ) . arg ( loc ) ) ;
result = WebReplyProcessError ;
2014-05-30 12:53:19 +04:00
}
}
2015-12-31 03:09:20 +08:00
} else {
LOG ( ( " Network Error: Bad HTTP status received in WebLoadManager::onProgress(): %1 " ) . arg ( statusCode . toInt ( ) ) ) ;
result = WebReplyProcessError ;
2014-05-30 12:53:19 +04:00
}
} else {
2015-12-31 03:09:20 +08:00
loader - > setProgress ( already , size ) ;
QByteArray r = reply - > readAll ( ) ;
if ( ! r . isEmpty ( ) ) {
loader - > addData ( r ) ;
}
if ( size = = 0 ) {
LOG ( ( " Network Error: Zero size received for HTTP download progress in WebLoadManager::onProgress(): %1 / %2 " ) . arg ( already ) . arg ( size ) ) ;
result = WebReplyProcessError ;
2014-05-30 12:53:19 +04:00
}
}
2015-12-31 03:09:20 +08:00
if ( ! handleReplyResult ( loader , result ) ) {
_replies . erase ( j ) ;
_loaders . remove ( loader ) ;
delete loader ;
2014-05-30 12:53:19 +04:00
2015-12-31 03:09:20 +08:00
reply - > abort ( ) ;
reply - > deleteLater ( ) ;
}
}
2014-05-30 12:53:19 +04:00
2015-12-31 03:09:20 +08:00
void WebLoadManager : : onMeta ( ) {
QNetworkReply * reply = qobject_cast < QNetworkReply * > ( QObject : : sender ( ) ) ;
if ( ! reply ) return ;
Replies : : iterator j = _replies . find ( reply ) ;
if ( j = = _replies . cend ( ) ) { // handled already
return ;
}
webFileLoaderPrivate * loader = j . value ( ) ;
typedef QList < QNetworkReply : : RawHeaderPair > Pairs ;
Pairs pairs = reply - > rawHeaderPairs ( ) ;
for ( Pairs : : iterator i = pairs . begin ( ) , e = pairs . end ( ) ; i ! = e ; + + i ) {
if ( QString : : fromUtf8 ( i - > first ) . toLower ( ) = = " content-range " ) {
QRegularExpressionMatch m = QRegularExpression ( qsl ( " /( \\ d+)([^ \\ d]|$) " ) ) . match ( QString : : fromUtf8 ( i - > second ) ) ;
if ( m . hasMatch ( ) ) {
loader - > setProgress ( qMax ( qint64 ( loader - > data ( ) . size ( ) ) , loader - > already ( ) ) , m . captured ( 1 ) . toLongLong ( ) ) ;
if ( ! handleReplyResult ( loader , WebReplyProcessProgress ) ) {
_replies . erase ( j ) ;
_loaders . remove ( loader ) ;
delete loader ;
reply - > abort ( ) ;
reply - > deleteLater ( ) ;
}
2014-05-30 12:53:19 +04:00
}
}
2015-12-31 03:09:20 +08:00
}
}
void WebLoadManager : : process ( ) {
Loaders newLoaders ;
{
QMutexLocker lock ( & _loaderPointersMutex ) ;
for ( LoaderPointers : : iterator i = _loaderPointers . begin ( ) , e = _loaderPointers . end ( ) ; i ! = e ; + + i ) {
Loaders : : iterator it = _loaders . find ( i . value ( ) ) ;
if ( i . value ( ) ) {
if ( it = = _loaders . cend ( ) ) {
_loaders . insert ( i . value ( ) ) ;
newLoaders . insert ( i . value ( ) ) ;
}
i . value ( ) = 0 ;
}
}
2016-03-25 18:20:34 +03:00
for ( auto i = _loaders . begin ( ) , e = _loaders . end ( ) ; i ! = e ; ) {
LoaderPointers : : iterator it = _loaderPointers . find ( ( * i ) - > _interface ) ;
if ( it ! = _loaderPointers . cend ( ) & & it . key ( ) - > _private ! = ( * i ) ) {
2015-12-31 03:09:20 +08:00
it = _loaderPointers . end ( ) ;
}
if ( it = = _loaderPointers . cend ( ) ) {
2016-03-25 18:20:34 +03:00
if ( QNetworkReply * reply = ( * i ) - > reply ( ) ) {
2015-12-31 03:09:20 +08:00
_replies . remove ( reply ) ;
reply - > abort ( ) ;
reply - > deleteLater ( ) ;
}
2016-03-25 18:20:34 +03:00
delete ( * i ) ;
2015-12-31 03:09:20 +08:00
i = _loaders . erase ( i ) ;
} else {
+ + i ;
2014-05-30 12:53:19 +04:00
}
}
}
2016-03-25 18:20:34 +03:00
for_const ( webFileLoaderPrivate * loader , newLoaders ) {
if ( _loaders . contains ( loader ) ) {
sendRequest ( loader ) ;
2015-12-31 03:09:20 +08:00
}
}
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
void WebLoadManager : : sendRequest ( webFileLoaderPrivate * loader , const QString & redirect ) {
Replies : : iterator j = _replies . find ( loader - > reply ( ) ) ;
if ( j ! = _replies . cend ( ) ) {
QNetworkReply * r = j . key ( ) ;
_replies . erase ( j ) ;
2015-12-24 22:26:28 +03:00
2015-12-31 03:09:20 +08:00
r - > abort ( ) ;
r - > deleteLater ( ) ;
2015-12-24 22:26:28 +03:00
}
2015-12-31 03:09:20 +08:00
QNetworkReply * r = loader - > request ( _manager , redirect ) ;
connect ( r , SIGNAL ( downloadProgress ( qint64 , qint64 ) ) , this , SLOT ( onProgress ( qint64 , qint64 ) ) ) ;
connect ( r , SIGNAL ( error ( QNetworkReply : : NetworkError ) ) , this , SLOT ( onFailed ( QNetworkReply : : NetworkError ) ) ) ;
connect ( r , SIGNAL ( metaDataChanged ( ) ) , this , SLOT ( onMeta ( ) ) ) ;
_replies . insert ( r , loader ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
void WebLoadManager : : proxyApply ( ) {
2016-03-20 11:16:35 +03:00
# ifndef TDESKTOP_DISABLE_NETWORK_PROXY
2015-12-31 03:09:20 +08:00
QMutexLocker lock ( & _loaderPointersMutex ) ;
_manager . setProxy ( _proxySettings ) ;
2016-10-18 10:56:38 +03:00
# endif // !TDESKTOP_DISABLE_NETWORK_PROXY
2015-12-31 03:09:20 +08:00
}
2014-10-30 19:23:44 +03:00
2015-12-31 03:09:20 +08:00
void WebLoadManager : : finish ( ) {
clear ( ) ;
}
void WebLoadManager : : clear ( ) {
QMutexLocker lock ( & _loaderPointersMutex ) ;
for ( LoaderPointers : : iterator i = _loaderPointers . begin ( ) , e = _loaderPointers . end ( ) ; i ! = e ; + + i ) {
if ( i . value ( ) ) {
i . key ( ) - > _private = 0 ;
}
2014-10-30 19:23:44 +03:00
}
2015-12-31 03:09:20 +08:00
_loaderPointers . clear ( ) ;
2014-10-30 19:23:44 +03:00
2016-03-25 18:20:34 +03:00
for_const ( webFileLoaderPrivate * loader , _loaders ) {
delete loader ;
2014-10-30 19:23:44 +03:00
}
2015-12-31 03:09:20 +08:00
_loaders . clear ( ) ;
for ( Replies : : iterator i = _replies . begin ( ) , e = _replies . end ( ) ; i ! = e ; + + i ) {
delete i . key ( ) ;
}
_replies . clear ( ) ;
2014-10-30 19:23:44 +03:00
}
2015-12-31 03:09:20 +08:00
WebLoadManager : : ~ WebLoadManager ( ) {
clear ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-31 03:09:20 +08:00
void WebLoadMainManager : : progress ( webFileLoader * loader , qint64 already , qint64 size ) {
if ( webLoadManager ( ) & & webLoadManager ( ) - > carries ( loader ) ) {
loader - > onProgress ( already , size ) ;
}
}
void WebLoadMainManager : : finished ( webFileLoader * loader , QByteArray data ) {
if ( webLoadManager ( ) & & webLoadManager ( ) - > carries ( loader ) ) {
loader - > onFinished ( data ) ;
}
}
void WebLoadMainManager : : error ( webFileLoader * loader ) {
if ( webLoadManager ( ) & & webLoadManager ( ) - > carries ( loader ) ) {
loader - > onError ( ) ;
2015-09-29 21:44:31 +03:00
}
2014-05-30 12:53:19 +04:00
}