diff --git a/Telegram/DeployLinux.sh b/Telegram/DeployLinux.sh index d3bc33f861..71f022d5dc 100755 --- a/Telegram/DeployLinux.sh +++ b/Telegram/DeployLinux.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinuxupd$AppVersion" ]; then echo "tlinuxupd$AppVersion not found!"; diff --git a/Telegram/DeployLinux32.sh b/Telegram/DeployLinux32.sh index 476ba92f47..50d729aca9 100755 --- a/Telegram/DeployLinux32.sh +++ b/Telegram/DeployLinux32.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinux32upd$AppVersion" ]; then echo "tlinux32upd$AppVersion not found!" diff --git a/Telegram/DeployMacWin.sh b/Telegram/DeployMacWin.sh index 4bdf817d22..d67ee3e37c 100755 --- a/Telegram/DeployMacWin.sh +++ b/Telegram/DeployMacWin.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ ! -f "./../Mac/Release/deploy/$AppVersionStr/tmacupd$AppVersion" ]; then echo "tmacupd$AppVersion not found!" diff --git a/Telegram/DeployWin.sh b/Telegram/DeployWin.sh index 63d6def586..400bb3946a 100644 --- a/Telegram/DeployWin.sh +++ b/Telegram/DeployWin.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr/tupdate$AppVersion" ]; then echo "tupdate$AppVersion not found!" diff --git a/Telegram/PrepareLinux.sh b/Telegram/PrepareLinux.sh index 2b389726bb..7455a72043 100755 --- a/Telegram/PrepareLinux.sh +++ b/Telegram/PrepareLinux.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then echo "Deploy folder for version $AppVersionStr already exists!" diff --git a/Telegram/PrepareLinux32.sh b/Telegram/PrepareLinux32.sh index 1e8cd2ecce..9f367ebfb1 100755 --- a/Telegram/PrepareLinux32.sh +++ b/Telegram/PrepareLinux32.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then echo "Deploy folder for version $AppVersionStr already exists!" diff --git a/Telegram/PrepareMac.sh b/Telegram/PrepareMac.sh index c0ccab8140..25fbfbf325 100755 --- a/Telegram/PrepareMac.sh +++ b/Telegram/PrepareMac.sh @@ -1,5 +1,5 @@ -AppVersionStr=0.6.5 -AppVersion=6005 +AppVersionStr=0.6.6 +AppVersion=6006 if [ -d "./../Mac/Release/deploy/$AppVersionStr" ]; then echo "Deploy folder for version $AppVersionStr already exists!" diff --git a/Telegram/PrepareWin.bat b/Telegram/PrepareWin.bat index 872904e7a2..b3ced200fc 100644 --- a/Telegram/PrepareWin.bat +++ b/Telegram/PrepareWin.bat @@ -1,6 +1,6 @@ cd ..\Win32\Deploy -call ..\..\..\TelegramPrivate\Sign.bat tsetup.0.6.5.exe +call ..\..\..\TelegramPrivate\Sign.bat tsetup.0.6.6.exe call Prepare.exe -path Telegram.exe -path Updater.exe -mkdir deploy\0.6.5\Telegram -move deploy\0.6.5\Telegram.exe deploy\0.6.5\Telegram\ +mkdir deploy\0.6.6\Telegram +move deploy\0.6.6\Telegram.exe deploy\0.6.6\Telegram\ cd ..\..\Telegram diff --git a/Telegram/Setup.iss b/Telegram/Setup.iss index c5b13b85e2..3b0b69a3d8 100644 --- a/Telegram/Setup.iss +++ b/Telegram/Setup.iss @@ -3,9 +3,9 @@ #define MyAppShortName "Telegram" #define MyAppName "Telegram Desktop" -#define MyAppVersion "0.6.5" -#define MyAppVersionZero "0.6.5" -#define MyAppFullVersion "0.6.5.0" +#define MyAppVersion "0.6.6" +#define MyAppVersionZero "0.6.6" +#define MyAppFullVersion "0.6.6.0" #define MyAppPublisher "Telegram Messenger LLP" #define MyAppURL "https://tdesktop.com" #define MyAppExeName "Telegram.exe" diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index d39db1210e..fb470b0cbc 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -531,7 +531,7 @@ namespace App { const MTPDphotoSize &d(size.c_photoSize()); if (d.vlocation.type() == mtpc_fileLocation) { const MTPDfileLocation &l(d.vlocation.c_fileLocation()); - return ImagePtr(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v); + return ImagePtr(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v, d.vsize.v); } } break; case mtpc_photoCachedSize: { diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 3273af203a..db03180124 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -154,6 +154,9 @@ Application::Application(int &argc, char **argv) : PsApplication(argc, argv), connect(&writeUserConfigTimer, SIGNAL(timeout()), this, SLOT(onWriteUserConfig())); writeUserConfigTimer.setSingleShot(true); + killDownloadSessionsTimer.setSingleShot(true); + connect(&killDownloadSessionsTimer, SIGNAL(timeout()), this, SLOT(killDownloadSessions())); + if (cManyInstance()) { startApp(); } else { @@ -326,10 +329,46 @@ void Application::writeUserConfigIn(uint64 ms) { } } +void Application::killDownloadSessionsStart(int32 dc) { + if (killDownloadSessionTimes.constFind(dc) == killDownloadSessionTimes.cend()) { + killDownloadSessionTimes.insert(dc, getms() + MTPKillFileSessionTimeout); + } + if (!killDownloadSessionsTimer.isActive()) { + killDownloadSessionsTimer.start(MTPKillFileSessionTimeout + 5); + } +} + +void Application::killDownloadSessionsStop(int32 dc) { + killDownloadSessionTimes.remove(dc); + if (killDownloadSessionTimes.isEmpty() && killDownloadSessionsTimer.isActive()) { + killDownloadSessionsTimer.stop(); + } +} + void Application::onWriteUserConfig() { App::writeUserConfig(); } +void Application::killDownloadSessions() { + uint64 ms = getms(), left = MTPKillFileSessionTimeout; + for (QMap::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) { + if (i.value() <= ms) { + for (int j = 1; j < MTPDownloadSessionsCount; ++j) { + MTP::killSession(MTP::dld[j] + i.key()); + } + i = killDownloadSessionTimes.erase(i); + } else { + if (i.value() - ms < left) { + left = i.value() - ms; + } + ++i; + } + } + if (!killDownloadSessionTimes.isEmpty()) { + killDownloadSessionsTimer.start(left); + } +} + void Application::photoUpdated(MsgId msgId, const MTPInputFile &file) { if (!App::self()) return; diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index 67dbb38186..303c138a79 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -70,6 +70,9 @@ public: void writeUserConfigIn(uint64 ms); + void killDownloadSessionsStart(int32 dc); + void killDownloadSessionsStop(int32 dc); + signals: void peerPhotoDone(PeerId peer); @@ -100,10 +103,15 @@ public slots: void onEnableDebugMode(); void onWriteUserConfig(); + void killDownloadSessions(); + private: QMap photoUpdates; + QMap killDownloadSessionTimes; + QTimer killDownloadSessionsTimer; + void startApp(); typedef QPair ClientSocket; diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 2f8d8df589..4c85b9c371 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com */ #pragma once -static const int32 AppVersion = 6005; -static const wchar_t *AppVersionStr = L"0.6.5"; +static const int32 AppVersion = 6006; +static const wchar_t *AppVersionStr = L"0.6.6"; static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppName = L"Telegram Desktop"; @@ -32,7 +32,7 @@ enum { MTPShortBufferSize = 65535, // of ints, 256 kb MTPPacketSizeMax = 67108864, // 64 mb MTPIdsBufferSize = 400, // received msgIds and wereAcked msgIds count stored - MTPCheckResendTimeout = 5000, // how much time passed from send till we resend request or check it's state, in ms + MTPCheckResendTimeout = 10000, // how much time passed from send till we resend request or check it's state, in ms MTPCheckResendWaiting = 1000, // how much time to wait for some more requests, when resending request or checking it's state, in ms MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state MTPContainerLives = 600, // container lives 10 minutes in haveSent map @@ -41,6 +41,10 @@ enum { MTPTcpConnectionWaitTimeout = 3000, // 3 seconds waiting for tcp, until we accept http MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check + MTPUploadSessionsCount = 4, // max 4 upload sessions is created + MTPDownloadSessionsCount = 4, // max 4 download sessions is created + MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill + MTPEnumDCTimeout = 4000, // 4 seconds timeout for help_getConfig to work (them move to other dc) MTPDebugBufferSize = 1024 * 1024, // 1 mb start size @@ -209,12 +213,12 @@ enum { LinkCropLimit = 360, // 360px link length max - DownloadPartSize = 32 * 1024, // 32kb for photo + DownloadPartSize = 64 * 1024, // 64kb for photo DocumentDownloadPartSize = 128 * 1024, // 128kb for document MaxUploadPhotoSize = 10 * 1024 * 1024, // 10mb photos max MaxUploadDocumentSize = 1500 * 1024 * 1024, // 1500mb documents max UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb - MaxFileQueries = 32, // max 32 file parts downloaded at the same time + MaxFileQueries = 16, // max 16 file parts downloaded at the same time UploadPartSize = 32 * 1024, // 32kb for photo DocumentMaxPartsCount = 3000, // no more than 3000 parts @@ -223,7 +227,7 @@ enum { DocumentUploadPartSize2 = 128 * 1024, // 128kb for small document ( <= 375mb ) DocumentUploadPartSize3 = 256 * 1024, // 256kb for medium document ( <= 750mb ) DocumentUploadPartSize4 = 512 * 1024, // 512kb for large document ( <= 1500mb ) - MaxUploadFileParallelSize = 512 * 1024, // max 512kb uploaded at the same time + MaxUploadFileParallelSize = MTPUploadSessionsCount * 512 * 1024, // max 512kb uploaded at the same time in each session UploadRequestInterval = 500, // one part each half second, if not uploaded faster MaxPhotosInMemory = 50, // try to clear some memory after 50 photos are created diff --git a/Telegram/SourceFiles/fileuploader.cpp b/Telegram/SourceFiles/fileuploader.cpp index 002d6d9a9c..bda9d1d3c0 100644 --- a/Telegram/SourceFiles/fileuploader.cpp +++ b/Telegram/SourceFiles/fileuploader.cpp @@ -19,8 +19,11 @@ Copyright (c) 2014 John Preston, https://tdesktop.com #include "fileuploader.h" FileUploader::FileUploader() : sentSize(0), uploading(0) { + memset(sentSizes, 0, sizeof(sentSizes)); nextTimer.setSingleShot(true); connect(&nextTimer, SIGNAL(timeout()), this, SLOT(sendNext())); + killSessionsTimer.setSingleShot(true); + connect(&killSessionsTimer, SIGNAL(timeout()), this, SLOT(killSessions())); } void FileUploader::uploadMedia(MsgId msgId, const ReadyLocalMedia &media) { @@ -60,16 +63,36 @@ void FileUploader::currentFailed() { requestsSent.clear(); docRequestsSent.clear(); - queue.remove(uploading); + dcMap.clear(); uploading = 0; sentSize = 0; + for (int i = 0; i < MTPUploadSessionsCount; ++i) { + sentSizes[i] = 0; + } sendNext(); } -void FileUploader::sendNext() { - if (sentSize >= MaxUploadFileParallelSize || queue.isEmpty()) return; +void FileUploader::killSessions() { + for (int i = 0; i < MTPUploadSessionsCount; ++i) { + MTP::killSession(MTP::upl[i]); + } +} +void FileUploader::sendNext() { + if (sentSize >= MaxUploadFileParallelSize) return; + + bool killing = killSessionsTimer.isActive(); + if (queue.isEmpty()) { + if (!killing) { + killSessionsTimer.start(MTPKillFileSessionTimeout); + } + return; + } + + if (killing) { + killSessionsTimer.stop(); + } Queue::iterator i = uploading ? queue.find(uploading) : queue.begin(); if (!uploading) { uploading = i.key(); @@ -77,6 +100,12 @@ void FileUploader::sendNext() { i = queue.begin(); uploading = i.key(); } + int todc = 0; + for (int dc = 1; dc < MTPUploadSessionsCount; ++dc) { + if (sentSizes[dc] < sentSizes[todc]) { + todc = dc; + } + } if (i->media.parts.isEmpty()) { if (i->docSentParts >= i->docPartsCount) { if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) { @@ -125,20 +154,24 @@ void FileUploader::sendNext() { } mtpRequestId requestId; if (i->docSize > UseBigFilesFrom) { - requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl); + requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]); } else { - requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl); + requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.id), MTP_int(i->docSentParts), MTP_string(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]); } docRequestsSent.insert(requestId, i->docSentParts); + dcMap.insert(requestId, todc); sentSize += i->docPartSize; + sentSizes[todc] += i->docPartSize; i->docSentParts++; } else { LocalFileParts::iterator part = i->media.parts.begin(); - mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.jpeg_id), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl); + mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.jpeg_id), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]); requestsSent.insert(requestId, part.value()); + dcMap.insert(requestId, todc); sentSize += part.value().size(); + sentSizes[todc] += part.value().size(); i->media.parts.erase(part); } @@ -168,7 +201,13 @@ void FileUploader::clear() { MTP::cancel(i.key()); } docRequestsSent.clear(); + dcMap.clear(); sentSize = 0; + for (int32 i = 0; i < MTPUploadSessionsCount; ++i) { + MTP::killSession(MTP::upl[i]); + sentSizes[i] = 0; + } + killSessionsTimer.stop(); } void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) { @@ -182,12 +221,22 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) { currentFailed(); return; } else { + QMap::iterator dcIt = dcMap.find(requestId); + if (dcIt == dcMap.cend()) { // must not happen + currentFailed(); + return; + } + int32 dc = dcIt.value(); + dcMap.erase(dcIt); + Queue::const_iterator k = queue.constFind(uploading); if (i != requestsSent.cend()) { sentSize -= i.value().size(); + sentSizes[dc] -= i.value().size(); requestsSent.erase(i); } else { sentSize -= k->docPartSize; + sentSizes[dc] -= k->docPartSize; docRequestsSent.erase(j); } if (k->media.type == ToPreparePhoto) { diff --git a/Telegram/SourceFiles/fileuploader.h b/Telegram/SourceFiles/fileuploader.h index 07a48be965..412e31167c 100644 --- a/Telegram/SourceFiles/fileuploader.h +++ b/Telegram/SourceFiles/fileuploader.h @@ -38,6 +38,7 @@ public: public slots: void sendNext(); + void killSessions(); signals: @@ -98,11 +99,13 @@ private: QMap requestsSent; QMap docRequestsSent; + QMap dcMap; uint32 sentSize; + uint32 sentSizes[MTPUploadSessionsCount]; MsgId uploading; Queue queue; Queue uploaded; - QTimer nextTimer; + QTimer nextTimer, killSessionsTimer; }; diff --git a/Telegram/SourceFiles/gui/images.cpp b/Telegram/SourceFiles/gui/images.cpp index 50a047a524..6cec09e128 100644 --- a/Telegram/SourceFiles/gui/images.cpp +++ b/Telegram/SourceFiles/gui/images.cpp @@ -336,7 +336,7 @@ int64 imageCacheSize() { return globalAquiredSize; } -StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret) : w(width), h(height), loader(new mtpFileLoader(dc, volume, local, secret)) { +StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) : w(width), h(height), loader(new mtpFileLoader(dc, volume, local, secret, size)) { } StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, QByteArray &bytes) : w(width), h(height), loader(0) { @@ -427,11 +427,11 @@ bool StorageImage::loaded() const { return check(); } -StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret) { +StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) { QByteArray key(storageKey(dc, volume, local, secret)); StorageImages::const_iterator i = storageImages.constFind(key); if (i == storageImages.cend()) { - i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret)); + i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret, size)); } return i.value(); } diff --git a/Telegram/SourceFiles/gui/images.h b/Telegram/SourceFiles/gui/images.h index c4776b642b..862a0b54fd 100644 --- a/Telegram/SourceFiles/gui/images.h +++ b/Telegram/SourceFiles/gui/images.h @@ -107,7 +107,7 @@ LocalImage *getImage(const QPixmap &pixmap, QByteArray format); class StorageImage : public Image { public: - StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret); + StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0); StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, QByteArray &bytes); int32 width() const; @@ -155,7 +155,7 @@ private: mutable mtpFileLoader *loader; }; -StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret); +StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0); StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes); Image *getImage(int32 width, int32 height, const MTPFileLocation &location); @@ -166,7 +166,7 @@ public: } ImagePtr(const QPixmap &pixmap, QByteArray format) : Parent(getImage(pixmap, format)) { } - ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret) : Parent(getImage(width, height, dc, volume, local, secret)) { + ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0) : Parent(getImage(width, height, dc, volume, local, secret, size)) { } ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes) : Parent(getImage(width, height, dc, volume, local, secret, bytes)) { } diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp index 3eeb3c4af6..7af8738c44 100644 --- a/Telegram/SourceFiles/mtproto/mtp.cpp +++ b/Telegram/SourceFiles/mtproto/mtp.cpp @@ -36,6 +36,7 @@ namespace { typedef QMap ParserMap; ParserMap parserMap; + QMutex parserMapLock; typedef QMap RequestMap; RequestMap requestMap; @@ -268,6 +269,8 @@ namespace _mtp_internal { } void unregisterRequest(mtpRequestId requestId) { + requestMap.remove(requestId); + QMutexLocker locker(&requestByDCLock); RequestsByDC::iterator i = requestsByDC.find(requestId); if (i != requestsByDC.end()) { @@ -283,9 +286,10 @@ namespace _mtp_internal { mtpRequestId res = reqid(); request->requestId = res; if (parser.onDone || parser.onFail) { + QMutexLocker locker(&parserMapLock); parserMap.insert(res, parser); - requestMap.insert(res, request); } + requestMap.insert(res, request); return res; } @@ -298,14 +302,21 @@ namespace _mtp_internal { } void clearCallbacks(mtpRequestId requestId, int32 errorCode) { - ParserMap::iterator i = parserMap.find(requestId); - if (i != parserMap.end()) { - if (errorCode) { - rpcErrorOccured(requestId, i.value(), rpcClientError("CLEAR_CALLBACK", QString("did not handle request %1, error code %2").arg(requestId).arg(errorCode))); + RPCResponseHandler h; + bool found = false; + { + QMutexLocker locker(&parserMapLock); + ParserMap::iterator i = parserMap.find(requestId); + if (i != parserMap.end()) { + h = i.value(); + found = true; + + parserMap.erase(i); } - parserMap.erase(i); } - requestMap.remove(requestId); + if (errorCode && found) { + rpcErrorOccured(requestId, h, rpcClientError("CLEAR_CALLBACK", QString("did not handle request %1, error code %2").arg(requestId).arg(errorCode))); + } _mtp_internal::unregisterRequest(requestId); } @@ -336,6 +347,7 @@ namespace _mtp_internal { if (!toClear.isEmpty()) { for (RPCCallbackClears::iterator i = toClear.begin(), e = toClear.end(); i != e; ++i) { if (cDebug()) { + QMutexLocker locker(&parserMapLock); if (parserMap.find(i->requestId) != parserMap.end()) { DEBUG_LOG(("RPC Info: clearing delayed callback %1, error code %2").arg(i->requestId).arg(i->errorCode)); } @@ -347,12 +359,18 @@ namespace _mtp_internal { } void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) { - ParserMap::iterator i = parserMap.find(requestId); - if (i != parserMap.cend()) { - RPCResponseHandler h(i.value()); - parserMap.erase(i); + RPCResponseHandler h; + { + QMutexLocker locker(&parserMapLock); + ParserMap::iterator i = parserMap.find(requestId); + if (i != parserMap.cend()) { + h = i.value(); + parserMap.erase(i); - DEBUG_LOG(("RPC Info: found parser for request %1, trying to parse response..").arg(requestId)); + DEBUG_LOG(("RPC Info: found parser for request %1, trying to parse response..").arg(requestId)); + } + } + if (h.onDone || h.onFail) { try { if (from >= end) throw mtpErrorInsufficient(); @@ -360,6 +378,7 @@ namespace _mtp_internal { RPCError err(MTPRpcError(from, end)); DEBUG_LOG(("RPC Info: error received, code %1, type %2, description: %3").arg(err.code()).arg(err.type()).arg(err.description())); if (!rpcErrorOccured(requestId, h, err)) { + QMutexLocker locker(&parserMapLock); parserMap.insert(requestId, h); return; } @@ -368,17 +387,23 @@ namespace _mtp_internal { } } catch (Exception &e) { if (!rpcErrorOccured(requestId, h, rpcClientError("RESPONSE_PARSE_FAILED", QString("exception text: ") + e.what()))) { + QMutexLocker locker(&parserMapLock); parserMap.insert(requestId, h); return; } } - requestMap.remove(requestId); } else { DEBUG_LOG(("RPC Info: parser not found for %1").arg(requestId)); } unregisterRequest(requestId); } + bool hasCallbacks(mtpRequestId requestId) { + QMutexLocker locker(&parserMapLock); + ParserMap::iterator i = parserMap.find(requestId); + return (i != parserMap.cend()); + } + void globalCallback(const mtpPrime *from, const mtpPrime *end) { if (globalHandler.onDone) (*globalHandler.onDone)(0, from, end); // some updates were received } diff --git a/Telegram/SourceFiles/mtproto/mtp.h b/Telegram/SourceFiles/mtproto/mtp.h index a815f229f8..a18d8c0f10 100644 --- a/Telegram/SourceFiles/mtproto/mtp.h +++ b/Telegram/SourceFiles/mtproto/mtp.h @@ -36,6 +36,7 @@ namespace _mtp_internal { void clearCallbacksDelayed(const RPCCallbackClears &requestIds); void performDelayedClear(); void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end); + bool hasCallbacks(mtpRequestId requestId); void globalCallback(const mtpPrime *from, const mtpPrime *end); void onStateChange(int32 dc, int32 state); void onSessionReset(int32 dc); @@ -58,9 +59,19 @@ namespace MTP { mtpAuthKey &localKey(); void createLocalKey(const QByteArray &pass, QByteArray *salt = 0); - static const uint32 dld = 1 * _mtp_internal::dcShift; // send(req, callbacks, MTP::dld + dc) - for download - static const uint32 upl = 2 * _mtp_internal::dcShift; // send(req, callbacks, MTP::upl + dc) - for upload - static const uint32 cfg = 3 * _mtp_internal::dcShift; // send(MTPhelp_GetConfig(), MTP::cfg + dc) - for dc enum + static const uint32 cfg = 1 * _mtp_internal::dcShift; // send(MTPhelp_GetConfig(), MTP::cfg + dc) - for dc enum + static const uint32 dld[MTPDownloadSessionsCount] = { // send(req, callbacks, MTP::dld[i] + dc) - for download + 0x10 * _mtp_internal::dcShift, + 0x11 * _mtp_internal::dcShift, + 0x12 * _mtp_internal::dcShift, + 0x13 * _mtp_internal::dcShift, + }; + static const uint32 upl[MTPUploadSessionsCount] = { // send(req, callbacks, MTP::upl[i] + dc) - for upload + 0x20 * _mtp_internal::dcShift, + 0x21 * _mtp_internal::dcShift, + 0x22 * _mtp_internal::dcShift, + 0x23 * _mtp_internal::dcShift, + }; void start(); void restart(); diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp index f84c4ffe3a..dc678f483d 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.cpp +++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp @@ -679,6 +679,15 @@ void MTPautoConnection::tcpSend(mtpBuffer &buffer) { TCP_LOG(("TCP Info: write %1 packet %2 bytes").arg(packetNum).arg(len)); sock.write((const char*)&buffer[0], len); + //int64 b = sock.bytesToWrite(); + //if (b > 100000) { + // int a = 0; + //} + //sock.flush(); + //int64 b2 = sock.bytesToWrite(); + //if (b2 > 0) { + // TCP_LOG(("TCP Info: writing many, %1 left to write").arg(b2)); + //} } void MTPautoConnection::httpSend(mtpBuffer &buffer) { @@ -1576,6 +1585,11 @@ void MTProtoConnectionPrivate::onSentSome(uint64 size) { DEBUG_LOG(("Checking connect for request with size %1 bytes, delay will be %2").arg(size).arg(remain)); } } + if (dc >= MTP::upl[0] && dc < MTP::upl[MTPUploadSessionsCount - 1] + _mtp_internal::dcShift) { + remain *= MTPUploadSessionsCount; + } else if (dc >= MTP::dld[0] && dc < MTP::dld[MTPDownloadSessionsCount - 1] + _mtp_internal::dcShift) { + remain *= MTPDownloadSessionsCount; + } connCheckTimer.start(remain); } if (!firstSentAt) firstSentAt = getms(); @@ -2070,15 +2084,19 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(reqMsgId)); return (badTime ? 0 : 1); } - if (serverSalt) sessionData->setSalt(serverSalt); // requestsFixTimeSalt with no lookup - unixtimeSet(serverTime, true); + if (badTime) { + if (serverSalt) sessionData->setSalt(serverSalt); // requestsFixTimeSalt with no lookup + unixtimeSet(serverTime, true); - DEBUG_LOG(("Message Info: unixtime updated from mtpc_msgs_state_info, now %1").arg(serverTime)); + DEBUG_LOG(("Message Info: unixtime updated from mtpc_msgs_state_info, now %1").arg(serverTime)); - badTime = false; + badTime = false; + } requestBuffer = replyTo.value(); } - QVector toAck(1, MTP_long(reqMsgId)); + QVector toAckReq(1, MTP_long(reqMsgId)), toAck; + requestsAcked(toAck, true); + if (requestBuffer->size() < 9) { LOG(("Message Error: bad request %1 found in requestMap, size: %2").arg(reqMsgId).arg(requestBuffer->size())); return -1; @@ -2207,7 +2225,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt return 0; } } - requestsAcked(ids); + requestsAcked(ids, true); if (typeId == mtpc_gzip_packed) { DEBUG_LOG(("RPC Info: gzip container")); @@ -2294,7 +2312,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt return 0; } } - requestsAcked(ids); + requestsAcked(ids, true); retryTimeout = 1; // reset restart() timer } return 1; @@ -2385,7 +2403,7 @@ bool MTProtoConnectionPrivate::requestsFixTimeSalt(const QVector &ids, return false; } -void MTProtoConnectionPrivate::requestsAcked(const QVector &ids) { +void MTProtoConnectionPrivate::requestsAcked(const QVector &ids, bool byResponse) { uint32 idsCount = ids.size(); DEBUG_LOG(("Message Info: requests acked, ids %1").arg(logVectorLong(ids))); @@ -2412,10 +2430,20 @@ void MTProtoConnectionPrivate::requestsAcked(const QVector &ids) { for (uint32 j = 0; j < inContCount; ++j) { toAckMore.push_back(MTP_long(*(inContId++))); } + haveSent.erase(req); } else { - wereAcked.insert(msgId, req.value()->requestId); + mtpRequestId reqId = req.value()->requestId; + bool moveToAcked = byResponse; + if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler) + moveToAcked = !_mtp_internal::hasCallbacks(reqId); + } + if (moveToAcked) { + wereAcked.insert(msgId, reqId); + haveSent.erase(req); + } else { + DEBUG_LOG(("Message Info: ignoring ACK for msgId %1 because request %2 requires a response").arg(msgId).arg(reqId)); + } } - haveSent.erase(req); } else { DEBUG_LOG(("Message Info: msgId %1 was not found in recent sent, while acking requests, searching in resend..").arg(msgId)); QWriteLocker locker3(sessionData->toResendMutex()); @@ -2423,21 +2451,29 @@ void MTProtoConnectionPrivate::requestsAcked(const QVector &ids) { mtpRequestIdsMap::iterator reqIt = toResend.find(msgId); if (reqIt != toResend.cend()) { mtpRequestId reqId = reqIt.value(); - QWriteLocker locker4(sessionData->toSendMutex()); - mtpPreRequestMap &toSend(sessionData->toSendMap()); - mtpPreRequestMap::iterator req = toSend.find(reqId); - if (req != toSend.cend()) { - wereAcked.insert(msgId, req.value()->requestId); - if (req.value()->requestId != reqId) { - DEBUG_LOG(("Message Error: for msgId %1 found resent request, requestId %2, contains requestId %3").arg(msgId).arg(reqId).arg(req.value()->requestId)); - } else { - DEBUG_LOG(("Message Info: acked msgId %1 that was prepared to resend, requestId %2").arg(msgId).arg(reqId)); - } - toSend.erase(req); - } else { - DEBUG_LOG(("Message Info: msgId %1 was found in recent resent, requestId %2 was not found in prepared to send").arg(msgId)); + bool moveToAcked = byResponse; + if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler) + moveToAcked = !_mtp_internal::hasCallbacks(reqId); + } + if (moveToAcked) { + QWriteLocker locker4(sessionData->toSendMutex()); + mtpPreRequestMap &toSend(sessionData->toSendMap()); + mtpPreRequestMap::iterator req = toSend.find(reqId); + if (req != toSend.cend()) { + wereAcked.insert(msgId, req.value()->requestId); + if (req.value()->requestId != reqId) { + DEBUG_LOG(("Message Error: for msgId %1 found resent request, requestId %2, contains requestId %3").arg(msgId).arg(reqId).arg(req.value()->requestId)); + } else { + DEBUG_LOG(("Message Info: acked msgId %1 that was prepared to resend, requestId %2").arg(msgId).arg(reqId)); + } + toSend.erase(req); + } else { + DEBUG_LOG(("Message Info: msgId %1 was found in recent resent, requestId %2 was not found in prepared to send").arg(msgId)); + } + toResend.erase(reqIt); + } else { + DEBUG_LOG(("Message Info: ignoring ACK for msgId %1 because request %2 requires a response").arg(msgId).arg(reqId)); } - toResend.erase(reqIt); } else { DEBUG_LOG(("Message Info: msgId %1 was not found in recent resent either").arg(msgId)); } diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.h b/Telegram/SourceFiles/mtproto/mtpConnection.h index 9d384d87b9..c76411c290 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.h +++ b/Telegram/SourceFiles/mtproto/mtpConnection.h @@ -374,7 +374,7 @@ private: bool requestsFixTimeSalt(const QVector &ids, int32 serverTime, uint64 serverSalt); // remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked - void requestsAcked(const QVector &ids); + void requestsAcked(const QVector &ids, bool byResponse = false); mtpPingId pingId, toSendPingId; mtpMsgId pingMsgId; diff --git a/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp b/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp index 0cd8b82422..91fef4707c 100644 --- a/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp +++ b/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp @@ -57,8 +57,10 @@ void mtpTextSerializeCore(MTPStringLogger &to, const mtpPrime *&from, const mtpP QString str = QString::fromUtf8(strUtf8); if (str.toUtf8() == strUtf8) { to.add("\"").add(str.replace('\\', "\\\\").replace('"', "\\\"").replace('\n', "\\n")).add("\" [STRING]"); - } else { + } else if (strUtf8.size() < 64) { to.add(mb(strUtf8.constData(), strUtf8.size()).str()).add(" [").add(mtpWrapNumber(strUtf8.size())).add(" BYTES]"); + } else { + to.add(mb(strUtf8.constData(), 16).str()).add(".. [").add(mtpWrapNumber(strUtf8.size())).add(" BYTES]"); } } break; diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp index 735a641764..af7289cca7 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp @@ -19,8 +19,17 @@ Copyright (c) 2014 John Preston, https://tdesktop.com #include "mainwidget.h" #include "window.h" +#include "application.h" + namespace { int32 _priority = 1; + struct DataRequested { + DataRequested() { + memset(v, 0, sizeof(v)); + } + int64 v[MTPDownloadSessionsCount]; + }; + QMap _dataRequested; } struct mtpFileLoaderQueue { mtpFileLoaderQueue() : queries(0), start(0), end(0) { @@ -34,10 +43,10 @@ namespace { LoaderQueues queues; } -mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret) : prev(0), next(0), - priority(0), inQueue(false), complete(false), requestId(0), - dc(dc), locationType(0), volume(volume), local(local), secret(secret), - id(0), access(0), initialSize(0), size(0), type(MTP_storage_fileUnknown()) { +mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) : prev(0), next(0), +priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false), +dc(dc), locationType(0), volume(volume), local(local), secret(secret), +id(0), access(0), size(size), type(MTP_storage_fileUnknown()) { LoaderQueues::iterator i = queues.find(dc); if (i == queues.cend()) { i = queues.insert(dc, mtpFileLoaderQueue()); @@ -46,23 +55,23 @@ mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const i } mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size) : prev(0), next(0), -priority(0), inQueue(false), complete(false), requestId(0), +priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false), dc(dc), locationType(locType), -id(id), access(access), file(to), duplicateInData(false), initialSize(size), type(MTP_storage_fileUnknown()) { - LoaderQueues::iterator i = queues.find(MTP::dld + dc); +id(id), access(access), file(to), duplicateInData(false), size(size), type(MTP_storage_fileUnknown()) { + LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc); if (i == queues.cend()) { - i = queues.insert(MTP::dld + dc, mtpFileLoaderQueue()); + i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue()); } queue = &i.value(); } mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size, bool todata) : prev(0), next(0), -priority(0), inQueue(false), complete(false), requestId(0), +priority(0), inQueue(false), complete(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false), dc(dc), locationType(locType), -id(id), access(access), file(to), duplicateInData(todata), initialSize(size), type(MTP_storage_fileUnknown()) { - LoaderQueues::iterator i = queues.find(MTP::dld + dc); +id(id), access(access), file(to), duplicateInData(todata), size(size), type(MTP_storage_fileUnknown()) { + LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc); if (i == queues.cend()) { - i = queues.insert(MTP::dld + dc, mtpFileLoaderQueue()); + i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue()); } queue = &i.value(); } @@ -89,8 +98,8 @@ float64 mtpFileLoader::currentProgress() const { return float64(currentOffset()) / fullSize(); } -int32 mtpFileLoader::currentOffset() const { - return file.isOpen() ? file.size() : data.size(); +int32 mtpFileLoader::currentOffset(bool includeSkipped) const { + return (file.isOpen() ? file.size() : data.size()) - (includeSkipped ? 0 : skippedBytes); } int32 mtpFileLoader::fullSize() const { @@ -109,17 +118,18 @@ uint64 mtpFileLoader::objId() const { void mtpFileLoader::loadNext() { if (queue->queries >= MaxFileQueries) return; - for (mtpFileLoader *i = queue->start; i; i = i->next) { - if (i->loadPart() && queue->queries >= MaxFileQueries) return; + for (mtpFileLoader *i = queue->start; i;) { + if (i->loadPart()) { + if (queue->queries >= MaxFileQueries) return; + } else { + i = i->next; + } } } void mtpFileLoader::finishFail() { - bool started = currentOffset() > 0; - if (requestId) { - requestId = 0; - --queue->queries; - } + bool started = currentOffset(true) > 0; + cancelRequests(); type = MTP_storage_fileUnknown(); complete = true; if (file.isOpen()) { @@ -133,7 +143,8 @@ void mtpFileLoader::finishFail() { } bool mtpFileLoader::loadPart() { - if (complete || requestId) return false; + if (complete || lastComplete || !requests.isEmpty() && !size) return false; + if (size && nextRequestOffset >= size) return false; int32 limit = DocumentDownloadPartSize; MTPInputFileLocation loc; @@ -148,54 +159,100 @@ bool mtpFileLoader::loadPart() { break; } - ++queue->queries; - int32 offset = currentOffset(); + int32 offset = nextRequestOffset, dcIndex = 0; + DataRequested &dr(_dataRequested[dc]); + if (size) { + for (int32 i = 1; i < MTPDownloadSessionsCount; ++i) { + if (dr.v[i] < dr.v[dcIndex]) { + dcIndex = i; + } + } + } + + if (dcIndex) { + App::app()->killDownloadSessionsStop(dc); + } + MTPupload_GetFile request(MTPupload_getFile(loc, MTP_int(offset), MTP_int(limit))); - requestId = MTP::send(request, rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld + dc, 50); + mtpRequestId reqId = MTP::send(request, rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dld[dcIndex] + dc, 50); + + ++queue->queries; + dr.v[dcIndex] += limit; + requests.insert(reqId, dcIndex); + nextRequestOffset += limit; + return true; } -void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result) { - if (requestId) { - --queue->queries; - requestId = 0; - } - if (offset == currentOffset()) { - int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize; - const MTPDupload_file &d(result.c_upload_file()); - const string &bytes(d.vbytes.c_string().v); - if (bytes.size()) { - if (file.isOpen()) { - if (file.write(bytes.data(), bytes.size()) != qint64(bytes.size())) { - return finishFail(); - } - } else { - data.append(bytes.data(), bytes.size()); +void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req) { + Requests::iterator i = requests.find(req); + if (i == requests.cend()) return; + + int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize; + int32 dcIndex = i.value(); + _dataRequested[dc].v[dcIndex] -= limit; + + --queue->queries; + requests.erase(i); + + const MTPDupload_file &d(result.c_upload_file()); + const string &bytes(d.vbytes.c_string().v); + if (bytes.size()) { + if (file.isOpen()) { + int64 fsize = file.size(); + if (offset < fsize) { + skippedBytes -= bytes.size(); + } else if (offset > fsize) { + skippedBytes += offset - fsize; + } + file.seek(offset); + if (file.write(bytes.data(), bytes.size()) != qint64(bytes.size())) { + return finishFail(); } - } - if (bytes.size() && !(bytes.size() % 1024)) { // good next offset -// offset += bytes.size(); } else { - if (duplicateInData && !file.fileName().isEmpty()) { - if (!file.open(QIODevice::WriteOnly)) { - return finishFail(); - } - if (file.write(data) != qint64(data.size())) { - return finishFail(); - } + data.reserve(offset + bytes.size()); + if (offset > data.size()) { + skippedBytes += offset - data.size(); + data.resize(offset); } - type = d.vtype; - complete = true; - if (file.isOpen()) { - file.close(); - psPostprocessFile(QFileInfo(file).absoluteFilePath()); + if (offset == data.size()) { + data.append(bytes.data(), bytes.size()); + } else { + skippedBytes -= bytes.size(); + if (offset + bytes.size() > data.size()) { + data.resize(offset + bytes.size()); + } + memcpy(data.data() + offset, bytes.data(), bytes.size()); } - removeFromQueue(); - App::wnd()->update(); - App::wnd()->notifyUpdateAllPhotos(); } - emit progress(this); } + if (!bytes.size() || (bytes.size() % 1024)) { // bad next offset + lastComplete = true; + } + if (requests.isEmpty() && (lastComplete || (size && nextRequestOffset >= size))) { + if (duplicateInData && !file.fileName().isEmpty()) { + if (!file.open(QIODevice::WriteOnly)) { + return finishFail(); + } + if (file.write(data) != qint64(data.size())) { + return finishFail(); + } + } + type = d.vtype; + complete = true; + if (file.isOpen()) { + file.close(); + psPostprocessFile(QFileInfo(file).absoluteFilePath()); + } + removeFromQueue(); + App::wnd()->update(); + App::wnd()->notifyUpdateAllPhotos(); + + if (!queue->queries && dcIndex) { + App::app()->killDownloadSessionsStart(dc); + } + } + emit progress(this); loadNext(); } @@ -325,11 +382,7 @@ void mtpFileLoader::start(bool loadFirst, bool prior) { } void mtpFileLoader::cancel() { - bool started = currentOffset() > 0; - if (requestId) { - requestId = 0; - --queue->queries; - } + cancelRequests(); type = MTP_storage_fileUnknown(); complete = true; if (file.isOpen()) { @@ -342,6 +395,26 @@ void mtpFileLoader::cancel() { loadNext(); } +void mtpFileLoader::cancelRequests() { + if (requests.isEmpty()) return; + + int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize; + bool wasIndex = false; + DataRequested &dr(_dataRequested[dc]); + for (Requests::const_iterator i = requests.cbegin(), e = requests.cend(); i != e; ++i) { + MTP::cancel(i.key()); + int32 dcIndex = i.value(); + dr.v[dcIndex] -= limit; + if (dcIndex) wasIndex = true; + } + queue->queries -= requests.size(); + requests.clear(); + + if (!queue->queries && wasIndex) { + App::app()->killDownloadSessionsStart(dc); + } +} + bool mtpFileLoader::loading() const { return inQueue; } @@ -353,6 +426,7 @@ void mtpFileLoader::started(bool loadFirst, bool prior) { mtpFileLoader::~mtpFileLoader() { removeFromQueue(); + cancelRequests(); } namespace MTP { diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.h b/Telegram/SourceFiles/mtproto/mtpFileLoader.h index c8b7b7f7b3..287fd67f99 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.h +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.h @@ -27,7 +27,7 @@ class mtpFileLoader : public QObject, public RPCSender { public: - mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret); + mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0); mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size); mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size, bool todata); bool done() const; @@ -35,7 +35,7 @@ public: const QByteArray &bytes() const; QString fileName() const; float64 currentProgress() const; - int32 currentOffset() const; + int32 currentOffset(bool includeSkipped = false) const; int32 fullSize() const; void setFileName(const QString &filename); // set filename for duplicateInData loader @@ -61,14 +61,22 @@ private: mtpFileLoaderQueue *queue; bool inQueue, complete; - int32 requestId; + + void cancelRequests(); + + typedef QMap Requests; + Requests requests; + int32 skippedBytes; + int32 nextRequestOffset; + bool lastComplete; + void started(bool loadFirst, bool prior); void removeFromQueue(); void loadNext(); void finishFail(); bool loadPart(); - void partLoaded(int32 offset, const MTPupload_File &result); + void partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req); bool partFailed(const RPCError &error); int32 dc; @@ -82,7 +90,6 @@ private: uint64 access; QFile file; bool duplicateInData; - int32 initialSize; QByteArray data; diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp index 398c745f16..b497f9f45b 100644 --- a/Telegram/SourceFiles/types.cpp +++ b/Telegram/SourceFiles/types.cpp @@ -123,6 +123,7 @@ void unixtimeSet(int32 serverTime, bool force) { } unixtimeWasSet = true; unixtimeDelta = serverTime + 1 - myunixtime(); + DEBUG_LOG(("MTP Info: now unixtimeDelta is %1").arg(unixtimeDelta)); } _initMsgIdConstants(); } diff --git a/Telegram/Telegram.plist b/Telegram/Telegram.plist index 050f197398..8b8072950b 100644 --- a/Telegram/Telegram.plist +++ b/Telegram/Telegram.plist @@ -11,7 +11,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.6.5 + 0.6.6 CFBundleSignature ???? NOTE diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc index 2aa544ded5..2e7db65e68 100644 Binary files a/Telegram/Telegram.rc and b/Telegram/Telegram.rc differ diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index e2d9d46201..4f21906d79 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -1515,7 +1515,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 0.6.5; + CURRENT_PROJECT_VERSION = 0.6.6; DEBUG_INFORMATION_FORMAT = dwarf; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -1533,7 +1533,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 0.6.5; + CURRENT_PROJECT_VERSION = 0.6.6; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = fast; GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h; @@ -1559,10 +1559,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 0.6.5; + CURRENT_PROJECT_VERSION = 0.6.6; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 0.6; - DYLIB_CURRENT_VERSION = 0.6.5; + DYLIB_CURRENT_VERSION = 0.6.6; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -1701,10 +1701,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 0.6.5; + CURRENT_PROJECT_VERSION = 0.6.6; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 0.6; - DYLIB_CURRENT_VERSION = 0.6.5; + DYLIB_CURRENT_VERSION = 0.6.6; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = YES;