Load non-streamable documents.

This commit is contained in:
John Preston 2023-12-05 13:17:07 +04:00
parent 5c428ca502
commit c46f34c677
6 changed files with 135 additions and 38 deletions

View file

@ -306,7 +306,7 @@ article ol aside {
article blockquote cite,
article aside cite,
article footer cite,
article .iv-pullquote cite {
article .pullquote cite {
font-family: 'Helvetica Neue';
font-size: 15px;
display: block;
@ -385,7 +385,7 @@ article table {
article table.bordered,
article table.bordered td,
article table.bordered th {
border: 1px solid var(--td-box-divider-fg);
border: 1px solid var(--td-history-to-down-shadow);
}
article table.striped tr:nth-child(odd) td {
background-color: var(--td-box-divider-bg);
@ -425,7 +425,7 @@ article details {
article details:before {
content: '';
display: block;
border-bottom: 1px solid var(--td-box-divider-fg);
border-bottom: 1px solid var(--td-history-to-down-shadow);
position: absolute;
left: 18px;
right: 0;
@ -818,6 +818,7 @@ section.embed-post small {
color: var(--td-window-sub-text-fg);
}
section.related {
margin: 7px 0 12px;
}
@ -842,7 +843,7 @@ section.related a.related-link {
section.related a.related-link:after {
content: '';
display: block;
border-bottom: 1px solid var(--td-box-divider-fg);
border-bottom: 1px solid var(--td-history-to-down-shadow);
position: absolute;
left: 18px;
right: 0;
@ -975,19 +976,19 @@ section.channel > a > h4 {
padding: 7px 18px;
}
.iv-pullquote {
.pullquote {
text-align: center;
max-width: 420px;
font-size: 19px;
display: block;
margin: 0 auto;
}
.iv-photo-wrap {
.photo-wrap {
width: 100%;
background-size: 100%;
margin: 0 auto;
}
.iv-photo {
.photo {
background-size: 100%;
}

View file

@ -772,7 +772,11 @@ Storage::Cache::Key DocumentData::bigFileBaseCacheKey() const {
}
void DocumentData::forceToCache(bool force) {
_flags |= Flag::ForceToCache;
if (force) {
_flags |= Flag::ForceToCache;
} else {
_flags &= ~Flag::ForceToCache;
}
}
bool DocumentData::saveToCache() const {

View file

@ -482,18 +482,25 @@ void Controller::processKey(const QString &key, const QString &modifier) {
void Controller::processLink(const QString &url, const QString &context) {
const auto channelPrefix = u"channel"_q;
const auto joinPrefix = u"join_link"_q;
const auto webpagePrefix = u"webpage"_q;
if (context.startsWith(channelPrefix)) {
_events.fire({
Event::Type::OpenChannel,
context.mid(channelPrefix.size()),
.type = Event::Type::OpenChannel,
.context = context.mid(channelPrefix.size()),
});
} else if (context.startsWith(joinPrefix)) {
_events.fire({
Event::Type::JoinChannel,
context.mid(joinPrefix.size()),
.type = Event::Type::JoinChannel,
.context = context.mid(joinPrefix.size()),
});
} else if (context.startsWith(webpagePrefix)) {
_events.fire({
.type = Event::Type::OpenPage,
.url = url,
.context = context.mid(webpagePrefix.size()),
});
} else if (context.isEmpty()) {
_events.fire({ Event::Type::OpenLink, url });
_events.fire({ .type = Event::Type::OpenLink, .url = url });
}
}

View file

@ -38,9 +38,11 @@ public:
Quit,
OpenChannel,
JoinChannel,
OpenPage,
OpenLink,
};
Type type = Type::Close;
QString url;
QString context;
};

View file

@ -15,12 +15,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_cloud_file.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_session.h"
#include "data/data_web_page.h"
#include "info/profile/info_profile_values.h"
#include "iv/iv_controller.h"
#include "iv/iv_data.h"
#include "lottie/lottie_common.h" // Lottie::ReadContent.
#include "main/main_account.h"
#include "main/main_domain.h"
#include "main/main_session.h"
@ -97,13 +100,17 @@ private:
std::vector<bool> loaded;
int64 offset = 0;
};
struct FileLoad {
struct FileStream {
not_null<DocumentData*> document;
std::unique_ptr<Media::Streaming::Loader> loader;
std::vector<PartRequest> requests;
std::string mime;
rpl::lifetime lifetime;
};
struct FileLoad {
std::shared_ptr<::Data::DocumentMedia> media;
std::vector<Webview::DataRequest> requests;
};
void showLocal(Prepared result);
void showWindowed(Prepared result);
@ -123,9 +130,9 @@ private:
// Windowed.
void streamPhoto(PhotoId photoId, Webview::DataRequest request);
void streamFile(DocumentId documentId, Webview::DataRequest request);
void streamFile(FileLoad &file, Webview::DataRequest request);
void streamFile(FileStream &file, Webview::DataRequest request);
void processPartInFile(
FileLoad &file,
FileStream &file,
Media::Streaming::LoadedPart &&part);
bool finishRequestWithPart(
PartRequest &request,
@ -134,6 +141,9 @@ private:
void sendEmbed(QByteArray hash, Webview::DataRequest request);
void fillChannelJoinedValues(const Prepared &result);
void subscribeToDocuments();
[[nodiscard]] QByteArray readFile(
const std::shared_ptr<::Data::DocumentMedia> &media);
void requestDone(
Webview::DataRequest request,
QByteArray bytes,
@ -146,6 +156,7 @@ private:
std::shared_ptr<Main::SessionShow> _show;
QString _id;
std::unique_ptr<Controller> _controller;
base::flat_map<DocumentId, FileStream> _streams;
base::flat_map<DocumentId, FileLoad> _files;
base::flat_map<QByteArray, rpl::producer<bool>> _inChannelValues;
@ -157,6 +168,7 @@ private:
rpl::event_stream<Controller::Event> _events;
rpl::lifetime _documentLifetime;
rpl::lifetime _lifetime;
};
@ -461,20 +473,37 @@ void Shown::streamFile(
Webview::DataRequest request) {
using namespace Data;
const auto i = _files.find(documentId);
if (i != end(_files)) {
const auto i = _streams.find(documentId);
if (i != end(_streams)) {
streamFile(i->second, std::move(request));
return;
}
const auto document = _session->data().document(documentId);
auto loader = document->createStreamingLoader(FileOrigin(), false);
if (!loader) {
requestFail(std::move(request));
if (document->size >= Storage::kMaxFileInMemory) {
requestFail(std::move(request));
} else {
auto media = document->createMediaView();
if (const auto content = readFile(media); !content.isEmpty()) {
requestDone(
std::move(request),
content,
document->mimeString().toStdString());
} else {
subscribeToDocuments();
auto &file = _files[documentId];
file.media = std::move(media);
file.requests.push_back(std::move(request));
document->forceToCache(true);
document->save(::Data::FileOrigin(), QString());
}
}
return;
}
auto &file = _files.emplace(
auto &file = _streams.emplace(
documentId,
FileLoad{
FileStream{
.document = document,
.loader = std::move(loader),
.mime = document->mimeString().toStdString(),
@ -482,15 +511,15 @@ void Shown::streamFile(
file.loader->parts(
) | rpl::start_with_next([=](Media::Streaming::LoadedPart &&part) {
const auto i = _files.find(documentId);
Assert(i != end(_files));
const auto i = _streams.find(documentId);
Assert(i != end(_streams));
processPartInFile(i->second, std::move(part));
}, file.lifetime);
streamFile(file, std::move(request));
}
void Shown::streamFile(FileLoad &file, Webview::DataRequest request) {
void Shown::streamFile(FileStream &file, Webview::DataRequest request) {
constexpr auto kPart = Media::Streaming::Loader::kPartSize;
const auto size = file.document->size;
const auto last = int((size + kPart - 1) / kPart);
@ -519,8 +548,44 @@ void Shown::streamFile(FileLoad &file, Webview::DataRequest request) {
}
}
void Shown::subscribeToDocuments() {
if (_documentLifetime) {
return;
}
_documentLifetime = _session->data().documentLoadProgress(
) | rpl::filter([=](not_null<DocumentData*> document) {
return !document->loading();
}) | rpl::start_with_next([=](not_null<DocumentData*> document) {
const auto i = _files.find(document->id);
if (i == end(_files)) {
return;
}
auto requests = base::take(i->second.requests);
const auto content = readFile(i->second.media);
_files.erase(i);
if (!content.isEmpty()) {
for (auto &request : requests) {
requestDone(
std::move(request),
content,
document->mimeString().toStdString());
}
} else {
for (auto &request : requests) {
requestFail(std::move(request));
}
}
});
}
QByteArray Shown::readFile(
const std::shared_ptr<::Data::DocumentMedia> &media) {
return Lottie::ReadContent(media->bytes(), media->owner()->filepath());
}
void Shown::processPartInFile(
FileLoad &file,
FileStream &file,
Media::Streaming::LoadedPart &&part) {
for (auto i = begin(file.requests); i != end(file.requests);) {
if (finishRequestWithPart(*i, part)) {
@ -725,8 +790,26 @@ void Instance::show(
case Type::JoinChannel:
processJoinChannel(event.context);
break;
case Type::OpenPage:
case Type::OpenLink:
UrlClickHandler::Open(event.context);
_shownSession->api().request(MTPmessages_GetWebPage(
MTP_string(event.url),
MTP_int(0)
)).done([=](const MTPmessages_WebPage &result) {
_shownSession->data().processUsers(result.data().vusers());
_shownSession->data().processChats(result.data().vchats());
const auto page = _shownSession->data().processWebpage(
result.data().vwebpage());
if (page && page->iv) {
const auto parts = event.url.split('#');
const auto hash = (parts.size() > 1) ? parts[1] : u""_q;
this->show(show, page->iv.get(), hash);
} else {
UrlClickHandler::Open(event.url);
}
}).fail([=] {
UrlClickHandler::Open(event.url);
}).send();
break;
}
}, _shown->lifetime());

View file

@ -214,11 +214,11 @@ QByteArray Parser::block(const MTPDpageBlockUnsupported &data) {
}
QByteArray Parser::block(const MTPDpageBlockTitle &data) {
return tag("h1", { { "class", "iv-title" } }, rich(data.vtext()));
return tag("h1", { { "class", "title" } }, rich(data.vtext()));
}
QByteArray Parser::block(const MTPDpageBlockSubtitle &data) {
return tag("h2", { { "class", "iv-subtitle" } }, rich(data.vtext()));
return tag("h2", { { "class", "subtitle" } }, rich(data.vtext()));
}
QByteArray Parser::block(const MTPDpageBlockAuthorDate &data) {
@ -232,11 +232,11 @@ QByteArray Parser::block(const MTPDpageBlockAuthorDate &data) {
}
QByteArray Parser::block(const MTPDpageBlockHeader &data) {
return tag("h3", { { "class", "iv-header" } }, rich(data.vtext()));
return tag("h3", { { "class", "header" } }, rich(data.vtext()));
}
QByteArray Parser::block(const MTPDpageBlockSubheader &data) {
return tag("h4", { { "class", "iv-subheader" } }, rich(data.vtext()));
return tag("h4", { { "class", "subheader" } }, rich(data.vtext()));
}
QByteArray Parser::block(const MTPDpageBlockParagraph &data) {
@ -255,11 +255,11 @@ QByteArray Parser::block(const MTPDpageBlockPreformatted &data) {
}
QByteArray Parser::block(const MTPDpageBlockFooter &data) {
return tag("footer", { { "class", "iv-footer" } }, rich(data.vtext()));
return tag("footer", { { "class", "footer" } }, rich(data.vtext()));
}
QByteArray Parser::block(const MTPDpageBlockDivider &data) {
return tag("hr", { { "class", "iv-divider" } });
return tag("hr", { { "class", "divider" } });
}
QByteArray Parser::block(const MTPDpageBlockAnchor &data) {
@ -285,7 +285,7 @@ QByteArray Parser::block(const MTPDpageBlockPullquote &data) {
: tag("cite", caption);
return tag(
"div",
{ { "class", "iv-pullquote" } },
{ { "class", "pullquote" } },
rich(data.vtext()) + cite);
}
@ -313,11 +313,11 @@ QByteArray Parser::block(const MTPDpageBlockPhoto &data) {
const auto style = "background-image:url('" + src + "');"
"padding-top:" + QByteArray::number(paddingTopPercent) + "%";
const auto inner = tag("div", {
{ "class", "iv-photo" },
{ "class", "photo" },
{ "style", style } });
auto result = tag(
"div",
{ { "class", "iv-photo-wrap" }, { "style", wrapStyle } },
{ { "class", "photo-wrap" }, { "style", wrapStyle } },
inner);
if (const auto url = data.vurl()) {
result = tag("a", { { "href", utf(*url) } }, result);
@ -552,7 +552,7 @@ QByteArray Parser::block(const MTPDpageBlockAudio &data) {
}
QByteArray Parser::block(const MTPDpageBlockKicker &data) {
return tag("h6", { { "class", "iv-kicker" } }, rich(data.vtext()));
return tag("h6", { { "class", "kicker" } }, rich(data.vtext()));
}
QByteArray Parser::block(const MTPDpageBlockTable &data) {
@ -599,9 +599,9 @@ QByteArray Parser::block(const MTPDpageBlockRelatedArticles &data) {
}
auto title = rich(data.vtitle());
if (!title.isEmpty()) {
title = tag("h4", { { "class", "iv-related-title" } }, title);
title = tag("h4", { { "class", "related-title" } }, title);
}
return tag("section", { { "class", "iv-related" } }, title + result);
return tag("section", { { "class", "related" } }, title + result);
}
QByteArray Parser::block(const MTPDpageBlockMap &data) {