mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-09-06 01:16:12 +00:00
initial commit for 0.4.18 version of Telegram Desktop
This commit is contained in:
333
Telegram/SourceFiles/mtproto/mtpFileLoader.cpp
Normal file
333
Telegram/SourceFiles/mtproto/mtpFileLoader.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
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.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
namespace {
|
||||
int32 _priority = 1;
|
||||
}
|
||||
struct mtpFileLoaderQueue {
|
||||
mtpFileLoaderQueue() : queries(0), start(0), end(0) {
|
||||
}
|
||||
int32 queries;
|
||||
mtpFileLoader *start, *end;
|
||||
};
|
||||
|
||||
namespace {
|
||||
typedef QMap<int32, mtpFileLoaderQueue> LoaderQueues;
|
||||
LoaderQueues queues;
|
||||
}
|
||||
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret) : next(0), prev(0), inQueue(false), complete(false), requestId(0), priority(0), initialSize(0),
|
||||
dc(dc), volume(volume), local(local), secret(secret), size(0), type(MTP_storage_fileUnknown()), locationType(0), id(0), access(0) {
|
||||
LoaderQueues::iterator i = queues.find(dc);
|
||||
if (i == queues.cend()) {
|
||||
i = queues.insert(dc, mtpFileLoaderQueue());
|
||||
}
|
||||
queue = &i.value();
|
||||
}
|
||||
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size) : next(0), prev(0), inQueue(false), complete(false), requestId(0), priority(0),
|
||||
dc(dc), id(id), access(access), type(MTP_storage_fileUnknown()), locationType(locType), file(to), initialSize(size) {
|
||||
LoaderQueues::iterator i = queues.find(MTP::dld + dc);
|
||||
if (i == queues.cend()) {
|
||||
i = queues.insert(MTP::dld + dc, mtpFileLoaderQueue());
|
||||
}
|
||||
queue = &i.value();
|
||||
}
|
||||
|
||||
QString mtpFileLoader::fileName() const {
|
||||
return file.fileName();
|
||||
}
|
||||
|
||||
bool mtpFileLoader::done() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
mtpTypeId mtpFileLoader::fileType() const {
|
||||
return type.type();
|
||||
}
|
||||
|
||||
const QByteArray &mtpFileLoader::bytes() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
float64 mtpFileLoader::currentProgress() const {
|
||||
if (complete) return 1;
|
||||
if (!fullSize()) return 0;
|
||||
return float64(currentOffset()) / fullSize();
|
||||
}
|
||||
|
||||
int32 mtpFileLoader::currentOffset() const {
|
||||
return file.isOpen() ? file.size() : data.size();
|
||||
}
|
||||
|
||||
int32 mtpFileLoader::fullSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
uint64 mtpFileLoader::objId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
void mtpFileLoader::loadNext() {
|
||||
if (queue->queries >= MaxFileQueries) return;
|
||||
for (mtpFileLoader *i = queue->start; i; i = i->next) {
|
||||
if (i->loadPart() && queue->queries >= MaxFileQueries) return;
|
||||
}
|
||||
}
|
||||
|
||||
void mtpFileLoader::finishFail() {
|
||||
bool started = currentOffset() > 0;
|
||||
if (requestId) {
|
||||
requestId = 0;
|
||||
--queue->queries;
|
||||
}
|
||||
type = MTP_storage_fileUnknown();
|
||||
complete = true;
|
||||
if (file.isOpen()) {
|
||||
file.close();
|
||||
file.remove();
|
||||
}
|
||||
data = QByteArray();
|
||||
emit failed(this, started);
|
||||
file.setFileName(QString());
|
||||
loadNext();
|
||||
}
|
||||
|
||||
bool mtpFileLoader::loadPart() {
|
||||
if (complete || requestId) return false;
|
||||
|
||||
int32 limit = DocumentDownloadPartSize;
|
||||
MTPInputFileLocation loc;
|
||||
switch (locationType) {
|
||||
case 0: loc = MTP_inputFileLocation(MTP_long(volume), MTP_int(local), MTP_long(secret)); limit = DownloadPartSize; break;
|
||||
case mtpc_inputVideoFileLocation: loc = MTP_inputVideoFileLocation(MTP_long(id), MTP_long(access)); break;
|
||||
case mtpc_inputAudioFileLocation: loc = MTP_inputAudioFileLocation(MTP_long(id), MTP_long(access)); break;
|
||||
case mtpc_inputDocumentFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(id), MTP_long(access)); break;
|
||||
default:
|
||||
finishFail();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
++queue->queries;
|
||||
int32 offset = currentOffset();
|
||||
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);
|
||||
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()) != bytes.size()) {
|
||||
return finishFail();
|
||||
}
|
||||
} else {
|
||||
data.append(bytes.data(), bytes.size());
|
||||
}
|
||||
}
|
||||
if (bytes.size() && !(bytes.size() % 1024)) { // good next offset
|
||||
// offset += bytes.size();
|
||||
} else {
|
||||
type = d.vtype;
|
||||
complete = true;
|
||||
if (file.isOpen()) {
|
||||
file.close();
|
||||
psPostprocessFile(QFileInfo(file).absoluteFilePath());
|
||||
}
|
||||
removeFromQueue();
|
||||
App::wnd()->update();
|
||||
App::wnd()->psUpdateNotifies();
|
||||
}
|
||||
emit progress(this);
|
||||
}
|
||||
loadNext();
|
||||
}
|
||||
|
||||
bool mtpFileLoader::partFailed(const RPCError &error) {
|
||||
finishFail();
|
||||
return true;
|
||||
}
|
||||
|
||||
void mtpFileLoader::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 mtpFileLoader::pause() {
|
||||
removeFromQueue();
|
||||
}
|
||||
|
||||
void mtpFileLoader::start(bool loadFirst, bool prior) {
|
||||
if (complete) return;
|
||||
|
||||
if (!file.fileName().isEmpty()) {
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
finishFail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mtpFileLoader *before = 0, *after = 0;
|
||||
if (prior) {
|
||||
if (inQueue && priority == _priority) {
|
||||
if (loadFirst) {
|
||||
if (!prev) return started(loadFirst, prior);
|
||||
before = queue->start;
|
||||
} else {
|
||||
if (!next || next->priority < _priority) return started(loadFirst, prior);
|
||||
after = next;
|
||||
while (after->next && after->next->priority == _priority) {
|
||||
after = after->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
priority = _priority;
|
||||
if (loadFirst) {
|
||||
if (inQueue && !prev) return started(loadFirst, prior);
|
||||
before = queue->start;
|
||||
} else {
|
||||
if (inQueue) {
|
||||
if (next && next->priority == _priority) {
|
||||
after = next;
|
||||
} else if (prev && prev->priority < _priority) {
|
||||
before = prev;
|
||||
while (before->prev && before->prev->priority < _priority) {
|
||||
before = before->prev;
|
||||
}
|
||||
} else {
|
||||
return started(loadFirst, prior);
|
||||
}
|
||||
} else {
|
||||
if (queue->start && queue->start->priority == _priority) {
|
||||
after = queue->start;
|
||||
} else {
|
||||
before = queue->start;
|
||||
}
|
||||
}
|
||||
if (after) {
|
||||
while (after->next && after->next->priority == _priority) {
|
||||
after = after->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (loadFirst) {
|
||||
if (inQueue && (!prev || prev->priority == _priority)) return started(loadFirst, prior);
|
||||
before = prev;
|
||||
while (before->prev && before->prev->priority != _priority) {
|
||||
before = before->prev;
|
||||
}
|
||||
} else {
|
||||
if (inQueue && !next) return started(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;
|
||||
}
|
||||
} else {
|
||||
LOG(("Queue Error: _start && !before && !after"));
|
||||
}
|
||||
return started(loadFirst, prior);
|
||||
}
|
||||
|
||||
void mtpFileLoader::cancel() {
|
||||
bool started = currentOffset() > 0;
|
||||
if (requestId) {
|
||||
requestId = 0;
|
||||
--queue->queries;
|
||||
}
|
||||
type = MTP_storage_fileUnknown();
|
||||
complete = true;
|
||||
if (file.isOpen()) {
|
||||
file.close();
|
||||
file.remove();
|
||||
}
|
||||
data = QByteArray();
|
||||
file.setFileName(QString());
|
||||
emit progress(this);
|
||||
loadNext();
|
||||
}
|
||||
|
||||
bool mtpFileLoader::loading() const {
|
||||
return inQueue;
|
||||
}
|
||||
|
||||
void mtpFileLoader::started(bool loadFirst, bool prior) {
|
||||
if (queue->queries >= MaxFileQueries && (!loadFirst || !prior) || complete) return;
|
||||
loadPart();
|
||||
}
|
||||
|
||||
mtpFileLoader::~mtpFileLoader() {
|
||||
removeFromQueue();
|
||||
}
|
||||
|
||||
namespace MTP {
|
||||
void clearLoaderPriorities() {
|
||||
++_priority;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user