Skip to content

Commit

Permalink
RoomMessageEvent::temporaryPathToDownload()
Browse files Browse the repository at this point in the history
This is a former part of Room::downloadFile() that calculated the path
to a fallback temporary file when no file path is passed to it. Exposing
this logic in a separate API allows to access the file outside of
downloading sequence (e.g. place the temporary file there created after
pasting an attachment from clipboard or drag-n-drop).

(cherry picked from commit 36951bb)
  • Loading branch information
KitsuneRal committed Nov 29, 2024
1 parent e44d3a2 commit c8111de
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 45 deletions.
24 changes: 22 additions & 2 deletions Quotient/events/roommessageevent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

#include "roommessageevent.h"

#include "../logging_categories_p.h"
#include "eventrelation.h"

#include "../logging_categories_p.h"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QMimeDatabase>
#include <QtGui/QImageReader>
#include <QtCore/QStringBuilder>
#include <QtGui/QImageReader>

using namespace Quotient;
using namespace EventContent;
Expand Down Expand Up @@ -358,6 +360,24 @@ QString RoomMessageEvent::fileNameToDownload() const
return fileName;
}

QString RoomMessageEvent::temporaryPathToDownload() const {
if (!QUO_CHECK(has<EventContent::FileContentBase>()))
return {};

const auto fileInfo = get<EventContent::FileContentBase>()->commonInfo();
if (!fileInfo.isValid()) {
qCWarning(MAIN) << "Event" << id() << "has an empty or malformed mxc URL";
return {};
}
auto filePath = QString(fileInfo.url().path().mid(1) % u'_' % fileNameToDownload());

if (filePath.size() > 200) // If too long, elide in the middle
filePath.replace(128, filePath.size() - 192, "---"_L1);

filePath = QDir::tempPath() % u'/' % filePath;
return filePath;
}

void RoomMessageEvent::updateFileSourceInfo(const FileSourceInfo& fsi)
{
editSubobject(editJson(), ContentKey, [&fsi](QJsonObject& contentJson) {
Expand Down
5 changes: 5 additions & 0 deletions Quotient/events/roommessageevent.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ class QUOTIENT_API RoomMessageEvent : public RoomEvent {

QString fileNameToDownload() const;

//! \brief Get the default temporary path to download the file to
//!
//! The event must have content for downloading; the behaviour is undefined otherwise.
[[nodiscard]] QString temporaryPathToDownload() const;

void updateFileSourceInfo(const FileSourceInfo& fsi);

static QString rawMsgTypeForUrl(const QUrl& url);
Expand Down
75 changes: 32 additions & 43 deletions Quotient/room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ class Q_DECL_HIDDEN Room::Private {
/// used for both download and upload operations
QHash<QString, FileTransferPrivateInfo> fileTransfers;

const RoomMessageEvent* getEventWithFile(const QString& eventId) const;
std::pair<const RoomMessageEvent*, std::unique_ptr<const EventContent::FileContentBase>>
getEventWithFile(const QString& eventId) const;

Changes setSummary(RoomSummary&& newSummary);

Expand Down Expand Up @@ -1416,16 +1417,16 @@ QUrl Room::makeMediaUrl(const QString& eventId, const QUrl& mxcUrl) const
return url;
}

const RoomMessageEvent*
std::pair<const RoomMessageEvent*, std::unique_ptr<const EventContent::FileContentBase>>
Room::Private::getEventWithFile(const QString& eventId) const
{
if (auto evtIt = q->findInTimeline(eventId); evtIt != historyEdge())
if (auto* event = evtIt->viewAs<RoomMessageEvent>();
event && event->has<EventContent::FileContentBase>())
return event;
if (const auto* event = evtIt->viewAs<RoomMessageEvent>())
if (auto&& fileInfo = event->get<EventContent::FileContentBase>())
return { event, std::move(fileInfo) };

qCWarning(MAIN) << "No files to download in event" << eventId;
return nullptr;
return {};
}

QUrl Room::urlToThumbnail(const QString& eventId) const
Expand All @@ -1443,17 +1444,15 @@ QUrl Room::urlToThumbnail(const QString& eventId) const

QUrl Room::urlToDownload(const QString& eventId) const
{
if (const auto* const event = d->getEventWithFile(eventId)) {
if (const auto fileInfo = event->get<EventContent::FileContentBase>();
QUO_CHECK(fileInfo != nullptr))
return connection()->getUrlForApi<DownloadFileJob>(fileInfo->url());
}
if (const auto& [_, fileInfo] = d->getEventWithFile(eventId); fileInfo != nullptr)
return connection()->getUrlForApi<DownloadFileJob>(fileInfo->url());

return {};
}

QString Room::fileNameToDownload(const QString& eventId) const
{
if (auto* event = d->getEventWithFile(eventId))
if (const auto& [event, _] = d->getEventWithFile(eventId); event != nullptr)
return event->fileNameToDownload();
return {};
}
Expand Down Expand Up @@ -2447,38 +2446,28 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
<< "is ongoing; download won't start";
return;
}

Q_ASSERT_X(localFilename.isEmpty() || localFilename.isLocalFile(),
__FUNCTION__, "localFilename should point at a local file");
const auto* event = d->getEventWithFile(eventId);
if (QUO_ALARM_X(!event, eventId + " is not in the local timeline or has no file content"_L1))
if (QUO_ALARM_X(!localFilename.isEmpty() && !localFilename.isLocalFile(),
"localFilename should be empty or point at a local file"))
return;

const auto fileInfo = event->get<EventContent::FileContentBase>()->commonInfo();
if (!fileInfo.isValid()) {
qCWarning(MAIN) << "Event" << eventId
<< "has an empty or malformed mxc URL; won't download";
const auto& [event, fileInfo] = d->getEventWithFile(eventId);
if (QUO_ALARM_X(!event || !fileInfo,
eventId + " is not in the local timeline or has no file content"_L1))
return;
}
const auto fileUrl = fileInfo.url();
auto filePath = localFilename.toLocalFile();
if (filePath.isEmpty()) { // Setup default file path
filePath = fileUrl.path().mid(1) % u'_' % event->fileNameToDownload();

if (filePath.size() > 200) // If too long, elide in the middle
filePath.replace(128, filePath.size() - 192, "---"_L1);

filePath = QDir::tempPath() % u'/' % filePath;
qDebug(MAIN) << "File path:" << filePath;
}
const auto job =
std::visit(Overloads{ [this, &fileUrl, &filePath](const EncryptedFileMetadata& fileMetadata) {
return connection()->downloadFile(fileUrl, fileMetadata, filePath);
},
[this, &fileUrl, &filePath](auto) {
return connection()->downloadFile(fileUrl, filePath);
} },
fileInfo.source);

auto targetPath = localFilename.toLocalFile();
if (targetPath.isEmpty())
targetPath = event->temporaryPathToDownload();
const auto sourceUrl = fileInfo->url();
qDebug(MAIN) << "Downloading the file to" << targetPath;
const auto job = std::visit(
Overloads{ [this, &sourceUrl, &targetPath](const EncryptedFileMetadata& fileMetadata) {
return connection()->downloadFile(sourceUrl, fileMetadata, targetPath);
},
[this, &sourceUrl, &targetPath](auto) {
return connection()->downloadFile(sourceUrl, targetPath);
} },
fileInfo->commonInfo().source);
if (!isJobPending(job)) {
d->failedTransfer(eventId);
return;
Expand All @@ -2491,10 +2480,10 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
d->fileTransfers[eventId].update(received, total);
emit fileTransferProgress(eventId, received, total);
});
connect(job, &BaseJob::success, this, [this, eventId, fileUrl, job] {
connect(job, &BaseJob::success, this, [this, eventId, sourceUrl, job] {
d->fileTransfers[eventId].status = FileTransferInfo::Completed;
emit fileTransferCompleted(
eventId, fileUrl, QUrl::fromLocalFile(job->targetFileName()));
eventId, sourceUrl, QUrl::fromLocalFile(job->targetFileName()));
});
connect(job, &BaseJob::failure, this,
std::bind_front(&Private::failedTransfer, d, eventId, job->errorString()));
Expand Down

0 comments on commit c8111de

Please sign in to comment.