Skip to content

Commit ac3fa70

Browse files
committed
File streaming fixes.
GitOrigin-RevId: 86c6d1394a31d6bb108a12e14f4d981133ece235
1 parent 3b238f6 commit ac3fa70

28 files changed

+201
-160
lines changed

‎memprof/memprof.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ void *memalign(std::size_t aligment, std::size_t size) {
280280
}
281281
}
282282

283-
// c++14 guarantees than it is enough to override this two operators.
283+
// c++14 guarantees that it is enough to override these two operators.
284284
void *operator new(std::size_t count) {
285285
return malloc_with_frame(count, get_backtrace());
286286
}

‎td/generate/scheme/td_api.tl

+6-10
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ temporaryPasswordState has_password:Bool valid_for:int32 = TemporaryPasswordStat
126126
//@can_be_deleted True, if the file can be deleted
127127
//@is_downloading_active True, if the file is currently being downloaded (or a local copy is being generated by some other means)
128128
//@is_downloading_completed True, if the local copy is fully available
129-
//@download_offset Download will be started from this offset. downloaded_prefix_size is calculated from this offset.
130-
//@downloaded_prefix_size If is_downloading_completed is false, then only some prefix of the file is ready to be read. downloaded_prefix_size is the size of that prefix
129+
//@download_offset Download will be started from this offset. downloaded_prefix_size is calculated from this offset
130+
//@downloaded_prefix_size If is_downloading_completed is false, then only some prefix of the file starting from download_offset is ready to be read. downloaded_prefix_size is the size of that prefix
131131
//@downloaded_size Total downloaded file bytes. Should be used only for calculating download progress. The actual file size may be bigger, and some parts of it may contain garbage
132132
localFile path:string can_be_downloaded:Bool can_be_deleted:Bool is_downloading_active:Bool is_downloading_completed:Bool download_offset:int32 downloaded_prefix_size:int32 downloaded_size:int32 = LocalFile;
133133

@@ -2949,18 +2949,14 @@ setPinnedChats chat_ids:vector<int53> = Ok;
29492949
//@description Asynchronously downloads a file from the cloud. updateFile will be used to notify about the download progress and successful completion of the download. Returns file state just after the download has been started
29502950
//@file_id Identifier of the file to download
29512951
//@priority Priority of the download (1-32). The higher the priority, the earlier the file will be downloaded. If the priorities of two files are equal, then the last one for which downloadFile was called will be downloaded first
2952-
//@offset File will be downloaded starting from offset first. Supposed to be used for streaming.
2952+
//@offset File will be downloaded starting from that offset in bytes first. Supposed to be used for streaming
29532953
downloadFile file_id:int32 priority:int32 offset:int32 = File;
29542954

2955-
//@description Set offset for file downloading
2956-
//@file_id Identifier of file
2957-
//@offset File download offset
2955+
//@description Sets offset for file downloading @file_id Identifier of the file to change download offset @offset New file download offset
29582956
setFileDownloadOffset file_id:int32 offset:int32 = File;
29592957

2960-
//@description Get downloaded prefix from a given offset
2961-
//@file_id Identifier of file
2962-
//@offset Offset from which downloaded prefix is calculated
2963-
getFileDownloadedPrefix file_id:int32 offset:int32 = Count;
2958+
//@description Returns file downloaded prefix size from a given offset @file_id Identifier of the file @offset Offset from which downloaded prefix size should be calculated
2959+
getFileDownloadedPrefixSize file_id:int32 offset:int32 = Count;
29642960

29652961
//@description Stops the downloading of a file. If a file has already been downloaded, does nothing @file_id Identifier of a file to stop downloading @only_if_pending Pass true to stop downloading only if it hasn't been started, i.e. request hasn't been sent to server
29662962
cancelDownloadFile file_id:int32 only_if_pending:Bool = Ok;

‎td/generate/scheme/td_api.tlo

4 Bytes
Binary file not shown.

‎td/telegram/MessagesManager.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -9956,6 +9956,9 @@ void MessagesManager::try_restore_dialog_reply_markup(Dialog *d, const Message *
99569956

99579957
void MessagesManager::set_dialog_pinned_message_notification(Dialog *d, MessageId message_id) {
99589958
auto old_message_id = d->pinned_message_notification_message_id;
9959+
if (!old_message_id.is_valid() && !message_id.is_valid()) {
9960+
return;
9961+
}
99599962
CHECK(old_message_id != message_id);
99609963
VLOG(notifications) << "Change pinned message notification in " << d->dialog_id << " from " << old_message_id
99619964
<< " to " << message_id;

‎td/telegram/SecretChatActor.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class SecretChatActor : public NetQueryCallback {
103103

104104
SecretChatActor(int32 id, unique_ptr<Context> context, bool can_be_empty);
105105

106-
// First query to new chat must be on of this two
106+
// First query to new chat must be on of these two
107107
void update_chat(telegram_api::object_ptr<telegram_api::EncryptedChat> chat);
108108
void create_chat(int32 user_id, int64 user_access_hash, int32 random_id, Promise<SecretChatId> promise);
109109
void cancel_chat(Promise<> promise);

‎td/telegram/StickersManager.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3040,7 +3040,7 @@ Result<std::tuple<FileId, bool, bool>> StickersManager::prepare_input_file(
30403040
if (file_view.has_url()) {
30413041
is_url = true;
30423042
} else {
3043-
if (file_view.has_local_location() && file_view.local_size() > MAX_STICKER_FILE_SIZE) {
3043+
if (file_view.has_local_location() && file_view.expected_size() > MAX_STICKER_FILE_SIZE) {
30443044
return Status::Error(400, "File is too big");
30453045
}
30463046
is_local = true;

‎td/telegram/Td.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -4858,13 +4858,13 @@ void Td::on_request(uint64 id, const td_api::getFile &request) {
48584858
send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(FileId(request.file_id_, 0)));
48594859
}
48604860

4861-
void Td::on_request(uint64 id, const td_api::getFileDownloadedPrefix &request) {
4861+
void Td::on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &request) {
48624862
auto file_view = file_manager_->get_file_view(FileId(request.file_id_, 0));
48634863
if (file_view.empty()) {
48644864
return send_closure(actor_id(this), &Td::send_error, id, Status::Error(10, "Unknown file id"));
48654865
}
48664866
send_closure(actor_id(this), &Td::send_result, id,
4867-
td_api::make_object<td_api::count>(static_cast<int32>(file_view.downloaded_prefix(request.offset_))));
4867+
td_api::make_object<td_api::count>(narrow_cast<int32>(file_view.downloaded_prefix(request.offset_))));
48684868
}
48694869

48704870
void Td::on_request(uint64 id, td_api::getRemoteFile &request) {

‎td/telegram/Td.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ class Td final : public NetQueryCallback {
442442

443443
void on_request(uint64 id, const td_api::getFile &request);
444444

445-
void on_request(uint64 id, const td_api::getFileDownloadedPrefix &request);
445+
void on_request(uint64 id, const td_api::getFileDownloadedPrefixSize &request);
446446

447447
void on_request(uint64 id, td_api::getRemoteFile &request);
448448

‎td/telegram/cli.cpp

+14-16
Original file line numberDiff line numberDiff line change
@@ -2251,11 +2251,11 @@ class CliClient final : public Actor {
22512251
send_request(make_tl_object<td_api::getChatMessageByDate>(as_chat_id(chat_id), to_integer<int32>(date)));
22522252
} else if (op == "gf" || op == "GetFile") {
22532253
send_request(make_tl_object<td_api::getFile>(as_file_id(args)));
2254-
} else if (op == "gfp" || op == "GetFileDownloadedPrefix") {
2254+
} else if (op == "gfdps") {
22552255
string file_id;
22562256
string offset;
22572257
std::tie(file_id, offset) = split(args);
2258-
send_request(make_tl_object<td_api::getFileDownloadedPrefix>(as_file_id(file_id), to_integer<int32>(offset)));
2258+
send_request(make_tl_object<td_api::getFileDownloadedPrefixSize>(as_file_id(file_id), to_integer<int32>(offset)));
22592259
} else if (op == "grf") {
22602260
send_request(make_tl_object<td_api::getRemoteFile>(args, nullptr));
22612261
} else if (op == "gmtf") {
@@ -2277,36 +2277,34 @@ class CliClient final : public Actor {
22772277
as_location(latitude, longitude), to_integer<int32>(zoom), to_integer<int32>(width),
22782278
to_integer<int32>(height), to_integer<int32>(scale), as_chat_id(chat_id)));
22792279
} else if (op == "sfdo" || op == "SetDownloadFileOffset") {
2280-
string file_id_str;
2280+
string file_id;
22812281
string offset;
2282-
std::tie(file_id_str, offset) = split(args);
2282+
std::tie(file_id, offset) = split(args);
22832283

2284-
auto file_id = as_file_id(file_id_str);
2285-
send_request(make_tl_object<td_api::setFileDownloadOffset>(file_id, to_integer<int32>(offset)));
2284+
send_request(make_tl_object<td_api::setFileDownloadOffset>(as_file_id(file_id), to_integer<int32>(offset)));
22862285
} else if (op == "df" || op == "DownloadFile") {
2287-
string file_id_str;
2286+
string file_id;
22882287
string priority;
22892288
string offset;
2290-
std::tie(file_id_str, args) = split(args);
2291-
std::tie(priority, offset) = split(args);
2289+
std::tie(file_id, args) = split(args);
2290+
std::tie(offset, priority) = split(args);
22922291
if (priority.empty()) {
22932292
priority = "1";
22942293
}
22952294

2296-
auto file_id = as_file_id(file_id_str);
2297-
send_request(
2298-
make_tl_object<td_api::downloadFile>(file_id, to_integer<int32>(priority), to_integer<int32>(offset)));
2295+
send_request(make_tl_object<td_api::downloadFile>(as_file_id(file_id), to_integer<int32>(priority),
2296+
to_integer<int32>(offset)));
22992297
} else if (op == "dff") {
2300-
string file_id;
2298+
string max_file_id;
23012299
string priority;
23022300
string offset;
2303-
std::tie(file_id, args) = split(args);
2304-
std::tie(priority, offset) = split(args);
2301+
std::tie(max_file_id, args) = split(args);
2302+
std::tie(offset, priority) = split(args);
23052303
if (priority.empty()) {
23062304
priority = "1";
23072305
}
23082306

2309-
for (int i = 1; i <= as_file_id(file_id); i++) {
2307+
for (int i = 1; i <= as_file_id(max_file_id); i++) {
23102308
send_request(make_tl_object<td_api::downloadFile>(i, to_integer<int32>(priority), to_integer<int32>(offset)));
23112309
}
23122310
} else if (op == "cdf") {

‎td/telegram/files/FileBitmask.cpp

+42-25
Original file line numberDiff line numberDiff line change
@@ -5,80 +5,97 @@
55
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
66
//
77
#include "td/telegram/files/FileBitmask.h"
8+
9+
#include "td/utils/common.h"
810
#include "td/utils/misc.h"
11+
912
namespace td {
13+
1014
Bitmask::Bitmask(Decode, Slice data) : data_(zero_one_decode(data)) {
1115
}
12-
Bitmask::Bitmask(Ones, int64 count) : data_((count + 7) / 8, '\0') {
16+
17+
Bitmask::Bitmask(Ones, int64 count) : data_(narrow_cast<size_t>((count + 7) / 8), '\0') {
1318
for (int64 i = 0; i < count; i++) {
1419
set(i);
1520
}
1621
}
22+
1723
std::string Bitmask::encode() const {
18-
// remove zeroes in the end to make encoding deteministic
24+
// remove zeroes in the end to make encoding deterministic
1925
td::Slice data(data_);
20-
while (!data.empty() && data.back() == 0) {
26+
while (!data.empty() && data.back() == '\0') {
2127
data.remove_suffix(1);
2228
}
23-
return zero_one_encode(data_);
29+
return zero_one_encode(data);
2430
}
25-
Bitmask::ReadySize Bitmask::get_ready_size(int64 offset, int64 part_size) const {
26-
ReadySize res;
27-
res.offset = offset;
31+
32+
int64 Bitmask::get_ready_prefix_size(int64 offset, int64 part_size, int64 file_size) const {
2833
auto offset_part = offset / part_size;
2934
auto ones = get_ready_parts(offset_part);
3035
if (ones == 0) {
31-
res.ready_size = 0;
32-
} else {
33-
res.ready_size = (offset_part + ones) * part_size - offset;
36+
return 0;
3437
}
35-
CHECK(res.ready_size >= 0);
38+
auto ready_parts_end = (offset_part + ones) * part_size;
39+
if (file_size != 0 && ready_parts_end > file_size) {
40+
ready_parts_end = file_size;
41+
if (offset > file_size) {
42+
offset = file_size;
43+
}
44+
}
45+
auto res = ready_parts_end - offset;
46+
CHECK(res >= 0);
3647
return res;
3748
}
49+
3850
int64 Bitmask::get_total_size(int64 part_size) const {
3951
int64 res = 0;
4052
for (int64 i = 0; i < size(); i++) {
41-
res += get(i);
53+
res += static_cast<int64>(get(i));
4254
}
4355
return res * part_size;
4456
}
45-
bool Bitmask::get(int64 offset) const {
46-
if (offset < 0) {
57+
58+
bool Bitmask::get(int64 offset_part) const {
59+
if (offset_part < 0) {
4760
return 0;
4861
}
49-
if (offset / 8 >= narrow_cast<int64>(data_.size())) {
62+
auto index = narrow_cast<size_t>(offset_part / 8);
63+
if (index >= data_.size()) {
5064
return 0;
5165
}
52-
return (data_[offset / 8] & (1 << (offset % 8))) != 0;
66+
return (static_cast<uint8>(data_[index]) & (1 << static_cast<int>(offset_part % 8))) != 0;
5367
}
5468

55-
int64 Bitmask::get_ready_parts(int64 offset) const {
69+
int64 Bitmask::get_ready_parts(int64 offset_part) const {
5670
int64 res = 0;
57-
while (get(offset + res)) {
71+
while (get(offset_part + res)) {
5872
res++;
5973
}
6074
return res;
61-
};
75+
}
6276

6377
std::vector<int32> Bitmask::as_vector() const {
6478
std::vector<int32> res;
65-
for (int32 i = 0; i < narrow_cast<int32>(data_.size() * 8); i++) {
79+
auto size = narrow_cast<int32>(data_.size() * 8);
80+
for (int32 i = 0; i < size; i++) {
6681
if (get(i)) {
6782
res.push_back(i);
6883
}
6984
}
7085
return res;
7186
}
72-
void Bitmask::set(int64 offset) {
73-
auto need_size = narrow_cast<size_t>(offset / 8 + 1);
87+
88+
void Bitmask::set(int64 offset_part) {
89+
CHECK(offset_part >= 0);
90+
auto need_size = narrow_cast<size_t>(offset_part / 8 + 1);
7491
if (need_size > data_.size()) {
75-
data_.resize(need_size, 0);
92+
data_.resize(need_size, '\0');
7693
}
77-
data_[need_size - 1] |= (1 << (offset % 8));
94+
data_[need_size - 1] |= (1 << (offset_part % 8));
7895
}
7996

8097
int64 Bitmask::size() const {
81-
return data_.size() * 8;
98+
return static_cast<int64>(data_.size() * 8);
8299
}
83100

84101
} // namespace td

‎td/telegram/files/FileBitmask.h

+8-14
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,40 @@
55
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
66
//
77
#pragma once
8+
89
#include "td/utils/common.h"
910
#include "td/utils/Slice.h"
1011
#include "td/utils/StringBuilder.h"
1112

1213
namespace td {
14+
1315
class Bitmask {
1416
public:
15-
struct ReadySize {
16-
int64 offset{-1};
17-
int64 ready_size{-1};
18-
bool empty() const {
19-
return offset == -1;
20-
}
21-
};
2217
struct Decode {};
2318
struct Ones {};
2419
Bitmask() = default;
2520
Bitmask(Decode, Slice data);
2621
Bitmask(Ones, int64 count);
2722
std::string encode() const;
28-
ReadySize get_ready_size(int64 offset, int64 part_size) const;
23+
int64 get_ready_prefix_size(int64 offset, int64 part_size, int64 file_size) const;
2924
int64 get_total_size(int64 part_size) const;
30-
bool get(int64 offset) const;
25+
bool get(int64 offset_part) const;
3126

32-
int64 get_ready_parts(int64 offset) const;
27+
int64 get_ready_parts(int64 offset_part) const;
3328

3429
std::vector<int32> as_vector() const;
35-
void set(int64 offset);
30+
void set(int64 offset_part);
3631
int64 size() const;
3732

3833
private:
3934
std::string data_;
4035
};
4136

4237
inline StringBuilder &operator<<(StringBuilder &sb, const Bitmask &mask) {
43-
std::string res;
4438
for (int64 i = 0; i < mask.size(); i++) {
45-
res += mask.get(i) ? "1" : "0";
39+
sb << (mask.get(i) ? '1' : '0');
4640
}
47-
return sb << res;
41+
return sb;
4842
}
4943

5044
} // namespace td

‎td/telegram/files/FileDownloader.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,11 @@ Result<FileLoader::FileInfo> FileDownloader::init() {
104104
res.ready_parts = bitmask.as_vector();
105105
res.use_part_count_limit = false;
106106
res.only_check = only_check_;
107-
res.need_delay = !is_small_ && (remote_.file_type_ == FileType::VideoNote ||
108-
remote_.file_type_ == FileType::VoiceNote || remote_.file_type_ == FileType::Audio ||
109-
remote_.file_type_ == FileType::Video || remote_.file_type_ == FileType::Animation ||
110-
(remote_.file_type_ == FileType::Encrypted && size_ > (1 << 20)));
107+
res.need_delay =
108+
!is_small_ && (remote_.file_type_ == FileType::VideoNote || remote_.file_type_ == FileType::Document ||
109+
remote_.file_type_ == FileType::VoiceNote || remote_.file_type_ == FileType::Audio ||
110+
remote_.file_type_ == FileType::Video || remote_.file_type_ == FileType::Animation ||
111+
(remote_.file_type_ == FileType::Encrypted && size_ > (1 << 20)));
111112
res.offset = offset_;
112113
return res;
113114
}
@@ -304,7 +305,6 @@ Result<size_t> FileDownloader::process_part(Part part, NetQueryPtr net_query) {
304305
if (encryption_key_.is_secret()) {
305306
padded_size = (part.size + 15) & ~15;
306307
}
307-
LOG(INFO) << "Got " << bytes.size() << " bytes, padded_size = " << padded_size << " for " << path_;
308308
if (bytes.size() > padded_size) {
309309
return Status::Error("Part size is more than requested");
310310
}
@@ -338,14 +338,15 @@ Result<size_t> FileDownloader::process_part(Part part, NetQueryPtr net_query) {
338338

339339
auto slice = bytes.as_slice().truncate(part.size);
340340
TRY_STATUS(acquire_fd());
341+
LOG(INFO) << "Got " << slice.size() << " bytes at " << part.offset << " for \"" << path_ << '"';
341342
TRY_RESULT(written, fd_.pwrite(slice, part.offset));
342343
// may write less than part.size, when size of downloadable file is unknown
343344
if (written != slice.size()) {
344345
return Status::Error("Failed to save file part to the file");
345346
}
346347
return written;
347348
}
348-
void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_part_count, string ready_bitmask,
349+
void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_part_count, const string &ready_bitmask,
349350
bool is_ready, int64 ready_size) {
350351
if (is_ready) {
351352
// do not send partial location. will lead to wrong local_size
@@ -355,7 +356,7 @@ void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_
355356
return;
356357
}
357358
if (encryption_key_.empty() || encryption_key_.is_secure()) {
358-
callback_->on_partial_download(PartialLocalFileLocation{remote_.file_type_, path_, part_size, "", ready_bitmask},
359+
callback_->on_partial_download(PartialLocalFileLocation{remote_.file_type_, part_size, path_, "", ready_bitmask},
359360
ready_size);
360361
} else if (encryption_key_.is_secret()) {
361362
UInt256 iv;
@@ -365,7 +366,7 @@ void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_
365366
LOG(FATAL) << tag("ready_part_count", ready_part_count) << tag("next_part", next_part_);
366367
}
367368
callback_->on_partial_download(
368-
PartialLocalFileLocation{remote_.file_type_, path_, part_size, as_slice(iv).str(), ready_bitmask}, ready_size);
369+
PartialLocalFileLocation{remote_.file_type_, part_size, path_, as_slice(iv).str(), ready_bitmask}, ready_size);
369370
} else {
370371
UNREACHABLE();
371372
}

0 commit comments

Comments
 (0)