Merge remote-tracking branch 'td/master'
This commit is contained in:
commit
71c2330749
@ -138,7 +138,7 @@ TDLib can be used from the Swift programming language through the [JSON](https:/
|
||||
|
||||
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
|
||||
|
||||
See [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS) or [tdlib-swift](https://github.com/modestman/tdlib-swift), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
See [TDLibKit](https://github.com/Swiftgram/TDLibKit), [tdlib-swift](https://github.com/modestman/tdlib-swift), or [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
|
||||
See [example/swift](https://github.com/tdlib/td/tree/master/example/swift) for an example of a macOS Swift application.
|
||||
|
||||
|
@ -803,7 +803,7 @@ foundMessages total_count:int32 messages:vector<message> next_offset:string = Fo
|
||||
|
||||
//@description Describes a sponsored message @id Unique sponsored message identifier @sponsor_chat_id Chat identifier
|
||||
//@start_parameter Parameter for the bot start message if the sponsored chat is a chat with a bot @content Content of the message
|
||||
sponsoredMessage id:bytes sponsor_chat_id:int53 start_parameter:string content:MessageContent = SponsoredMessage;
|
||||
sponsoredMessage id:int32 sponsor_chat_id:int53 start_parameter:string content:MessageContent = SponsoredMessage;
|
||||
|
||||
//@description Contains a list of sponsored messages @messages List of sponsored messages
|
||||
sponsoredMessages messages:vector<sponsoredMessage> = SponsoredMessages;
|
||||
@ -4267,8 +4267,8 @@ getMessagePublicForwards chat_id:int53 message_id:int53 offset:string limit:int3
|
||||
//@description Returns sponsored messages to be shown in a chat; for channel chats only @chat_id Identifier of the chat
|
||||
getChatSponsoredMessages chat_id:int53 = SponsoredMessages;
|
||||
|
||||
//@description Informs TDLib that a sponsored message was viewed by the user @chat_id Chat identifier @message_id The identifier of the sponsored message being viewed
|
||||
viewSponsoredMessage chat_id:int53 message_id:bytes = Ok;
|
||||
//@description Informs TDLib that a sponsored message was viewed by the user @chat_id Identifier of the chat with the sponsored message @sponsored_message_id The identifier of the sponsored message being viewed
|
||||
viewSponsoredMessage chat_id:int53 sponsored_message_id:int32 = Ok;
|
||||
|
||||
|
||||
//@description Removes an active notification from notification list. Needs to be called only if the notification is removed by the current user @notification_group_id Identifier of notification group to which the notification belongs @notification_id Identifier of removed notification
|
||||
@ -4368,7 +4368,8 @@ editMessageText chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_me
|
||||
//@proximity_alert_radius The new maximum distance for proximity alerts, in meters (0-100000). Pass 0 if the notification is disabled
|
||||
editMessageLiveLocation chat_id:int53 message_id:int53 reply_markup:ReplyMarkup location:location heading:int32 proximity_alert_radius:int32 = Message;
|
||||
|
||||
//@description Edits the content of a message with an animation, an audio, a document, a photo or a video. The media in the message can't be replaced if the message was set to self-destruct. Media can't be replaced by self-destructing media. Media in an album can be edited only to contain a photo or a video. Returns the edited message after the edit is completed on the server side
|
||||
//@description Edits the content of a message with an animation, an audio, a document, a photo or a video, including message caption. If only the caption needs to be edited, use editMessageCaption instead.
|
||||
//-The media can't be edited if the message was set to self-destruct or to a self-destructing media. The type of message content in an album can't be changed with exception of replacing a photo with a video or vice versa. Returns the edited message after the edit is completed on the server side
|
||||
//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: inputMessageAnimation, inputMessageAudio, inputMessageDocument, inputMessagePhoto or inputMessageVideo
|
||||
editMessageMedia chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message;
|
||||
|
||||
@ -4623,7 +4624,7 @@ setChatMessageTtlSetting chat_id:int53 ttl:int32 = Ok;
|
||||
//@chat_id Chat identifier @permissions New non-administrator members permissions in the chat
|
||||
setChatPermissions chat_id:int53 permissions:chatPermissions = Ok;
|
||||
|
||||
//@description Changes the chat theme. Requires can_change_info administrator right in groups, supergroups and channels @chat_id Chat identifier
|
||||
//@description Changes the chat theme. Supported only in private and secret chats @chat_id Chat identifier
|
||||
//@theme_name Name of the new chat theme; may be empty to return the default theme
|
||||
setChatTheme chat_id:int53 theme_name:string = Ok;
|
||||
|
||||
|
@ -140,6 +140,9 @@ class PingConnectionPingPong final
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status on_update(BufferSlice packet) final {
|
||||
return Status::OK();
|
||||
}
|
||||
void on_message_ack(uint64 id) final {
|
||||
}
|
||||
Status on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) final {
|
||||
|
@ -253,26 +253,31 @@ Status SessionConnection::on_packet_rpc_result(const MsgInfo &info, Slice packet
|
||||
return Status::Error("Receive an update in rpc_result");
|
||||
}
|
||||
|
||||
auto object_begin_pos = packet.size() - parser.get_left_len();
|
||||
int32 id = parser.fetch_int();
|
||||
if (id == mtproto_api::rpc_error::ID) {
|
||||
mtproto_api::rpc_error rpc_error(parser);
|
||||
if (parser.get_error()) {
|
||||
return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_error: " << parser.get_error());
|
||||
switch (parser.fetch_int()) {
|
||||
case mtproto_api::rpc_error::ID: {
|
||||
mtproto_api::rpc_error rpc_error(parser);
|
||||
if (parser.get_error()) {
|
||||
return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_error: " << parser.get_error());
|
||||
}
|
||||
VLOG(mtproto) << "ERROR " << tag("code", rpc_error.error_code_) << tag("message", rpc_error.error_message_)
|
||||
<< tag("req_msg_id", req_msg_id);
|
||||
callback_->on_message_result_error(req_msg_id, rpc_error.error_code_, rpc_error.error_message_.str());
|
||||
return Status::OK();
|
||||
}
|
||||
return on_packet(info, req_msg_id, rpc_error);
|
||||
} else if (id == mtproto_api::gzip_packed::ID) {
|
||||
mtproto_api::gzip_packed gzip(parser);
|
||||
if (parser.get_error()) {
|
||||
return Status::Error(PSLICE() << "Failed to parse mtproto_api::gzip_packed: " << parser.get_error());
|
||||
case mtproto_api::gzip_packed::ID: {
|
||||
mtproto_api::gzip_packed gzip(parser);
|
||||
if (parser.get_error()) {
|
||||
return Status::Error(PSLICE() << "Failed to parse mtproto_api::gzip_packed: " << parser.get_error());
|
||||
}
|
||||
// yep, gzip in rpc_result
|
||||
BufferSlice object = gzdecode(gzip.packed_data_);
|
||||
// send header no more optimization
|
||||
return callback_->on_message_result_ok(req_msg_id, std::move(object), info.size);
|
||||
}
|
||||
// yep, gzip in rpc_result
|
||||
BufferSlice object = gzdecode(gzip.packed_data_);
|
||||
// send header no more optimization
|
||||
return callback_->on_message_result_ok(req_msg_id, std::move(object), info.size);
|
||||
default:
|
||||
packet.remove_prefix(4 + sizeof(req_msg_id));
|
||||
return callback_->on_message_result_ok(req_msg_id, as_buffer_slice(packet), info.size);
|
||||
}
|
||||
|
||||
return callback_->on_message_result_ok(req_msg_id, as_buffer_slice(packet.substr(object_begin_pos)), info.size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -297,17 +302,7 @@ Status SessionConnection::on_destroy_auth_key(const mtproto_api::DestroyAuthKeyR
|
||||
}
|
||||
|
||||
Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::rpc_error &rpc_error) {
|
||||
return on_packet(info, 0, rpc_error);
|
||||
}
|
||||
|
||||
Status SessionConnection::on_packet(const MsgInfo &info, uint64 req_msg_id, const mtproto_api::rpc_error &rpc_error) {
|
||||
VLOG(mtproto) << "ERROR " << tag("code", rpc_error.error_code_) << tag("message", rpc_error.error_message_)
|
||||
<< tag("req_msg_id", req_msg_id);
|
||||
if (req_msg_id != 0) {
|
||||
callback_->on_message_result_error(req_msg_id, rpc_error.error_code_, rpc_error.error_message_.str());
|
||||
} else {
|
||||
LOG(ERROR) << "Receive rpc_error as update: [" << rpc_error.error_code_ << "][" << rpc_error.error_message_ << "]";
|
||||
}
|
||||
LOG(ERROR) << "Receive rpc_error as update: [" << rpc_error.error_code_ << "][" << rpc_error.error_message_ << "]";
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@ -523,7 +518,7 @@ Status SessionConnection::on_slice_packet(const MsgInfo &info, Slice packet) {
|
||||
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
|
||||
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
|
||||
<< ", seq_no = " << info.seq_no << " and original size " << info.size;
|
||||
return callback_->on_message_result_ok(0, as_buffer_slice(packet), info.size);
|
||||
return callback_->on_update(as_buffer_slice(packet));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,8 @@ class SessionConnection final
|
||||
virtual void on_container_sent(uint64 container_id, vector<uint64> msgs_id) = 0;
|
||||
virtual Status on_pong() = 0;
|
||||
|
||||
virtual Status on_update(BufferSlice packet) = 0;
|
||||
|
||||
virtual void on_message_ack(uint64 id) = 0;
|
||||
virtual Status on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) = 0;
|
||||
virtual void on_message_result_error(uint64 id, int code, string message) = 0;
|
||||
@ -216,8 +218,6 @@ class SessionConnection final
|
||||
Status parse_packet(TlParser &parser) TD_WARN_UNUSED_RESULT;
|
||||
Status on_packet_container(const MsgInfo &info, Slice packet) TD_WARN_UNUSED_RESULT;
|
||||
Status on_packet_rpc_result(const MsgInfo &info, Slice packet) TD_WARN_UNUSED_RESULT;
|
||||
Status on_packet(const MsgInfo &info, uint64 req_msg_id,
|
||||
const mtproto_api::rpc_error &rpc_error) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
template <class T>
|
||||
Status on_packet(const MsgInfo &info, const T &packet) TD_WARN_UNUSED_RESULT;
|
||||
|
@ -406,6 +406,12 @@ ActorOwn<> get_full_config(DcOption option, Promise<FullConfig> promise, ActorSh
|
||||
void on_tmp_auth_key_updated(mtproto::AuthKey auth_key) final {
|
||||
// nop
|
||||
}
|
||||
void on_server_salt_updated(std::vector<mtproto::ServerSalt> server_salts) final {
|
||||
// nop
|
||||
}
|
||||
void on_update(BufferSlice &&update) final {
|
||||
// nop
|
||||
}
|
||||
void on_result(NetQueryPtr net_query) final {
|
||||
G()->net_query_dispatcher().dispatch(std::move(net_query));
|
||||
}
|
||||
|
@ -11583,7 +11583,9 @@ void ContactsManager::on_get_chat_participants(tl_object_ptr<telegram_api::ChatP
|
||||
|
||||
on_update_chat_full_participants(chat_full, chat_id, std::move(new_participants), participants->version_,
|
||||
from_update);
|
||||
update_chat_full(chat_full, chat_id, "on_get_chat_participants");
|
||||
if (from_update) {
|
||||
update_chat_full(chat_full, chat_id, "on_get_chat_participants");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -60,9 +60,6 @@ class ThemeManager;
|
||||
class TopDialogManager;
|
||||
class UpdatesManager;
|
||||
class WebPagesManager;
|
||||
} // namespace td
|
||||
|
||||
namespace td {
|
||||
|
||||
class Global final : public ActorContext {
|
||||
public:
|
||||
|
@ -668,6 +668,7 @@ static vector<Slice> match_urls(Slice str) {
|
||||
case '<':
|
||||
case '>':
|
||||
case '"':
|
||||
case '@':
|
||||
case 0xab: // «
|
||||
case 0xbb: // »
|
||||
return false;
|
||||
@ -697,20 +698,34 @@ static vector<Slice> match_urls(Slice str) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const unsigned char *last_at_ptr = nullptr;
|
||||
const unsigned char *domain_end_ptr = begin + dot_pos;
|
||||
while (domain_end_ptr != end) {
|
||||
const unsigned char *domain_begin_ptr = begin + dot_pos;
|
||||
while (domain_begin_ptr != begin) {
|
||||
domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr);
|
||||
uint32 code = 0;
|
||||
auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code, "match_urls");
|
||||
if (code == '@') {
|
||||
last_at_ptr = domain_end_ptr;
|
||||
}
|
||||
if (!is_user_data_symbol(code)) {
|
||||
auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code, "match_urls 0");
|
||||
if (!is_domain_symbol(code)) {
|
||||
domain_begin_ptr = next_ptr;
|
||||
break;
|
||||
}
|
||||
domain_end_ptr = next_ptr;
|
||||
}
|
||||
domain_end_ptr = last_at_ptr == nullptr ? begin + dot_pos : last_at_ptr + 1;
|
||||
|
||||
const unsigned char *last_at_ptr = nullptr;
|
||||
const unsigned char *domain_end_ptr = begin + dot_pos;
|
||||
if (domain_begin_ptr == begin || domain_begin_ptr[-1] != '@') {
|
||||
// try to find '@' to the right if there is no '@' to the left
|
||||
while (domain_end_ptr != end) {
|
||||
uint32 code = 0;
|
||||
auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code, "match_urls");
|
||||
if (code == '@') {
|
||||
last_at_ptr = domain_end_ptr;
|
||||
}
|
||||
if (!is_user_data_symbol(code)) {
|
||||
break;
|
||||
}
|
||||
domain_end_ptr = next_ptr;
|
||||
}
|
||||
domain_end_ptr = last_at_ptr == nullptr ? begin + dot_pos : last_at_ptr + 1;
|
||||
}
|
||||
while (domain_end_ptr != end) {
|
||||
uint32 code = 0;
|
||||
auto next_ptr = next_utf8_unsafe(domain_end_ptr, &code, "match_urls 2");
|
||||
@ -720,14 +735,15 @@ static vector<Slice> match_urls(Slice str) {
|
||||
domain_end_ptr = next_ptr;
|
||||
}
|
||||
|
||||
const unsigned char *domain_begin_ptr = begin + dot_pos;
|
||||
while (domain_begin_ptr != begin) {
|
||||
domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr);
|
||||
uint32 code = 0;
|
||||
auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code, "match_urls 3");
|
||||
if (last_at_ptr == nullptr ? !is_domain_symbol(code) : !is_user_data_symbol(code)) {
|
||||
domain_begin_ptr = next_ptr;
|
||||
break;
|
||||
if (last_at_ptr != nullptr) {
|
||||
while (domain_begin_ptr != begin) {
|
||||
domain_begin_ptr = prev_utf8_unsafe(domain_begin_ptr);
|
||||
uint32 code = 0;
|
||||
auto next_ptr = next_utf8_unsafe(domain_begin_ptr, &code, "match_urls 3");
|
||||
if (!is_user_data_symbol(code)) {
|
||||
domain_begin_ptr = next_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// LOG(ERROR) << "Domain: " << Slice(domain_begin_ptr, domain_end_ptr);
|
||||
@ -776,6 +792,9 @@ static vector<Slice> match_urls(Slice str) {
|
||||
bool is_bad = false;
|
||||
const unsigned char *url_begin_ptr = domain_begin_ptr;
|
||||
if (url_begin_ptr != begin && url_begin_ptr[-1] == '@') {
|
||||
if (last_at_ptr != nullptr) {
|
||||
is_bad = true;
|
||||
}
|
||||
auto user_data_begin_ptr = url_begin_ptr - 1;
|
||||
while (user_data_begin_ptr != begin) {
|
||||
user_data_begin_ptr = prev_utf8_unsafe(user_data_begin_ptr);
|
||||
|
@ -31586,33 +31586,18 @@ void MessagesManager::set_dialog_theme(DialogId dialog_id, const string &theme_n
|
||||
|
||||
auto d = get_dialog_force(dialog_id, "set_dialog_theme");
|
||||
if (d == nullptr) {
|
||||
return promise.set_error(Status::Error(3, "Chat not found"));
|
||||
return promise.set_error(Status::Error(400, "Chat not found"));
|
||||
}
|
||||
if (!have_input_peer(dialog_id, AccessRights::Write)) {
|
||||
return promise.set_error(Status::Error(3, "Can't access the chat"));
|
||||
return promise.set_error(Status::Error(400, "Can't access the chat"));
|
||||
}
|
||||
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
break;
|
||||
case DialogType::Chat: {
|
||||
auto chat_id = dialog_id.get_chat_id();
|
||||
auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
|
||||
if (!status.can_change_info_and_settings()) {
|
||||
return promise.set_error(Status::Error(3, "Not enough rights to change chat theme"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::Channel: {
|
||||
if (is_broadcast_channel(dialog_id)) {
|
||||
return promise.set_error(Status::Error(3, "Can't change channel chat permissions"));
|
||||
}
|
||||
auto status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
|
||||
if (!status.can_change_info_and_settings()) {
|
||||
return promise.set_error(Status::Error(3, "Not enough rights to change chat theme"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::Chat:
|
||||
case DialogType::Channel:
|
||||
return promise.set_error(Status::Error(400, "Can't change theme in the chat"));
|
||||
case DialogType::SecretChat: {
|
||||
auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
|
||||
if (!user_id.is_valid()) {
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace td {
|
||||
|
||||
class GetSponsoredMessagesQuery final : public Td::ResultHandler {
|
||||
@ -91,14 +93,14 @@ class ViewSponsoredMessageQuery final : public Td::ResultHandler {
|
||||
};
|
||||
|
||||
struct SponsoredMessageManager::SponsoredMessage {
|
||||
string random_id;
|
||||
int32 local_id = 0;
|
||||
DialogId sponsor_dialog_id;
|
||||
string start_param;
|
||||
unique_ptr<MessageContent> content;
|
||||
|
||||
SponsoredMessage() = default;
|
||||
SponsoredMessage(string random_id, DialogId sponsor_dialog_id, string start_param, unique_ptr<MessageContent> content)
|
||||
: random_id(std::move(random_id))
|
||||
SponsoredMessage(int32 local_id, DialogId sponsor_dialog_id, string start_param, unique_ptr<MessageContent> content)
|
||||
: local_id(local_id)
|
||||
, sponsor_dialog_id(sponsor_dialog_id)
|
||||
, start_param(std::move(start_param))
|
||||
, content(std::move(content)) {
|
||||
@ -108,6 +110,7 @@ struct SponsoredMessageManager::SponsoredMessage {
|
||||
struct SponsoredMessageManager::DialogSponsoredMessages {
|
||||
vector<Promise<td_api::object_ptr<td_api::sponsoredMessages>>> promises;
|
||||
vector<SponsoredMessage> messages;
|
||||
std::unordered_map<int32, string> message_random_ids;
|
||||
};
|
||||
|
||||
SponsoredMessageManager::SponsoredMessageManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||
@ -146,7 +149,7 @@ void SponsoredMessageManager::delete_cached_sponsored_messages(DialogId dialog_i
|
||||
td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponsored_message_object(
|
||||
DialogId dialog_id, const SponsoredMessage &sponsored_message) const {
|
||||
return td_api::make_object<td_api::sponsoredMessage>(
|
||||
sponsored_message.random_id, sponsored_message.sponsor_dialog_id.get(), sponsored_message.start_param,
|
||||
sponsored_message.local_id, sponsored_message.sponsor_dialog_id.get(), sponsored_message.start_param,
|
||||
get_message_content_object(sponsored_message.content.get(), td_, dialog_id, 0, false, true, -1));
|
||||
}
|
||||
|
||||
@ -194,6 +197,8 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
|
||||
CHECK(messages != nullptr);
|
||||
auto promises = std::move(messages->promises);
|
||||
reset_to_empty(messages->promises);
|
||||
CHECK(messages->messages.empty());
|
||||
CHECK(messages->message_random_ids.empty());
|
||||
|
||||
if (result.is_ok() && G()->close_flag()) {
|
||||
result = Status::Error(500, "Request aborted");
|
||||
@ -211,7 +216,6 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
|
||||
td_->contacts_manager_->on_get_users(std::move(sponsored_messages->users_), "on_get_dialog_sponsored_messages");
|
||||
td_->contacts_manager_->on_get_chats(std::move(sponsored_messages->chats_), "on_get_dialog_sponsored_messages");
|
||||
|
||||
reset_to_empty(messages->messages);
|
||||
for (auto &sponsored_message : sponsored_messages->messages_) {
|
||||
DialogId sponsor_dialog_id(sponsored_message->from_id_);
|
||||
if (!sponsor_dialog_id.is_valid() || !td_->messages_manager_->have_dialog_info_force(sponsor_dialog_id)) {
|
||||
@ -229,8 +233,11 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
|
||||
continue;
|
||||
}
|
||||
|
||||
messages->messages.emplace_back(sponsored_message->random_id_.as_slice().str(), sponsor_dialog_id,
|
||||
std::move(sponsored_message->start_param_), std::move(content));
|
||||
CHECK(current_sponsored_message_id_ < std::numeric_limits<int32>::max());
|
||||
auto local_id = ++current_sponsored_message_id_;
|
||||
messages->message_random_ids[local_id] = sponsored_message->random_id_.as_slice().str();
|
||||
messages->messages.emplace_back(local_id, sponsor_dialog_id, std::move(sponsored_message->start_param_),
|
||||
std::move(content));
|
||||
}
|
||||
|
||||
for (auto &promise : promises) {
|
||||
@ -239,18 +246,24 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
|
||||
delete_cached_sponsored_messages_timeout_.set_timeout_in(dialog_id.get(), 300.0);
|
||||
}
|
||||
|
||||
void SponsoredMessageManager::view_sponsored_message(DialogId dialog_id, const string &message_id,
|
||||
void SponsoredMessageManager::view_sponsored_message(DialogId dialog_id, int32 sponsored_message_id,
|
||||
Promise<Unit> &&promise) {
|
||||
if (!td_->messages_manager_->have_dialog_force(dialog_id, "view_sponsored_message")) {
|
||||
return promise.set_error(Status::Error(400, "Chat not found"));
|
||||
}
|
||||
if (dialog_id.get_type() != DialogType::Channel ||
|
||||
td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) != ContactsManager::ChannelType::Broadcast ||
|
||||
message_id.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Message not found"));
|
||||
|
||||
auto it = dialog_sponsored_messages_.find(dialog_id);
|
||||
if (it == dialog_sponsored_messages_.end()) {
|
||||
return promise.set_value(Unit());
|
||||
}
|
||||
auto random_id_it = it->second->message_random_ids.find(sponsored_message_id);
|
||||
if (random_id_it == it->second->message_random_ids.end()) {
|
||||
return promise.set_value(Unit());
|
||||
}
|
||||
|
||||
td_->create_handler<ViewSponsoredMessageQuery>(std::move(promise))->send(dialog_id.get_channel_id(), message_id);
|
||||
auto random_id = std::move(random_id_it->second);
|
||||
it->second->message_random_ids.erase(random_id_it);
|
||||
td_->create_handler<ViewSponsoredMessageQuery>(std::move(promise))->send(dialog_id.get_channel_id(), random_id);
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -35,7 +35,7 @@ class SponsoredMessageManager final : public Actor {
|
||||
void get_dialog_sponsored_messages(DialogId dialog_id,
|
||||
Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise);
|
||||
|
||||
void view_sponsored_message(DialogId dialog_id, const string &message_id, Promise<Unit> &&promise);
|
||||
void view_sponsored_message(DialogId dialog_id, int32 sponsored_message_id, Promise<Unit> &&promise);
|
||||
|
||||
private:
|
||||
struct SponsoredMessage;
|
||||
@ -59,6 +59,8 @@ class SponsoredMessageManager final : public Actor {
|
||||
|
||||
std::unordered_map<DialogId, unique_ptr<DialogSponsoredMessages>, DialogIdHash> dialog_sponsored_messages_;
|
||||
|
||||
int32 current_sponsored_message_id_ = 0;
|
||||
|
||||
MultiTimeout delete_cached_sponsored_messages_timeout_{"DeleteCachedSponsoredMessagesTimeout"};
|
||||
|
||||
Td *td_;
|
||||
|
@ -3343,10 +3343,30 @@ void Td::invalidate_handler(ResultHandler *handler) {
|
||||
void Td::send(NetQueryPtr &&query) {
|
||||
VLOG(net_query) << "Send " << query << " to dispatcher";
|
||||
query->debug("Td: send to NetQueryDispatcher");
|
||||
query->set_callback(actor_shared(this, 1));
|
||||
G()->net_query_dispatcher().dispatch(std::move(query));
|
||||
}
|
||||
|
||||
void Td::on_update(BufferSlice &&update) {
|
||||
if (close_flag_ > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
TlBufferParser parser(&update);
|
||||
auto ptr = telegram_api::Updates::fetch(parser);
|
||||
parser.fetch_end();
|
||||
if (parser.get_error()) {
|
||||
LOG(ERROR) << "Failed to fetch update: " << parser.get_error() << format::as_hex_dump<4>(update.as_slice());
|
||||
updates_manager_->schedule_get_difference("failed to fetch update");
|
||||
} else {
|
||||
updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
|
||||
if (auth_manager_->is_bot() && auth_manager_->is_authorized()) {
|
||||
alarm_timeout_.set_timeout_in(PING_SERVER_ALARM_ID,
|
||||
PING_SERVER_TIMEOUT + Random::fast(0, PING_SERVER_TIMEOUT / 5));
|
||||
set_is_bot_online(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Td::on_result(NetQueryPtr query) {
|
||||
query->debug("Td: received from DcManager");
|
||||
VLOG(net_query) << "Receive result of " << query;
|
||||
@ -3354,30 +3374,6 @@ void Td::on_result(NetQueryPtr query) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (query->id() == 0) {
|
||||
if (query->is_error()) {
|
||||
query->clear();
|
||||
updates_manager_->schedule_get_difference("error in update");
|
||||
LOG(ERROR) << "Error in update";
|
||||
return;
|
||||
}
|
||||
auto ok = query->move_as_ok();
|
||||
TlBufferParser parser(&ok);
|
||||
auto ptr = telegram_api::Updates::fetch(parser);
|
||||
parser.fetch_end();
|
||||
if (parser.get_error()) {
|
||||
LOG(ERROR) << "Failed to fetch update: " << parser.get_error() << format::as_hex_dump<4>(ok.as_slice());
|
||||
updates_manager_->schedule_get_difference("failed to fetch update");
|
||||
} else {
|
||||
updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
|
||||
if (auth_manager_->is_bot() && auth_manager_->is_authorized()) {
|
||||
alarm_timeout_.set_timeout_in(PING_SERVER_ALARM_ID,
|
||||
PING_SERVER_TIMEOUT + Random::fast(0, PING_SERVER_TIMEOUT / 5));
|
||||
set_is_bot_online(true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto handler = extract_handler(query->id());
|
||||
if (handler == nullptr) {
|
||||
query->clear();
|
||||
@ -3575,7 +3571,7 @@ void Td::hangup_shared() {
|
||||
auto type = Container<int>::type_from_id(token);
|
||||
|
||||
if (type == RequestActorIdType) {
|
||||
request_actors_.erase(get_link_token());
|
||||
request_actors_.erase(token);
|
||||
dec_request_actor_refcnt();
|
||||
} else if (type == ActorIdType) {
|
||||
dec_actor_refcnt();
|
||||
@ -5042,7 +5038,7 @@ void Td::on_request(uint64 id, const td_api::getChatSponsoredMessages &request)
|
||||
void Td::on_request(uint64 id, const td_api::viewSponsoredMessage &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
sponsored_message_manager_->view_sponsored_message(DialogId(request.chat_id_), request.message_id_,
|
||||
sponsored_message_manager_->view_sponsored_message(DialogId(request.chat_id_), request.sponsored_message_id_,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,6 @@ class VideosManager;
|
||||
class VoiceNotesManager;
|
||||
class WebPagesManager;
|
||||
|
||||
} // namespace td
|
||||
|
||||
namespace td {
|
||||
|
||||
extern int VERBOSITY_NAME(td_init);
|
||||
extern int VERBOSITY_NAME(td_requests);
|
||||
extern int VERBOSITY_NAME(messages);
|
||||
@ -103,7 +99,7 @@ extern int VERBOSITY_NAME(add_pending_update);
|
||||
//
|
||||
// Parent needs a way to know that it will receive no more updates.
|
||||
// It happens after destruction of callback or after on_closed.
|
||||
class Td final : public NetQueryCallback {
|
||||
class Td final : public Actor {
|
||||
public:
|
||||
Td(const Td &) = delete;
|
||||
Td(Td &&) = delete;
|
||||
@ -125,7 +121,9 @@ class Td final : public NetQueryCallback {
|
||||
|
||||
void schedule_get_promo_data(int32 expires_in);
|
||||
|
||||
void on_result(NetQueryPtr query) final;
|
||||
void on_update(BufferSlice &&update);
|
||||
|
||||
void on_result(NetQueryPtr query);
|
||||
|
||||
void on_update_server_time_difference();
|
||||
|
||||
|
@ -2603,9 +2603,10 @@ class CliClient final : public Actor {
|
||||
send_request(td_api::make_object<td_api::getChatSponsoredMessages>(as_chat_id(args)));
|
||||
} else if (op == "vsm") {
|
||||
string chat_id;
|
||||
string message_id;
|
||||
get_args(args, chat_id, message_id);
|
||||
send_request(td_api::make_object<td_api::viewSponsoredMessage>(as_chat_id(chat_id), message_id));
|
||||
string sponsored_message_id;
|
||||
get_args(args, chat_id, sponsored_message_id);
|
||||
send_request(td_api::make_object<td_api::viewSponsoredMessage>(as_chat_id(chat_id),
|
||||
to_integer<int32>(sponsored_message_id)));
|
||||
} else if (op == "gmlink") {
|
||||
string chat_id;
|
||||
string message_id;
|
||||
|
@ -17,13 +17,11 @@
|
||||
#include <unordered_map>
|
||||
|
||||
namespace td {
|
||||
|
||||
namespace td_api {
|
||||
class storageStatistics;
|
||||
class storageStatisticsFast;
|
||||
} // namespace td_api
|
||||
} // namespace td
|
||||
|
||||
namespace td {
|
||||
|
||||
struct FileTypeStat {
|
||||
int64 size{0};
|
||||
|
@ -48,10 +48,6 @@ class StatsCallback;
|
||||
|
||||
class GetHostByNameActor;
|
||||
|
||||
} // namespace td
|
||||
|
||||
namespace td {
|
||||
|
||||
extern int VERBOSITY_NAME(connections);
|
||||
|
||||
class ConnectionCreator final : public NetQueryCallback {
|
||||
|
@ -354,6 +354,7 @@ class NetQuery final : public TsListNode<NetQueryDebug> {
|
||||
, answer_(std::move(answer))
|
||||
, tl_constructor_(tl_constructor)
|
||||
, total_timeout_limit_(total_timeout_limit) {
|
||||
CHECK(id_ != 0);
|
||||
auto &data = get_data_unsafe();
|
||||
data.my_id_ = get_my_id();
|
||||
data.start_timestamp_ = data.state_timestamp_ = Time::now();
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/Gzip.h"
|
||||
#include "td/utils/logging.h"
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "td/telegram/net/NetQueryStats.h"
|
||||
#include "td/telegram/UniqueId.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/ObjectPool.h"
|
||||
|
||||
#include <memory>
|
||||
@ -33,12 +32,6 @@ class NetQueryCreator {
|
||||
object_pool_.set_check_empty(false);
|
||||
}
|
||||
|
||||
NetQueryPtr create_update(BufferSlice &&buffer) {
|
||||
return object_pool_.create(NetQuery::State::OK, 0, BufferSlice(), std::move(buffer), DcId::main(),
|
||||
NetQuery::Type::Common, NetQuery::AuthFlag::On, NetQuery::GzipFlag::Off, 0, 0,
|
||||
net_query_stats_.get());
|
||||
}
|
||||
|
||||
NetQueryPtr create(const telegram_api::Function &function, DcId dc_id = DcId::main(),
|
||||
NetQuery::Type type = NetQuery::Type::Common);
|
||||
|
||||
|
@ -34,22 +34,20 @@ void NetQueryDispatcher::complete_net_query(NetQueryPtr net_query) {
|
||||
auto callback = net_query->move_callback();
|
||||
if (callback.empty()) {
|
||||
net_query->debug("sent to td (no callback)");
|
||||
send_closure(G()->td(), &NetQueryCallback::on_result, std::move(net_query));
|
||||
send_closure_later(G()->td(), &Td::on_result, std::move(net_query));
|
||||
} else {
|
||||
net_query->debug("sent to callback", true);
|
||||
send_closure(std::move(callback), &NetQueryCallback::on_result, std::move(net_query));
|
||||
send_closure_later(std::move(callback), &NetQueryCallback::on_result, std::move(net_query));
|
||||
}
|
||||
}
|
||||
|
||||
void NetQueryDispatcher::dispatch(NetQueryPtr net_query) {
|
||||
// net_query->debug("dispatch");
|
||||
if (stop_flag_.load(std::memory_order_relaxed)) {
|
||||
if (net_query->id() != 0) {
|
||||
net_query->set_error(Status::Error(500, "Request aborted"));
|
||||
}
|
||||
net_query->set_error(Status::Error(500, "Request aborted"));
|
||||
return complete_net_query(std::move(net_query));
|
||||
}
|
||||
if (net_query->id() != 0 && G()->shared_config().get_option_boolean("test_flood_wait")) {
|
||||
if (G()->shared_config().get_option_boolean("test_flood_wait")) {
|
||||
net_query->set_error(Status::Error(429, "Too Many Requests: retry after 10"));
|
||||
return complete_net_query(std::move(net_query));
|
||||
}
|
||||
|
@ -569,7 +569,8 @@ void Session::on_session_created(uint64 unique_id, uint64 first_id) {
|
||||
LOG(DEBUG) << "Sending updatesTooLong to force getDifference";
|
||||
BufferSlice packet(4);
|
||||
as<int32>(packet.as_slice().begin()) = telegram_api::updatesTooLong::ID;
|
||||
return_query(G()->net_query_creator().create_update(std::move(packet)));
|
||||
last_activity_timestamp_ = Time::now();
|
||||
callback_->on_update(std::move(packet));
|
||||
}
|
||||
|
||||
for (auto it = sent_queries_.begin(); it != sent_queries_.end();) {
|
||||
@ -710,15 +711,18 @@ void Session::mark_as_unknown(uint64 id, Query *query) {
|
||||
unknown_queries_.insert(id);
|
||||
}
|
||||
|
||||
Status Session::on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) {
|
||||
if (id == 0) {
|
||||
if (is_cdn_) {
|
||||
return Status::Error("Got update from CDN connection");
|
||||
}
|
||||
last_success_timestamp_ = Time::now();
|
||||
return_query(G()->net_query_creator().create_update(std::move(packet)));
|
||||
return Status::OK();
|
||||
Status Session::on_update(BufferSlice packet) {
|
||||
if (is_cdn_) {
|
||||
return Status::Error("Receive at update from CDN connection");
|
||||
}
|
||||
|
||||
last_success_timestamp_ = Time::now();
|
||||
last_activity_timestamp_ = Time::now();
|
||||
callback_->on_update(std::move(packet));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status Session::on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) {
|
||||
last_success_timestamp_ = Time::now();
|
||||
|
||||
TlParser parser(packet.as_slice());
|
||||
|
@ -61,9 +61,8 @@ class Session final
|
||||
virtual void request_raw_connection(unique_ptr<mtproto::AuthData> auth_data,
|
||||
Promise<unique_ptr<mtproto::RawConnection>>) = 0;
|
||||
virtual void on_tmp_auth_key_updated(mtproto::AuthKey auth_key) = 0;
|
||||
virtual void on_server_salt_updated(std::vector<mtproto::ServerSalt> server_salts) {
|
||||
}
|
||||
// one still have to call close after on_closed
|
||||
virtual void on_server_salt_updated(std::vector<mtproto::ServerSalt> server_salts) = 0;
|
||||
virtual void on_update(BufferSlice &&update) = 0;
|
||||
virtual void on_result(NetQueryPtr net_query) = 0;
|
||||
};
|
||||
|
||||
@ -206,6 +205,8 @@ class Session final
|
||||
|
||||
void on_container_sent(uint64 container_id, vector<uint64> msg_ids) final;
|
||||
|
||||
Status on_update(BufferSlice packet) final;
|
||||
|
||||
void on_message_ack(uint64 id) final;
|
||||
Status on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) final;
|
||||
void on_message_result_error(uint64 id, int error_code, string message) final;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "td/telegram/net/DcId.h"
|
||||
#include "td/telegram/net/NetQueryDispatcher.h"
|
||||
#include "td/telegram/net/Session.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/UniqueId.h"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
@ -58,9 +59,12 @@ class SessionCallback final : public Session::Callback {
|
||||
send_closure(parent_, &SessionProxy::on_server_salt_updated, std::move(server_salts));
|
||||
}
|
||||
|
||||
void on_update(BufferSlice &&update) final {
|
||||
send_closure_later(G()->td(), &Td::on_update, std::move(update));
|
||||
}
|
||||
|
||||
void on_result(NetQueryPtr query) final {
|
||||
if (UniqueId::extract_type(query->id()) != UniqueId::BindKey &&
|
||||
query->id() != 0) { // not bind key query and not an update
|
||||
if (UniqueId::extract_type(query->id()) != UniqueId::BindKey) {
|
||||
send_closure(parent_, &SessionProxy::on_query_finished);
|
||||
}
|
||||
G()->net_query_dispatcher().dispatch(std::move(query));
|
||||
@ -240,6 +244,7 @@ void SessionProxy::on_tmp_auth_key_updated(mtproto::AuthKey auth_key) {
|
||||
LOG(WARNING) << "Have tmp_auth_key " << auth_key.id() << ": " << state;
|
||||
tmp_auth_key_ = std::move(auth_key);
|
||||
}
|
||||
|
||||
void SessionProxy::on_server_salt_updated(std::vector<mtproto::ServerSalt> server_salts) {
|
||||
server_salts_ = std::move(server_salts);
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ TEST(MessageEntities, url) {
|
||||
check_url(".", {});
|
||||
check_url("http://@google.com", {});
|
||||
check_url("http://@goog.com", {}); // TODO: server fix
|
||||
check_url("http://@@google.com", {"http://@@google.com"});
|
||||
check_url("http://@@google.com", {});
|
||||
check_url("http://a@google.com", {"http://a@google.com"});
|
||||
check_url("http://test@google.com", {"http://test@google.com"});
|
||||
check_url("google.com:᪉᪉᪉᪉᪉", {"google.com"});
|
||||
@ -692,6 +692,8 @@ TEST(MessageEntities, url) {
|
||||
check_url(".?", {});
|
||||
check_url("http://test―‑@―google―.―com―/―–―‐―/―/―/―?―‑―#―――", {"http://test―‑@―google―.―com―/―–―‐―/―/―/―?―‑―#―――"});
|
||||
check_url("http://google.com/‖", {"http://google.com/"});
|
||||
check_url("a@b@c.com", {}, {});
|
||||
check_url("a@b.com:c@1", {}, {"a@b.com"});
|
||||
}
|
||||
|
||||
static void check_fix_formatted_text(td::string str, td::vector<td::MessageEntity> entities,
|
||||
|
Loading…
Reference in New Issue
Block a user