Skip to content

Commit

Permalink
preparing for loading photos from local in other thread
Browse files Browse the repository at this point in the history
  • Loading branch information
john-preston committed Sep 29, 2015
1 parent d5e5ef2 commit 592e3f7
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 114 deletions.
23 changes: 0 additions & 23 deletions Telegram/SourceFiles/gui/images.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,29 +327,6 @@ inline bool operator!=(const FileLocation &a, const FileLocation &b) {
return !(a == b);
}

enum LocationType {
UnknownFileLocation = 0,
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
};
inline LocationType mtpToLocationType(mtpTypeId type) {
switch (type) {
case mtpc_inputDocumentFileLocation: return DocumentFileLocation;
case mtpc_inputAudioFileLocation: return AudioFileLocation;
case mtpc_inputVideoFileLocation: return VideoFileLocation;
default: return UnknownFileLocation;
}
}
inline mtpTypeId mtpFromLocationType(LocationType type) {
switch (type) {
case DocumentFileLocation: return mtpc_inputDocumentFileLocation;
case AudioFileLocation: return mtpc_inputAudioFileLocation;
case VideoFileLocation: return mtpc_inputVideoFileLocation;
case UnknownFileLocation:
default: return 0;
}
}
typedef QPair<uint64, uint64> MediaKey;
inline uint64 mediaMix32To64(int32 a, int32 b) {
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
Expand Down
24 changes: 24 additions & 0 deletions Telegram/SourceFiles/localstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,14 @@ namespace Local {
}
}

bool startImageLoad(const StorageKey &location) {
StorageMap::iterator j = _imagesMap.find(location);
if (j == _imagesMap.cend()) {
return false;
}
return true;
}

StorageImageSaved readImage(const StorageKey &location) {
StorageMap::iterator j = _imagesMap.find(location);
if (j == _imagesMap.cend()) {
Expand Down Expand Up @@ -2325,6 +2333,14 @@ namespace Local {
}
}

bool startStickerImageLoad(const StorageKey &location) {
StorageMap::iterator j = _stickerImagesMap.find(location);
if (j == _stickerImagesMap.cend()) {
return false;
}
return true;
}

QByteArray readStickerImage(const StorageKey &location) {
StorageMap::iterator j = _stickerImagesMap.find(location);
if (j == _stickerImagesMap.cend()) {
Expand Down Expand Up @@ -2377,6 +2393,14 @@ namespace Local {
}
}

bool startAudioLoad(const StorageKey &location) {
StorageMap::iterator j = _audiosMap.find(location);
if (j == _audiosMap.cend()) {
return false;
}
return true;
}

QByteArray readAudio(const StorageKey &location) {
StorageMap::iterator j = _audiosMap.find(location);
if (j == _audiosMap.cend()) {
Expand Down
3 changes: 3 additions & 0 deletions Telegram/SourceFiles/localstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,19 @@ namespace Local {

void writeImage(const StorageKey &location, const ImagePtr &img);
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
bool startImageLoad(const StorageKey &location);
StorageImageSaved readImage(const StorageKey &location);
int32 hasImages();
qint64 storageImagesSize();

void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
bool startStickerImageLoad(const StorageKey &location);
QByteArray readStickerImage(const StorageKey &location);
int32 hasStickers();
qint64 storageStickersSize();

void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
bool startAudioLoad(const StorageKey &location);
QByteArray readAudio(const StorageKey &location);
int32 hasAudios();
qint64 storageAudiosSize();
Expand Down
169 changes: 91 additions & 78 deletions Telegram/SourceFiles/mtproto/mtpFileLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ namespace {
}

mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &volume, int32 local, const uint64 &secret, int32 size) : prev(0), next(0),
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), locationType(0), volume(volume), local(local), secret(secret),
priority(0), inQueue(false), complete(false),
_localStatus(LocalNotTried), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), _locationType(UnknownFileLocation), volume(volume), local(local), secret(secret),
id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown) {
LoaderQueues::iterator i = queues.find(dc);
if (i == queues.cend()) {
Expand All @@ -55,20 +56,10 @@ id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown)
queue = &i.value();
}

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), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), locationType(locType), volume(0), local(0), secret(0),
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(false), size(size), type(mtpc_storage_fileUnknown) {
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
if (i == queues.cend()) {
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), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), locationType(locType), volume(0), local(0), secret(0),
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, LocationType type, const QString &to, int32 size, bool todata) : prev(0), next(0),
priority(0), inQueue(false), complete(false),
_localStatus(LocalNotTried), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), _locationType(type), volume(0), local(0), secret(0),
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(mtpc_storage_fileUnknown) {
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
if (i == queues.cend()) {
Expand Down Expand Up @@ -150,11 +141,20 @@ bool mtpFileLoader::loadPart() {

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;
switch (_locationType) {
case UnknownFileLocation:
loc = MTP_inputFileLocation(MTP_long(volume), MTP_int(local), MTP_long(secret));
limit = DownloadPartSize;
break;
case VideoFileLocation:
loc = MTP_inputVideoFileLocation(MTP_long(id), MTP_long(access));
break;
case AudioFileLocation:
loc = MTP_inputAudioFileLocation(MTP_long(id), MTP_long(access));
break;
case DocumentFileLocation:
loc = MTP_inputDocumentFileLocation(MTP_long(id), MTP_long(access));
break;
default:
finishFail();
return false;
Expand Down Expand Up @@ -188,7 +188,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
Requests::iterator i = requests.find(req);
if (i == requests.cend()) return loadNext();

int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize;
int32 limit = (_locationType == UnknownFileLocation) ? DownloadPartSize : DocumentDownloadPartSize;
int32 dcIndex = i.value();
_dataRequested[dc].v[dcIndex] -= limit;

Expand Down Expand Up @@ -254,24 +254,26 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
App::app()->killDownloadSessionsStart(dc);
}

if (!locationType && triedLocal && (fname.isEmpty() || duplicateInData)) {
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(mtpToStorageType(type), data));
} else if (locationType && triedLocal) {
if (!fname.isEmpty()) {
Local::writeFileLocation(mediaKey(mtpToLocationType(locationType), dc, id), FileLocation(mtpToStorageType(type), fname));
}
if (duplicateInData) {
if (locationType == mtpc_inputDocumentFileLocation) {
Local::writeStickerImage(mediaKey(mtpToLocationType(locationType), dc, id), data);
} else if (locationType == mtpc_inputAudioFileLocation) {
Local::writeAudio(mediaKey(mtpToLocationType(locationType), dc, id), data);
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
if (_locationType != UnknownFileLocation) { // audio, video, document
MediaKey mkey = mediaKey(_locationType, dc, id);
if (!fname.isEmpty()) {
Local::writeFileLocation(mkey, FileLocation(mtpToStorageType(type), fname));
}
if (duplicateInData) {
if (_locationType == DocumentFileLocation) {
Local::writeStickerImage(mkey, data);
} else if (_locationType == AudioFileLocation) {
Local::writeAudio(mkey, data);
}
}
} else {
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(mtpToStorageType(type), data));
}
}
}
emit progress(this);
loadNext();
// LOG(("Part loaded, handle time: %1").arg(getms() - ms));
}

bool mtpFileLoader::partFailed(const RPCError &error) {
Expand Down Expand Up @@ -303,54 +305,65 @@ void mtpFileLoader::pause() {
removeFromQueue();
}

void mtpFileLoader::start(bool loadFirst, bool prior) {
if (complete) return;
if (!triedLocal) {
if (!locationType) {
triedLocal = true;
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
if (cached.type != StorageFileUnknown) {
data = cached.data;
type = mtpFromStorageType(cached.type);
}
} else if (locationType) {
if (!fname.isEmpty()) {
triedLocal = true;
}
if (duplicateInData) {
if (locationType == mtpc_inputDocumentFileLocation) {
triedLocal = true;
data = Local::readStickerImage(mediaKey(mtpToLocationType(locationType), dc, id));
if (!data.isEmpty()) type = mtpc_storage_filePartial;
} else if (locationType == mtpc_inputAudioFileLocation) {
triedLocal = true;
data = Local::readAudio(mediaKey(mtpToLocationType(locationType), dc, id));
if (!data.isEmpty()) type = mtpc_storage_filePartial;
}
}
bool mtpFileLoader::tryLoadLocal() {
if (_localStatus == LocalNotFound || _localStatus == LocalLoaded || _localStatus == LocalFailed) {
return false;
}
if (_localStatus == LocalLoading) {
return true;
}

if (_locationType == UnknownFileLocation) {
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
if (cached.type != StorageFileUnknown) {
data = cached.data;
type = mtpFromStorageType(cached.type);
}
if (triedLocal && !data.isEmpty()) {
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
return finishFail();
}
if (file.write(data) != qint64(data.size())) {
return finishFail();
}
}
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
} else {
if (duplicateInData) {
MediaKey mkey = mediaKey(_locationType, dc, id);
if (_locationType == DocumentFileLocation) {
data = Local::readStickerImage(mkey);
if (!data.isEmpty()) type = mtpc_storage_filePartial;
} else if (_locationType == AudioFileLocation) {
data = Local::readAudio(mkey);
if (!data.isEmpty()) type = mtpc_storage_filePartial;
}
emit App::wnd()->imageLoaded();
emit progress(this);
return loadNext();
}
}

if (data.isEmpty()) {
_localStatus = LocalNotFound;
return false;
}

_localStatus = LocalLoaded;
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
finishFail();
return true;
}
if (file.write(data) != qint64(data.size())) {
finishFail();
return true;
}
}
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
}
emit App::wnd()->imageLoaded();
emit progress(this);
loadNext();
return true;
}

void mtpFileLoader::start(bool loadFirst, bool prior) {
if (complete || tryLoadLocal()) return;

if (!fname.isEmpty() && !duplicateInData && !fileIsOpen) {
fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
Expand Down Expand Up @@ -464,7 +477,7 @@ void mtpFileLoader::cancel() {
void mtpFileLoader::cancelRequests() {
if (requests.isEmpty()) return;

int32 limit = locationType ? DocumentDownloadPartSize : DownloadPartSize;
int32 limit = (_locationType == UnknownFileLocation) ? DownloadPartSize : DocumentDownloadPartSize;
DataRequested &dr(_dataRequested[dc]);
for (Requests::const_iterator i = requests.cbegin(), e = requests.cend(); i != e; ++i) {
MTP::cancel(i.key());
Expand Down
43 changes: 38 additions & 5 deletions Telegram/SourceFiles/mtproto/mtpFileLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,46 @@ namespace MTP {
void clearLoaderPriorities();
}

enum LocationType {
UnknownFileLocation = 0,
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
};
inline LocationType mtpToLocationType(mtpTypeId type) {
switch (type) {
case mtpc_inputDocumentFileLocation: return DocumentFileLocation;
case mtpc_inputAudioFileLocation: return AudioFileLocation;
case mtpc_inputVideoFileLocation: return VideoFileLocation;
default: return UnknownFileLocation;
}
}
inline mtpTypeId mtpFromLocationType(LocationType type) {
switch (type) {
case DocumentFileLocation: return mtpc_inputDocumentFileLocation;
case AudioFileLocation: return mtpc_inputAudioFileLocation;
case VideoFileLocation: return mtpc_inputVideoFileLocation;
case UnknownFileLocation:
default: return 0;
}
}

enum LocalLoadStatus {
LocalNotTried,
LocalNotFound,
LocalLoading,
LocalLoaded,
LocalFailed,
};

struct mtpFileLoaderQueue;
class mtpFileLoader : public QObject, public RPCSender {
Q_OBJECT

public:

mtpFileLoader(int32 dc, const uint64 &volume, int32 local, const uint64 &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);
mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, LocationType type, const QString &to, int32 size, bool todata = false);
bool done() const;
mtpTypeId fileType() const;
const QByteArray &bytes() const;
Expand Down Expand Up @@ -60,8 +91,10 @@ class mtpFileLoader : public QObject, public RPCSender {
private:

mtpFileLoaderQueue *queue;
bool inQueue, complete, triedLocal;

bool inQueue, complete;
LocalLoadStatus _localStatus;

bool tryLoadLocal();
void cancelRequests();

typedef QMap<mtpRequestId, int32> Requests;
Expand All @@ -80,7 +113,7 @@ class mtpFileLoader : public QObject, public RPCSender {
bool partFailed(const RPCError &error);

int32 dc;
mtpTypeId locationType; // 0 or mtpc_inputVideoFileLocation / mtpc_inputAudioFileLocation / mtpc_inputDocumentFileLocation
LocationType _locationType;

uint64 volume; // for photo locations
int32 local;
Expand Down
Loading

0 comments on commit 592e3f7

Please sign in to comment.