Merge remote-tracking branch 'td/master'
This commit is contained in:
commit
8e13003896
@ -280,6 +280,7 @@ set(TDLIB_SOURCE
|
||||
td/mtproto/Transport.cpp
|
||||
td/mtproto/utils.cpp
|
||||
|
||||
td/telegram/Account.cpp
|
||||
td/telegram/AnimationsManager.cpp
|
||||
td/telegram/AudiosManager.cpp
|
||||
td/telegram/AuthManager.cpp
|
||||
@ -458,6 +459,7 @@ set(TDLIB_SOURCE
|
||||
td/mtproto/utils.h
|
||||
|
||||
td/telegram/AccessRights.h
|
||||
td/telegram/Account.h
|
||||
td/telegram/AffectedHistory.h
|
||||
td/telegram/AnimationsManager.h
|
||||
td/telegram/AudiosManager.h
|
||||
|
220
build.html
220
build.html
@ -2,18 +2,185 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>TDLight build instructions</title>
|
||||
<style>
|
||||
.hide { display: none; }
|
||||
div.main { max-width:1200px; margin: auto; font-size: x-large; }
|
||||
select.large { font-size: large; }
|
||||
</style>
|
||||
<title>TDLight build instructions</title>
|
||||
<style>
|
||||
:root {
|
||||
--background: #fafafa;
|
||||
--color: black;
|
||||
--color-primary: #0088ff;
|
||||
--color-code-block: #ebf9ff;
|
||||
--color-select-border: rgb(211, 211, 211);
|
||||
--color-checkbox-background: rgb(211, 211, 211);
|
||||
--color-checkbox-tick: #ffffff;
|
||||
--color-copy-success-background: #c1ffc6;
|
||||
--color-copy-success-border: rgb(0, 255, 0);
|
||||
--color-copy-fail-background: #ffcbcb;
|
||||
--color-copy-fail-border: rgb(255, 0, 0);
|
||||
|
||||
color: var(--color);
|
||||
background: var(--background);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0e0e0e;
|
||||
--color: rgb(190, 190, 190);
|
||||
--color-primary: #0088ff;
|
||||
--color-code-block: #101315;
|
||||
--color-select-border: rgb(54, 54, 54);
|
||||
--color-checkbox-background: rgb(51, 51, 51);
|
||||
--color-checkbox-tick: #ffffff;
|
||||
--color-copy-success-background: #001f00;
|
||||
--color-copy-success-border: rgb(0, 255, 0);
|
||||
--color-copy-fail-background: #1f0000;
|
||||
--color-copy-fail-border: rgb(255, 0, 0);
|
||||
}
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
div.main {
|
||||
max-width: 1250px;
|
||||
padding: 25px;
|
||||
margin: auto;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
.main > div {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#buildCommands {
|
||||
font-family: Consolas, monospace;
|
||||
margin-left: 40px;
|
||||
background: var(--color-code-block);
|
||||
padding: 5px;
|
||||
margin-bottom: 0;
|
||||
display: block;
|
||||
}
|
||||
#buildCommands ul {
|
||||
list-style: '$ ';
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-primary);
|
||||
text-decoration-color: transparent;
|
||||
transition: text-decoration-color 200ms;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
select, button {
|
||||
border: 1px solid var(--color-select-border);
|
||||
background-color: var(--background);
|
||||
color: var(--color);
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
transition: border 200ms, padding 200ms;
|
||||
border-radius: 999em;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select:focus, button:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
border-width: 2px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
label * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
margin-right: 5px;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background-color: var(--color-checkbox-background);
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
transition: background-color 200ms;
|
||||
}
|
||||
input[type=checkbox]::after {
|
||||
content: "";
|
||||
transition: border-color 200ms;
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
top: 2px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid transparent;
|
||||
border-width: 0 3px 3px 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
input[type=checkbox]:checked {
|
||||
background-color: var(--color-primary);
|
||||
}
|
||||
input[type=checkbox]:checked::after {
|
||||
border-color: var(--color-checkbox-tick);
|
||||
}
|
||||
|
||||
input[type=radio] {
|
||||
margin-right: 5px;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background-color: var(--color-checkbox-background);
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 100%;
|
||||
position: relative;
|
||||
transition: background-color 200ms;
|
||||
}
|
||||
input[type=radio]::after {
|
||||
content: "";
|
||||
transition: border-color 200ms;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-radius: 100%;
|
||||
background-color: transparent;
|
||||
transition: width 200ms, height 200ms, left 200ms, top 200ms, background-color 100ms;
|
||||
}
|
||||
input[type=radio]:checked::after {
|
||||
background-color: var(--color-primary);
|
||||
left: 2px;
|
||||
top: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#copyBuildCommandsButton {
|
||||
margin-left: 40px;
|
||||
}
|
||||
#copyBuildCommandsButton.success {
|
||||
background: var(--color-copy-success-background);
|
||||
border-color: var(--color-copy-success-border);
|
||||
}
|
||||
#copyBuildCommandsButton.fail {
|
||||
background: var(--color-copy-fail-background);
|
||||
border-color: var(--color-copy-fail-border);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="onLoad(true)" onpopstate="onLoad(false)">
|
||||
|
||||
<div class="main">
|
||||
<div id="languageSelectDiv" style="text-align:center;">
|
||||
<div id="languageSelectDiv">
|
||||
<p>Choose a programming language, from which you want to use TDLight:</p>
|
||||
<select id="languageSelect" onchange="onLanguageChanged(false)" autofocus class="large">
|
||||
<option>Choose a programming language:</option>
|
||||
@ -44,7 +211,7 @@ select.large { font-size: large; }
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="osSelectDiv" class="hide" style="text-align:center;">
|
||||
<div id="osSelectDiv" class="hide">
|
||||
<p>Choose an operating system, on which you want to use TDLight:</p>
|
||||
<select id="osSelect" onchange="onOsChanged()" class="large">
|
||||
<option>Choose an operating system:</option>
|
||||
@ -52,7 +219,7 @@ select.large { font-size: large; }
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<div id="linuxSelectDiv" class="hide" style="text-align:center;">
|
||||
<div id="linuxSelectDiv" class="hide">
|
||||
<p>Choose a Linux distro, on which you want to use TDLight:</p>
|
||||
<select id="linuxSelect" onchange="onOsChanged()" class="large">
|
||||
<option>Choose a Linux distro:</option>
|
||||
@ -71,7 +238,7 @@ select.large { font-size: large; }
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<div id="buildOptionsDiv" class="hide" style="text-align:center;">
|
||||
<div id="buildOptionsDiv" class="hide">
|
||||
<div id="buildLtoDiv" class="hide">
|
||||
<label><input type="checkbox" id="buildLtoCheckbox" onchange="onOptionsChanged()"/>Enable Link Time Optimization (requires CMake >= 3.9.0). It can significantly reduce binary size and increase performance, but sometimes it can lead to build failures.</label>
|
||||
</div>
|
||||
@ -133,14 +300,17 @@ select.large { font-size: large; }
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<div id="buildTextDiv" class="hide" style="text-align:center;">
|
||||
<div id="buildTextDiv" class="hide">
|
||||
<p id="buildText">Hidden text</p>
|
||||
</div>
|
||||
|
||||
<div id="buildCommandsDiv" class="hide" style="text-align:left;">
|
||||
<p id="buildCommandsHeader" style="text-align:center;">Here is complete instruction for TDLight binaries building:</p>
|
||||
<div id="buildCommandsDiv" class="hide">
|
||||
<p id="buildCommandsHeader">Here is complete instruction for TDLight binaries building:</p>
|
||||
<p id="buildPre">Hidden text</p>
|
||||
<code id="buildCommands">Empty commands</code>
|
||||
<button id="copyBuildCommandsButton" onclick="copyBuildInstructions()">
|
||||
<span id="copyBuildCommandsText">Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -543,7 +713,7 @@ function onOptionsChanged() {
|
||||
pre_text.push('Note that the following instruction is for NetBSD 8.0 and default SH shell.');
|
||||
}
|
||||
if (os_mac) {
|
||||
pre_text.push('Note that the following instruction will build TDLib only for the current architecture (x64 or Apple silicon).');
|
||||
pre_text.push('Note that the following instruction will build TDLight only for the current architecture (x64 or Apple silicon).');
|
||||
pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlight-team/tdlight/tree/master/example/ios">example</a> instead.');
|
||||
}
|
||||
|
||||
@ -573,7 +743,7 @@ function onOptionsChanged() {
|
||||
document.getElementById('buildPre').style.display = 'block';
|
||||
|
||||
if (install_dir && install_dir !== '/usr/local') {
|
||||
install_dir = '../tdlib';
|
||||
install_dir = '../tdlight';
|
||||
if (target === 'JNI' || target === 'C++/CX') {
|
||||
install_dir = '../../' + install_dir;
|
||||
}
|
||||
@ -903,6 +1073,26 @@ function onOptionsChanged() {
|
||||
commands.push((use_powershell ? 'dir ' : 'ls -l ') + install_dir);
|
||||
}
|
||||
document.getElementById('buildCommands').innerHTML = '<ul><li>' + commands.join('</li><li>') + '</li></ul>';
|
||||
document.getElementById('copyBuildCommandsButton').style.display = commands.includes('exit') ? 'none' : 'block';
|
||||
}
|
||||
|
||||
function copyBuildInstructions() {
|
||||
var text = document.getElementById('buildCommands').innerText;
|
||||
|
||||
function resetButtonState (state) {
|
||||
document.getElementById('copyBuildCommandsButton').classList.remove(state);
|
||||
document.getElementById('copyBuildCommandsText').innerText = "Copy";
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(text).then(result => {
|
||||
document.getElementById('copyBuildCommandsButton').classList.add('success');
|
||||
document.getElementById('copyBuildCommandsText').innerText = "Copied!";
|
||||
setTimeout(() => resetButtonState('success'), 5000);
|
||||
}, error => {
|
||||
document.getElementById('copyBuildCommandsButton').classList.add('fail');
|
||||
document.getElementById('copyBuildCommandsText').innerText = "Couldn't copy :(";
|
||||
setTimeout(() => resetButtonState('fail'), 5000);
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -13,8 +13,7 @@ import sys
|
||||
# load shared library
|
||||
tdjson_path = find_library('tdjson') or 'tdjson.dll'
|
||||
if tdjson_path is None:
|
||||
print('can\'t find tdjson library')
|
||||
quit()
|
||||
sys.exit("Can't find 'tdjson' library")
|
||||
tdjson = CDLL(tdjson_path)
|
||||
|
||||
# load TDLib functions from shared library
|
||||
@ -43,8 +42,7 @@ _td_set_log_message_callback.argtypes = [c_int, log_message_callback_type]
|
||||
# initialize TDLib log with desired parameters
|
||||
def on_log_message_callback(verbosity_level, message):
|
||||
if verbosity_level == 0:
|
||||
print('TDLib fatal error: ', message)
|
||||
sys.stdout.flush()
|
||||
sys.exit('TDLib fatal error: %r' % message)
|
||||
|
||||
def td_execute(query):
|
||||
query = json.dumps(query).encode('utf-8')
|
||||
|
@ -600,7 +600,7 @@ chatInviteLinks total_count:int32 invite_links:vector<chatInviteLink> = ChatInvi
|
||||
//@revoked_invite_link_count Number of revoked invite links
|
||||
chatInviteLinkCount user_id:int53 invite_link_count:int32 revoked_invite_link_count:int32 = ChatInviteLinkCount;
|
||||
|
||||
//@description Contains a list of chat invite link counts @invite_link_counts List of invite linkcounts
|
||||
//@description Contains a list of chat invite link counts @invite_link_counts List of invite link counts
|
||||
chatInviteLinkCounts invite_link_counts:vector<chatInviteLinkCount> = ChatInviteLinkCounts;
|
||||
|
||||
//@description Describes a chat member joined a chat by an invite link @user_id User identifier @joined_chat_date Point in time (Unix timestamp) when the user joined the chat @approver_user_id User identifier of the chat administrator, approved user join request
|
||||
|
@ -301,6 +301,13 @@ std::string TD_TL_writer_cpp::get_pretty_field_name(std::string field_name) cons
|
||||
}
|
||||
|
||||
std::string TD_TL_writer_cpp::get_pretty_class_name(std::string class_name) const {
|
||||
if (tl_name != "mtproto_api") {
|
||||
for (std::size_t i = 0; i < class_name.size(); i++) {
|
||||
if (class_name[i] == '_') {
|
||||
class_name[i] = '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
return class_name;
|
||||
}
|
||||
|
||||
|
371
td/telegram/Account.cpp
Normal file
371
td/telegram/Account.cpp
Normal file
@ -0,0 +1,371 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/Account.h"
|
||||
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/DeviceTokenManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/net/NetQueryCreator.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace td {
|
||||
|
||||
static td_api::object_ptr<td_api::session> convert_authorization_object(
|
||||
tl_object_ptr<telegram_api::authorization> &&authorization) {
|
||||
CHECK(authorization != nullptr);
|
||||
return td_api::make_object<td_api::session>(
|
||||
authorization->hash_, authorization->current_, authorization->password_pending_, authorization->api_id_,
|
||||
authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_,
|
||||
authorization->platform_, authorization->system_version_, authorization->date_created_,
|
||||
authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_);
|
||||
}
|
||||
|
||||
class SetAccountTtlQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit SetAccountTtlQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(int32 account_ttl) {
|
||||
send_query(G()->net_query_creator().create(
|
||||
telegram_api::account_setAccountTTL(make_tl_object<telegram_api::accountDaysTTL>(account_ttl))));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_setAccountTTL>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
if (!result) {
|
||||
return on_error(Status::Error(500, "Internal Server Error: failed to set account TTL"));
|
||||
}
|
||||
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetAccountTtlQuery final : public Td::ResultHandler {
|
||||
Promise<int32> promise_;
|
||||
|
||||
public:
|
||||
explicit GetAccountTtlQuery(Promise<int32> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_getAccountTTL()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_getAccountTTL>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for GetAccountTtlQuery: " << to_string(ptr);
|
||||
|
||||
promise_.set_value(std::move(ptr->days_));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class AcceptLoginTokenQuery final : public Td::ResultHandler {
|
||||
Promise<td_api::object_ptr<td_api::session>> promise_;
|
||||
|
||||
public:
|
||||
explicit AcceptLoginTokenQuery(Promise<td_api::object_ptr<td_api::session>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(const string &login_token) {
|
||||
send_query(G()->net_query_creator().create(telegram_api::auth_acceptLoginToken(BufferSlice(login_token))));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::auth_acceptLoginToken>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
LOG(DEBUG) << "Receive result for AcceptLoginTokenQuery: " << to_string(result_ptr.ok());
|
||||
promise_.set_value(convert_authorization_object(result_ptr.move_as_ok()));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<td_api::object_ptr<td_api::sessions>> promise_;
|
||||
|
||||
public:
|
||||
explicit GetAuthorizationsQuery(Promise<td_api::object_ptr<td_api::sessions>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_getAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_getAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for GetAuthorizationsQuery: " << to_string(ptr);
|
||||
|
||||
auto results =
|
||||
td_api::make_object<td_api::sessions>(transform(std::move(ptr->authorizations_), convert_authorization_object));
|
||||
std::sort(results->sessions_.begin(), results->sessions_.end(),
|
||||
[](const td_api::object_ptr<td_api::session> &lhs, const td_api::object_ptr<td_api::session> &rhs) {
|
||||
if (lhs->is_current_ != rhs->is_current_) {
|
||||
return lhs->is_current_;
|
||||
}
|
||||
if (lhs->is_password_pending_ != rhs->is_password_pending_) {
|
||||
return lhs->is_password_pending_;
|
||||
}
|
||||
return lhs->last_active_date_ > rhs->last_active_date_;
|
||||
});
|
||||
|
||||
promise_.set_value(std::move(results));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetAuthorizationQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetAuthorizationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(int64 authorization_id) {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_resetAuthorization(authorization_id)));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_resetAuthorization>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to terminate session";
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetAuthorizationsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::auth_resetAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::auth_resetAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to terminate all sessions";
|
||||
send_closure(td_->device_token_manager_, &DeviceTokenManager::reregister_device);
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetWebAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<td_api::object_ptr<td_api::connectedWebsites>> promise_;
|
||||
|
||||
public:
|
||||
explicit GetWebAuthorizationsQuery(Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_getWebAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_getWebAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for GetWebAuthorizationsQuery: " << to_string(ptr);
|
||||
|
||||
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetWebAuthorizationsQuery");
|
||||
|
||||
auto results = td_api::make_object<td_api::connectedWebsites>();
|
||||
results->websites_.reserve(ptr->authorizations_.size());
|
||||
for (auto &authorization : ptr->authorizations_) {
|
||||
CHECK(authorization != nullptr);
|
||||
UserId bot_user_id(authorization->bot_id_);
|
||||
if (!bot_user_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid bot " << bot_user_id;
|
||||
bot_user_id = UserId();
|
||||
}
|
||||
|
||||
results->websites_.push_back(td_api::make_object<td_api::connectedWebsite>(
|
||||
authorization->hash_, authorization->domain_,
|
||||
td_->contacts_manager_->get_user_id_object(bot_user_id, "GetWebAuthorizationsQuery"), authorization->browser_,
|
||||
authorization->platform_, authorization->date_created_, authorization->date_active_, authorization->ip_,
|
||||
authorization->region_));
|
||||
}
|
||||
|
||||
promise_.set_value(std::move(results));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetWebAuthorizationQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetWebAuthorizationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(int64 hash) {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_resetWebAuthorization(hash)));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_resetWebAuthorization>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to disconnect website";
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetWebAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetWebAuthorizationsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_resetWebAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_resetWebAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to disconnect all websites";
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
void set_account_ttl(Td *td, int32 account_ttl, Promise<Unit> &&promise) {
|
||||
td->create_handler<SetAccountTtlQuery>(std::move(promise))->send(account_ttl);
|
||||
}
|
||||
|
||||
void get_account_ttl(Td *td, Promise<int32> &&promise) {
|
||||
td->create_handler<GetAccountTtlQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void confirm_qr_code_authentication(Td *td, const string &link,
|
||||
Promise<td_api::object_ptr<td_api::session>> &&promise) {
|
||||
Slice prefix("tg://login?token=");
|
||||
if (!begins_with(to_lower(link), prefix)) {
|
||||
return promise.set_error(Status::Error(400, "AUTH_TOKEN_INVALID"));
|
||||
}
|
||||
auto r_token = base64url_decode(Slice(link).substr(prefix.size()));
|
||||
if (r_token.is_error()) {
|
||||
return promise.set_error(Status::Error(400, "AUTH_TOKEN_INVALID"));
|
||||
}
|
||||
td->create_handler<AcceptLoginTokenQuery>(std::move(promise))->send(r_token.ok());
|
||||
}
|
||||
|
||||
void get_active_sessions(Td *td, Promise<td_api::object_ptr<td_api::sessions>> &&promise) {
|
||||
td->create_handler<GetAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void terminate_session(Td *td, int64 session_id, Promise<Unit> &&promise) {
|
||||
td->create_handler<ResetAuthorizationQuery>(std::move(promise))->send(session_id);
|
||||
}
|
||||
|
||||
void terminate_all_other_sessions(Td *td, Promise<Unit> &&promise) {
|
||||
td->create_handler<ResetAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void get_connected_websites(Td *td, Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise) {
|
||||
td->create_handler<GetWebAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void disconnect_website(Td *td, int64 website_id, Promise<Unit> &&promise) {
|
||||
td->create_handler<ResetWebAuthorizationQuery>(std::move(promise))->send(website_id);
|
||||
}
|
||||
|
||||
void disconnect_all_websites(Td *td, Promise<Unit> &&promise) {
|
||||
td->create_handler<ResetWebAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
} // namespace td
|
37
td/telegram/Account.h
Normal file
37
td/telegram/Account.h
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
class Td;
|
||||
|
||||
void set_account_ttl(Td *td, int32 account_ttl, Promise<Unit> &&promise);
|
||||
|
||||
void get_account_ttl(Td *td, Promise<int32> &&promise);
|
||||
|
||||
void confirm_qr_code_authentication(Td *td, const string &link, Promise<td_api::object_ptr<td_api::session>> &&promise);
|
||||
|
||||
void get_active_sessions(Td *td, Promise<td_api::object_ptr<td_api::sessions>> &&promise);
|
||||
|
||||
void terminate_session(Td *td, int64 session_id, Promise<Unit> &&promise);
|
||||
|
||||
void terminate_all_other_sessions(Td *td, Promise<Unit> &&promise);
|
||||
|
||||
void get_connected_websites(Td *td, Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise);
|
||||
|
||||
void disconnect_website(Td *td, int64 website_id, Promise<Unit> &&promise);
|
||||
|
||||
void disconnect_all_websites(Td *td, Promise<Unit> &&promise);
|
||||
|
||||
} // namespace td
|
@ -55,7 +55,6 @@
|
||||
#include "td/actor/SleepActor.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
@ -107,290 +106,6 @@ class DismissSuggestionQuery final : public Td::ResultHandler {
|
||||
}
|
||||
};
|
||||
|
||||
class SetAccountTtlQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit SetAccountTtlQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(int32 account_ttl) {
|
||||
send_query(G()->net_query_creator().create(
|
||||
telegram_api::account_setAccountTTL(make_tl_object<telegram_api::accountDaysTTL>(account_ttl))));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_setAccountTTL>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
if (!result) {
|
||||
return on_error(Status::Error(500, "Internal Server Error: failed to set account TTL"));
|
||||
}
|
||||
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetAccountTtlQuery final : public Td::ResultHandler {
|
||||
Promise<int32> promise_;
|
||||
|
||||
public:
|
||||
explicit GetAccountTtlQuery(Promise<int32> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_getAccountTTL()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_getAccountTTL>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for GetAccountTtlQuery: " << to_string(ptr);
|
||||
|
||||
promise_.set_value(std::move(ptr->days_));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class AcceptLoginTokenQuery final : public Td::ResultHandler {
|
||||
Promise<td_api::object_ptr<td_api::session>> promise_;
|
||||
|
||||
public:
|
||||
explicit AcceptLoginTokenQuery(Promise<td_api::object_ptr<td_api::session>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(const string &login_token) {
|
||||
send_query(G()->net_query_creator().create(telegram_api::auth_acceptLoginToken(BufferSlice(login_token))));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::auth_acceptLoginToken>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
LOG(DEBUG) << "Receive result for AcceptLoginTokenQuery: " << to_string(result_ptr.ok());
|
||||
promise_.set_value(ContactsManager::convert_authorization_object(result_ptr.move_as_ok()));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<tl_object_ptr<td_api::sessions>> promise_;
|
||||
|
||||
public:
|
||||
explicit GetAuthorizationsQuery(Promise<tl_object_ptr<td_api::sessions>> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_getAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_getAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for GetAuthorizationsQuery: " << to_string(ptr);
|
||||
|
||||
auto results = make_tl_object<td_api::sessions>(
|
||||
transform(std::move(ptr->authorizations_), ContactsManager::convert_authorization_object));
|
||||
std::sort(results->sessions_.begin(), results->sessions_.end(),
|
||||
[](const td_api::object_ptr<td_api::session> &lhs, const td_api::object_ptr<td_api::session> &rhs) {
|
||||
if (lhs->is_current_ != rhs->is_current_) {
|
||||
return lhs->is_current_;
|
||||
}
|
||||
if (lhs->is_password_pending_ != rhs->is_password_pending_) {
|
||||
return lhs->is_password_pending_;
|
||||
}
|
||||
return lhs->last_active_date_ > rhs->last_active_date_;
|
||||
});
|
||||
|
||||
promise_.set_value(std::move(results));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetAuthorizationQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetAuthorizationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(int64 authorization_id) {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_resetAuthorization(authorization_id)));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_resetAuthorization>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to terminate session";
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetAuthorizationsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::auth_resetAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::auth_resetAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to terminate all sessions";
|
||||
send_closure(td_->device_token_manager_, &DeviceTokenManager::reregister_device);
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetWebAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<tl_object_ptr<td_api::connectedWebsites>> promise_;
|
||||
|
||||
public:
|
||||
explicit GetWebAuthorizationsQuery(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_getWebAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_getWebAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for GetWebAuthorizationsQuery: " << to_string(ptr);
|
||||
|
||||
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetWebAuthorizationsQuery");
|
||||
|
||||
auto results = make_tl_object<td_api::connectedWebsites>();
|
||||
results->websites_.reserve(ptr->authorizations_.size());
|
||||
for (auto &authorization : ptr->authorizations_) {
|
||||
CHECK(authorization != nullptr);
|
||||
UserId bot_user_id(authorization->bot_id_);
|
||||
if (!bot_user_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid bot " << bot_user_id;
|
||||
bot_user_id = UserId();
|
||||
}
|
||||
|
||||
results->websites_.push_back(make_tl_object<td_api::connectedWebsite>(
|
||||
authorization->hash_, authorization->domain_,
|
||||
td_->contacts_manager_->get_user_id_object(bot_user_id, "GetWebAuthorizationsQuery"), authorization->browser_,
|
||||
authorization->platform_, authorization->date_created_, authorization->date_active_, authorization->ip_,
|
||||
authorization->region_));
|
||||
}
|
||||
|
||||
promise_.set_value(std::move(results));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetWebAuthorizationQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetWebAuthorizationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(int64 hash) {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_resetWebAuthorization(hash)));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_resetWebAuthorization>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to disconnect website";
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class ResetWebAuthorizationsQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
|
||||
public:
|
||||
explicit ResetWebAuthorizationsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send() {
|
||||
send_query(G()->net_query_creator().create(telegram_api::account_resetWebAuthorizations()));
|
||||
}
|
||||
|
||||
void on_result(BufferSlice packet) final {
|
||||
auto result_ptr = fetch_result<telegram_api::account_resetWebAuthorizations>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
bool result = result_ptr.move_as_ok();
|
||||
LOG_IF(WARNING, !result) << "Failed to disconnect all websites";
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
class GetContactsQuery final : public Td::ResultHandler {
|
||||
public:
|
||||
void send(int64 hash) {
|
||||
@ -5224,61 +4939,6 @@ td_api::object_ptr<td_api::CheckChatUsernameResult> ContactsManager::get_check_c
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::set_account_ttl(int32 account_ttl, Promise<Unit> &&promise) const {
|
||||
td_->create_handler<SetAccountTtlQuery>(std::move(promise))->send(account_ttl);
|
||||
}
|
||||
|
||||
void ContactsManager::get_account_ttl(Promise<int32> &&promise) const {
|
||||
td_->create_handler<GetAccountTtlQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::session> ContactsManager::convert_authorization_object(
|
||||
tl_object_ptr<telegram_api::authorization> &&authorization) {
|
||||
CHECK(authorization != nullptr);
|
||||
return td_api::make_object<td_api::session>(
|
||||
authorization->hash_, authorization->current_, authorization->password_pending_, authorization->api_id_,
|
||||
authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_,
|
||||
authorization->platform_, authorization->system_version_, authorization->date_created_,
|
||||
authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_);
|
||||
}
|
||||
|
||||
void ContactsManager::confirm_qr_code_authentication(const string &link,
|
||||
Promise<td_api::object_ptr<td_api::session>> &&promise) {
|
||||
Slice prefix("tg://login?token=");
|
||||
if (!begins_with(to_lower(link), prefix)) {
|
||||
return promise.set_error(Status::Error(400, "AUTH_TOKEN_INVALID"));
|
||||
}
|
||||
auto r_token = base64url_decode(Slice(link).substr(prefix.size()));
|
||||
if (r_token.is_error()) {
|
||||
return promise.set_error(Status::Error(400, "AUTH_TOKEN_INVALID"));
|
||||
}
|
||||
td_->create_handler<AcceptLoginTokenQuery>(std::move(promise))->send(r_token.ok());
|
||||
}
|
||||
|
||||
void ContactsManager::get_active_sessions(Promise<tl_object_ptr<td_api::sessions>> &&promise) const {
|
||||
td_->create_handler<GetAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void ContactsManager::terminate_session(int64 session_id, Promise<Unit> &&promise) const {
|
||||
td_->create_handler<ResetAuthorizationQuery>(std::move(promise))->send(session_id);
|
||||
}
|
||||
|
||||
void ContactsManager::terminate_all_other_sessions(Promise<Unit> &&promise) const {
|
||||
td_->create_handler<ResetAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void ContactsManager::get_connected_websites(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise) const {
|
||||
td_->create_handler<GetWebAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void ContactsManager::disconnect_website(int64 website_id, Promise<Unit> &&promise) const {
|
||||
td_->create_handler<ResetWebAuthorizationQuery>(std::move(promise))->send(website_id);
|
||||
}
|
||||
|
||||
void ContactsManager::disconnect_all_websites(Promise<Unit> &&promise) const {
|
||||
td_->create_handler<ResetWebAuthorizationsQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
bool ContactsManager::is_valid_username(const string &username) {
|
||||
if (username.size() < 5 || username.size() > 32) {
|
||||
return false;
|
||||
|
@ -275,22 +275,6 @@ class ContactsManager final : public Actor {
|
||||
static td_api::object_ptr<td_api::CheckChatUsernameResult> get_check_chat_username_result_object(
|
||||
CheckDialogUsernameResult result);
|
||||
|
||||
void set_account_ttl(int32 account_ttl, Promise<Unit> &&promise) const;
|
||||
void get_account_ttl(Promise<int32> &&promise) const;
|
||||
|
||||
static td_api::object_ptr<td_api::session> convert_authorization_object(
|
||||
tl_object_ptr<telegram_api::authorization> &&authorization);
|
||||
|
||||
void confirm_qr_code_authentication(const string &link, Promise<td_api::object_ptr<td_api::session>> &&promise);
|
||||
|
||||
void get_active_sessions(Promise<tl_object_ptr<td_api::sessions>> &&promise) const;
|
||||
void terminate_session(int64 session_id, Promise<Unit> &&promise) const;
|
||||
void terminate_all_other_sessions(Promise<Unit> &&promise) const;
|
||||
|
||||
void get_connected_websites(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise) const;
|
||||
void disconnect_website(int64 website_id, Promise<Unit> &&promise) const;
|
||||
void disconnect_all_websites(Promise<Unit> &&promise) const;
|
||||
|
||||
void add_contact(Contact contact, bool share_phone_number, Promise<Unit> &&promise);
|
||||
|
||||
std::pair<vector<UserId>, vector<int32>> import_contacts(const vector<Contact> &contacts, int64 &random_id,
|
||||
|
@ -94,7 +94,9 @@ void parse(Document &document, ParserT &parser) {
|
||||
break;
|
||||
case Document::Type::Unknown:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
LOG(ERROR) << "Have invalid Document type " << static_cast<int32>(document.type);
|
||||
document = Document();
|
||||
return;
|
||||
}
|
||||
if (!document.file_id.is_valid()) {
|
||||
LOG(ERROR) << "Parse invalid document.file_id";
|
||||
|
@ -2849,6 +2849,15 @@ int32 get_message_content_live_location_period(const MessageContent *content) {
|
||||
}
|
||||
}
|
||||
|
||||
bool get_message_content_poll_is_anonymous(const Td *td, const MessageContent *content) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Poll:
|
||||
return td->poll_manager_->get_poll_is_anonymous(static_cast<const MessagePoll *>(content)->poll_id);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_message_content_poll_is_closed(const Td *td, const MessageContent *content) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Poll:
|
||||
|
@ -147,6 +147,8 @@ UserId get_message_content_deleted_user_id(const MessageContent *content);
|
||||
|
||||
int32 get_message_content_live_location_period(const MessageContent *content);
|
||||
|
||||
bool get_message_content_poll_is_anonymous(const Td *td, const MessageContent *content);
|
||||
|
||||
bool get_message_content_poll_is_closed(const Td *td, const MessageContent *content);
|
||||
|
||||
bool has_message_content_web_page(const MessageContent *content);
|
||||
|
@ -7054,7 +7054,7 @@ void MessagesManager::on_update_delete_scheduled_messages(DialogId dialog_id,
|
||||
void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id,
|
||||
DialogId typing_dialog_id, DialogAction action, int32 date,
|
||||
MessageContentType message_content_type) {
|
||||
if (td_->auth_manager_->is_bot() || !typing_dialog_id.is_valid() || is_broadcast_channel(dialog_id)) {
|
||||
if (td_->auth_manager_->is_bot() || !typing_dialog_id.is_valid()) {
|
||||
return;
|
||||
}
|
||||
if (top_thread_message_id != MessageId() && !top_thread_message_id.is_valid()) {
|
||||
@ -7076,6 +7076,10 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_broadcast_channel(dialog_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typing_dialog_id.get_type() != DialogType::User) {
|
||||
LOG(ERROR) << "Ignore " << action << " of " << typing_dialog_id << " in " << dialog_id;
|
||||
return;
|
||||
@ -17371,6 +17375,7 @@ Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Messag
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return Status::Error(400, "User is bot");
|
||||
}
|
||||
CHECK(m != nullptr);
|
||||
if (!m->is_outgoing) {
|
||||
return Status::Error(400, "Can't get viewers of incoming messages");
|
||||
}
|
||||
@ -17407,7 +17412,7 @@ Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Messag
|
||||
if (participant_count == 0) {
|
||||
return Status::Error(400, "Chat is empty or have unknown number of members");
|
||||
}
|
||||
if (participant_count > G()->shared_config().get_option_integer("chat_read_mark_size_threshold", 50)) {
|
||||
if (participant_count > G()->shared_config().get_option_integer("chat_read_mark_size_threshold", 100)) {
|
||||
return Status::Error(400, "Chat is too big");
|
||||
}
|
||||
|
||||
@ -17422,6 +17427,10 @@ Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Messag
|
||||
}
|
||||
CHECK(m->message_id.is_server());
|
||||
|
||||
if (m->content->get_type() == MessageContentType::Poll &&
|
||||
get_message_content_poll_is_anonymous(td_, m->content.get())) {
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/AuthManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
@ -68,14 +67,12 @@ class RequestActor : public Actor {
|
||||
if (future_.is_error()) {
|
||||
auto error = future_.move_as_error();
|
||||
if (error == Status::Error<FutureActor<T>::HANGUP_ERROR_CODE>()) {
|
||||
// dropping query due to lost authorization or lost promise
|
||||
// dropping query due to closing or lost promise
|
||||
if (G()->close_flag()) {
|
||||
do_send_error(Global::request_aborted_error());
|
||||
} else if (!td_->auth_manager_->is_authorized()) {
|
||||
} else {
|
||||
LOG(ERROR) << "Promise was lost";
|
||||
do_send_error(Status::Error(500, "Query can't be answered due to a bug in TDLib"));
|
||||
} else {
|
||||
do_send_error(Status::Error(401, "Unauthorized"));
|
||||
}
|
||||
return stop();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#include "td/telegram/Td.h"
|
||||
|
||||
#include "td/telegram/Account.h"
|
||||
#include "td/telegram/AnimationsManager.h"
|
||||
#include "td/telegram/AudiosManager.h"
|
||||
#include "td/telegram/AuthManager.h"
|
||||
@ -4565,7 +4566,7 @@ void Td::on_request(uint64 id, td_api::checkAuthenticationBotToken &request) {
|
||||
void Td::on_request(uint64 id, td_api::confirmQrCodeAuthentication &request) {
|
||||
CLEAN_INPUT_STRING(request.link_);
|
||||
CREATE_REQUEST_PROMISE();
|
||||
contacts_manager_->confirm_qr_code_authentication(request.link_, std::move(promise));
|
||||
confirm_qr_code_authentication(this, request.link_, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getCurrentState &request) {
|
||||
@ -4762,7 +4763,7 @@ void Td::on_request(uint64 id, const td_api::getAccountTtl &request) {
|
||||
promise.set_value(td_api::make_object<td_api::accountTtl>(result.ok()));
|
||||
}
|
||||
});
|
||||
contacts_manager_->get_account_ttl(std::move(query_promise));
|
||||
get_account_ttl(this, std::move(query_promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::setAccountTtl &request) {
|
||||
@ -4771,7 +4772,7 @@ void Td::on_request(uint64 id, const td_api::setAccountTtl &request) {
|
||||
return send_error_raw(id, 400, "New account TTL must be non-empty");
|
||||
}
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
contacts_manager_->set_account_ttl(request.ttl_->days_, std::move(promise));
|
||||
set_account_ttl(this, request.ttl_->days_, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, td_api::deleteAccount &request) {
|
||||
@ -4801,37 +4802,37 @@ void Td::on_request(uint64 id, td_api::resendChangePhoneNumberCode &request) {
|
||||
void Td::on_request(uint64 id, const td_api::getActiveSessions &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_REQUEST_PROMISE();
|
||||
contacts_manager_->get_active_sessions(std::move(promise));
|
||||
get_active_sessions(this, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::terminateSession &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
contacts_manager_->terminate_session(request.session_id_, std::move(promise));
|
||||
terminate_session(this, request.session_id_, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::terminateAllOtherSessions &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
contacts_manager_->terminate_all_other_sessions(std::move(promise));
|
||||
terminate_all_other_sessions(this, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getConnectedWebsites &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_REQUEST_PROMISE();
|
||||
contacts_manager_->get_connected_websites(std::move(promise));
|
||||
get_connected_websites(this, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::disconnectWebsite &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
contacts_manager_->disconnect_website(request.website_id_, std::move(promise));
|
||||
disconnect_website(this, request.website_id_, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::disconnectAllWebsites &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
contacts_manager_->disconnect_all_websites(std::move(promise));
|
||||
disconnect_all_websites(this, std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getMe &request) {
|
||||
|
@ -315,7 +315,7 @@ Status TdDb::init_sqlite(int32 scheduler_id, const TdParameters ¶meters, con
|
||||
|
||||
// Get 'PRAGMA user_version'
|
||||
TRY_RESULT(user_version, db.user_version());
|
||||
LOG(WARNING) << "Got PRAGMA user_version = " << user_version;
|
||||
LOG(INFO) << "Got PRAGMA user_version = " << user_version;
|
||||
|
||||
// init DialogDb
|
||||
bool dialog_db_was_created = false;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/NullLog.h"
|
||||
#include "td/utils/OptionParser.h"
|
||||
#include "td/utils/port/detail/ThreadIdGuard.h"
|
||||
#include "td/utils/port/FileFd.h"
|
||||
#include "td/utils/port/PollFlags.h"
|
||||
#include "td/utils/port/signals.h"
|
||||
@ -4596,6 +4597,7 @@ static void on_log_message(int verbosity_level, const char *message) {
|
||||
|
||||
void main(int argc, char **argv) {
|
||||
ExitGuard exit_guard;
|
||||
detail::ThreadIdGuard thread_id_guard;
|
||||
ignore_signal(SignalType::HangUp).ensure();
|
||||
ignore_signal(SignalType::Pipe).ensure();
|
||||
set_signal_handler(SignalType::Error, fail_signal).ensure();
|
||||
|
@ -143,10 +143,9 @@ bool Session::PriorityQueue::empty() const {
|
||||
Session::Session(unique_ptr<Callback> callback, std::shared_ptr<AuthDataShared> shared_auth_data, int32 raw_dc_id,
|
||||
int32 dc_id, bool is_main, bool use_pfs, bool is_cdn, bool need_destroy,
|
||||
const mtproto::AuthKey &tmp_auth_key, const vector<mtproto::ServerSalt> &server_salts)
|
||||
: raw_dc_id_(raw_dc_id), dc_id_(dc_id), is_main_(is_main), is_cdn_(is_cdn) {
|
||||
VLOG(dc) << "Start connection " << tag("need_destroy", need_destroy);
|
||||
need_destroy_ = need_destroy;
|
||||
if (need_destroy) {
|
||||
: raw_dc_id_(raw_dc_id), dc_id_(dc_id), is_main_(is_main), is_cdn_(is_cdn), need_destroy_(need_destroy) {
|
||||
VLOG(dc) << "Start connection " << tag("need_destroy", need_destroy_);
|
||||
if (need_destroy_) {
|
||||
use_pfs = false;
|
||||
CHECK(!is_cdn);
|
||||
}
|
||||
@ -173,8 +172,8 @@ Session::Session(unique_ptr<Callback> callback, std::shared_ptr<AuthDataShared>
|
||||
|
||||
callback_ = std::shared_ptr<Callback>(callback.release());
|
||||
|
||||
main_connection_.connection_id = 0;
|
||||
long_poll_connection_.connection_id = 1;
|
||||
main_connection_.connection_id_ = 0;
|
||||
long_poll_connection_.connection_id_ = 1;
|
||||
|
||||
if (is_cdn) {
|
||||
auth_data_.set_header(G()->mtproto_header().get_anonymous_header().str());
|
||||
@ -244,11 +243,11 @@ void Session::connection_online_update(bool force) {
|
||||
}
|
||||
connection_online_flag_ = new_connection_online_flag;
|
||||
VLOG(dc) << "Set connection_online " << connection_online_flag_;
|
||||
if (main_connection_.connection) {
|
||||
main_connection_.connection->set_online(connection_online_flag_, is_main_);
|
||||
if (main_connection_.connection_) {
|
||||
main_connection_.connection_->set_online(connection_online_flag_, is_main_);
|
||||
}
|
||||
if (long_poll_connection_.connection) {
|
||||
long_poll_connection_.connection->set_online(connection_online_flag_, is_main_);
|
||||
if (long_poll_connection_.connection_) {
|
||||
long_poll_connection_.connection_->set_online(connection_online_flag_, is_main_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,8 +422,8 @@ void Session::raw_event(const Event::Raw &event) {
|
||||
return_query(std::move(query));
|
||||
|
||||
LOG(DEBUG) << "Drop answer " << tag("message_id", format::as_hex(message_id));
|
||||
if (main_connection_.state == ConnectionInfo::State::Ready) {
|
||||
main_connection_.connection->cancel_answer(message_id);
|
||||
if (main_connection_.state_ == ConnectionInfo::State::Ready) {
|
||||
main_connection_.connection_->cancel_answer(message_id);
|
||||
} else {
|
||||
to_cancel_.push_back(message_id);
|
||||
}
|
||||
@ -443,11 +442,11 @@ Status Session::on_pong() {
|
||||
constexpr int MAX_QUERY_TIMEOUT = 60;
|
||||
constexpr int MIN_CONNECTION_ACTIVE = 60;
|
||||
if (current_info_ == &main_connection_ &&
|
||||
Timestamp::at(current_info_->created_at + MIN_CONNECTION_ACTIVE).is_in_past()) {
|
||||
Timestamp::at(current_info_->created_at_ + MIN_CONNECTION_ACTIVE).is_in_past()) {
|
||||
Status status;
|
||||
if (!unknown_queries_.empty()) {
|
||||
status = Status::Error(PSLICE() << "No state info for " << unknown_queries_.size() << " queries for "
|
||||
<< format::as_time(Time::now_cached() - current_info_->created_at));
|
||||
<< format::as_time(Time::now_cached() - current_info_->created_at_));
|
||||
}
|
||||
if (!sent_queries_list_.empty()) {
|
||||
for (auto it = sent_queries_list_.prev; it != &sent_queries_list_; it = it->prev) {
|
||||
@ -494,16 +493,16 @@ void Session::on_closed(Status status) {
|
||||
if (!close_flag_ && is_main_) {
|
||||
connection_token_.reset();
|
||||
}
|
||||
auto raw_connection = current_info_->connection->move_as_raw_connection();
|
||||
auto raw_connection = current_info_->connection_->move_as_raw_connection();
|
||||
Scheduler::unsubscribe_before_close(raw_connection->get_poll_info().get_pollable_fd_ref());
|
||||
raw_connection->close();
|
||||
|
||||
if (status.is_error()) {
|
||||
LOG(WARNING) << "Session with " << sent_queries_.size() << " pending requests was closed: " << status << " "
|
||||
<< current_info_->connection->get_name();
|
||||
<< current_info_->connection_->get_name();
|
||||
} else {
|
||||
LOG(INFO) << "Session with " << sent_queries_.size() << " pending requests was closed: " << status << " "
|
||||
<< current_info_->connection->get_name();
|
||||
<< current_info_->connection_->get_name();
|
||||
}
|
||||
|
||||
if (status.is_error() && status.code() == -404) {
|
||||
@ -536,7 +535,7 @@ void Session::on_closed(Status status) {
|
||||
|
||||
// resend all queries without ack
|
||||
for (auto it = sent_queries_.begin(); it != sent_queries_.end();) {
|
||||
if (!it->second.ack && it->second.connection_id == current_info_->connection_id) {
|
||||
if (!it->second.ack && it->second.connection_id == current_info_->connection_id_) {
|
||||
// container vector leak otherwise
|
||||
cleanup_container(it->first, &it->second);
|
||||
|
||||
@ -550,7 +549,7 @@ void Session::on_closed(Status status) {
|
||||
query->set_message_id(0);
|
||||
query->cancel_slot_.clear_event();
|
||||
query->set_error(Status::Error(500, PSLICE() << "Session failed: " << status.message()),
|
||||
current_info_->connection->get_name().str());
|
||||
current_info_->connection_->get_name().str());
|
||||
return_query(std::move(query));
|
||||
it = sent_queries_.erase(it);
|
||||
} else {
|
||||
@ -562,8 +561,8 @@ void Session::on_closed(Status status) {
|
||||
}
|
||||
}
|
||||
|
||||
current_info_->connection.reset();
|
||||
current_info_->state = ConnectionInfo::State::Empty;
|
||||
current_info_->connection_.reset();
|
||||
current_info_->state_ = ConnectionInfo::State::Empty;
|
||||
}
|
||||
|
||||
void Session::on_session_created(uint64 unique_id, uint64 first_id) {
|
||||
@ -790,21 +789,38 @@ void Session::on_message_result_error(uint64 id, int error_code, string message)
|
||||
|
||||
// UNAUTHORIZED
|
||||
if (error_code == 401 && message != "SESSION_PASSWORD_NEEDED") {
|
||||
if (auth_data_.use_pfs() && message == CSlice("AUTH_KEY_PERM_EMPTY")) {
|
||||
LOG(INFO) << "Receive AUTH_KEY_PERM_EMPTY in session " << auth_data_.get_session_id() << " for auth key "
|
||||
if (auth_data_.use_pfs() && (message == CSlice("AUTH_KEY_PERM_EMPTY") || !is_main_)) {
|
||||
LOG(INFO) << "Receive 401, " << message << " in session " << auth_data_.get_session_id() << " for auth key "
|
||||
<< auth_data_.get_tmp_auth_key().id();
|
||||
// temporary key can be dropped any time
|
||||
auth_data_.drop_tmp_auth_key();
|
||||
on_tmp_auth_key_updated();
|
||||
error_code = 500;
|
||||
} else {
|
||||
if (message == "USER_DEACTIVATED_BAN") {
|
||||
LOG(PLAIN) << "Your account was suspended for suspicious activity. If you think that this is a mistake, please "
|
||||
"write to recover@telegram.org your phone number and other details to recover the account.";
|
||||
bool can_drop_main_auth_key_without_logging_out = is_cdn_;
|
||||
if (!is_main_) {
|
||||
CHECK(!auth_data_.use_pfs());
|
||||
if (G()->net_query_dispatcher().get_main_dc_id().get_raw_id() != raw_dc_id_) {
|
||||
can_drop_main_auth_key_without_logging_out = true;
|
||||
}
|
||||
}
|
||||
if (can_drop_main_auth_key_without_logging_out) {
|
||||
LOG(INFO) << "Receive 401, " << message << " in session " << auth_data_.get_session_id() << " for auth key "
|
||||
<< auth_data_.get_auth_key().id();
|
||||
auth_data_.drop_main_auth_key();
|
||||
on_auth_key_updated();
|
||||
error_code = 500;
|
||||
} else {
|
||||
if (message == "USER_DEACTIVATED_BAN") {
|
||||
LOG(PLAIN)
|
||||
<< "Your account was suspended for suspicious activity. If you think that this is a mistake, please "
|
||||
"write to recover@telegram.org your phone number and other details to recover the account.";
|
||||
}
|
||||
auth_data_.set_auth_flag(false);
|
||||
G()->shared_config().set_option_string("auth", message);
|
||||
shared_auth_data_->set_auth_key(auth_data_.get_main_auth_key());
|
||||
on_session_failed(Status::OK());
|
||||
}
|
||||
auth_data_.set_auth_flag(false);
|
||||
G()->shared_config().set_option_string("auth", message);
|
||||
shared_auth_data_->set_auth_key(auth_data_.get_main_auth_key());
|
||||
on_session_failed(Status::OK());
|
||||
}
|
||||
}
|
||||
|
||||
@ -830,7 +846,7 @@ void Session::on_message_result_error(uint64 id, int error_code, string message)
|
||||
|
||||
cleanup_container(id, query_ptr);
|
||||
mark_as_known(id, query_ptr);
|
||||
query_ptr->query->set_error(Status::Error(error_code, message), current_info_->connection->get_name().str());
|
||||
query_ptr->query->set_error(Status::Error(error_code, message), current_info_->connection_->get_name().str());
|
||||
query_ptr->query->set_message_id(0);
|
||||
query_ptr->query->cancel_slot_.clear_event();
|
||||
return_query(std::move(query_ptr->query));
|
||||
@ -922,7 +938,7 @@ void Session::on_message_info(uint64 id, int32 state, uint64 answer_id, int32 an
|
||||
<< tag("answer_size", answer_size) << it->second.query;
|
||||
it->second.query->debug("Session: resend answer");
|
||||
}
|
||||
current_info_->connection->resend_answer(answer_id);
|
||||
current_info_->connection_->resend_answer(answer_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -954,7 +970,7 @@ void Session::add_query(NetQueryPtr &&net_query) {
|
||||
|
||||
void Session::connection_send_query(ConnectionInfo *info, NetQueryPtr &&net_query, uint64 message_id) {
|
||||
net_query->debug("Session: trying to send to mtproto::connection");
|
||||
CHECK(info->state == ConnectionInfo::State::Ready);
|
||||
CHECK(info->state_ == ConnectionInfo::State::Ready);
|
||||
current_info_ = info;
|
||||
|
||||
if (net_query->update_is_ready()) {
|
||||
@ -975,17 +991,23 @@ void Session::connection_send_query(ConnectionInfo *info, NetQueryPtr &&net_quer
|
||||
}
|
||||
}
|
||||
|
||||
// net_query->debug("Session: send to mtproto::connection");
|
||||
auto r_message_id =
|
||||
info->connection->send_query(net_query->query().clone(), net_query->gzip_flag() == NetQuery::GzipFlag::On,
|
||||
message_id, invoke_after_id, static_cast<bool>(net_query->quick_ack_promise_));
|
||||
bool immediately_fail_query = false;
|
||||
if (!immediately_fail_query) {
|
||||
auto r_message_id =
|
||||
info->connection_->send_query(net_query->query().clone(), net_query->gzip_flag() == NetQuery::GzipFlag::On,
|
||||
message_id, invoke_after_id, static_cast<bool>(net_query->quick_ack_promise_));
|
||||
|
||||
net_query->on_net_write(net_query->query().size());
|
||||
net_query->on_net_write(net_query->query().size());
|
||||
|
||||
if (r_message_id.is_error()) {
|
||||
LOG(FATAL) << "Failed to send query: " << r_message_id.error();
|
||||
if (r_message_id.is_error()) {
|
||||
LOG(FATAL) << "Failed to send query: " << r_message_id.error();
|
||||
}
|
||||
message_id = r_message_id.ok();
|
||||
} else {
|
||||
if (message_id == 0) {
|
||||
message_id = auth_data_.next_message_id(Time::now_cached());
|
||||
}
|
||||
}
|
||||
message_id = r_message_id.ok();
|
||||
VLOG(net_query) << "Send query to connection " << net_query << " [msg_id:" << format::as_hex(message_id) << "]"
|
||||
<< tag("invoke_after", format::as_hex(invoke_after_id));
|
||||
net_query->set_message_id(message_id);
|
||||
@ -1001,24 +1023,27 @@ void Session::connection_send_query(ConnectionInfo *info, NetQueryPtr &&net_quer
|
||||
net_query->cancel_slot_.set_event(EventCreator::raw(actor_id(), message_id));
|
||||
}
|
||||
auto status = sent_queries_.emplace(
|
||||
message_id, Query{message_id, std::move(net_query), main_connection_.connection_id, Time::now_cached()});
|
||||
message_id, Query{message_id, std::move(net_query), main_connection_.connection_id_, Time::now_cached()});
|
||||
sent_queries_list_.put(status.first->second.get_list_node());
|
||||
if (!status.second) {
|
||||
LOG(FATAL) << "Duplicate message_id [message_id = " << message_id << "]";
|
||||
}
|
||||
if (immediately_fail_query) {
|
||||
on_message_result_error(message_id, 401, "TEST_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
void Session::connection_open(ConnectionInfo *info, bool ask_info) {
|
||||
CHECK(info->state == ConnectionInfo::State::Empty);
|
||||
CHECK(info->state_ == ConnectionInfo::State::Empty);
|
||||
if (!network_flag_) {
|
||||
return;
|
||||
}
|
||||
if (!auth_data_.has_auth_key(Time::now_cached())) {
|
||||
return;
|
||||
}
|
||||
info->ask_info = ask_info;
|
||||
info->ask_info_ = ask_info;
|
||||
|
||||
info->state = ConnectionInfo::State::Connecting;
|
||||
info->state_ = ConnectionInfo::State::Connecting;
|
||||
info->cancellation_token_source_ = CancellationTokenSource{};
|
||||
// NB: rely on constant location of info
|
||||
auto promise = PromiseCreator::cancellable_lambda(
|
||||
@ -1039,7 +1064,7 @@ void Session::connection_open(ConnectionInfo *info, bool ask_info) {
|
||||
callback_->request_raw_connection(std::move(auth_data), std::move(promise));
|
||||
}
|
||||
|
||||
info->wakeup_at = Time::now_cached() + 1000;
|
||||
info->wakeup_at_ = Time::now_cached() + 1000;
|
||||
}
|
||||
|
||||
void Session::connection_add(unique_ptr<mtproto::RawConnection> raw_connection) {
|
||||
@ -1049,10 +1074,10 @@ void Session::connection_add(unique_ptr<mtproto::RawConnection> raw_connection)
|
||||
}
|
||||
|
||||
void Session::connection_check_mode(ConnectionInfo *info) {
|
||||
if (close_flag_ || info->state != ConnectionInfo::State::Ready) {
|
||||
if (close_flag_ || info->state_ != ConnectionInfo::State::Ready) {
|
||||
return;
|
||||
}
|
||||
if (info->mode != mode_) {
|
||||
if (info->mode_ != mode_) {
|
||||
LOG(WARNING) << "Close connection because of outdated mode_";
|
||||
connection_close(info);
|
||||
}
|
||||
@ -1060,14 +1085,14 @@ void Session::connection_check_mode(ConnectionInfo *info) {
|
||||
|
||||
void Session::connection_open_finish(ConnectionInfo *info,
|
||||
Result<unique_ptr<mtproto::RawConnection>> r_raw_connection) {
|
||||
if (close_flag_ || info->state != ConnectionInfo::State::Connecting) {
|
||||
if (close_flag_ || info->state_ != ConnectionInfo::State::Connecting) {
|
||||
VLOG(dc) << "Ignore raw connection while closing";
|
||||
return;
|
||||
}
|
||||
current_info_ = info;
|
||||
if (r_raw_connection.is_error()) {
|
||||
LOG(WARNING) << "Failed to open socket: " << r_raw_connection.error();
|
||||
info->state = ConnectionInfo::State::Empty;
|
||||
info->state_ = ConnectionInfo::State::Empty;
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
@ -1076,7 +1101,7 @@ void Session::connection_open_finish(ConnectionInfo *info,
|
||||
VLOG(dc) << "Receive raw connection " << raw_connection.get();
|
||||
if (raw_connection->extra().extra != network_generation_) {
|
||||
LOG(WARNING) << "Got RawConnection with old network_generation";
|
||||
info->state = ConnectionInfo::State::Empty;
|
||||
info->state_ = ConnectionInfo::State::Empty;
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
@ -1086,10 +1111,10 @@ void Session::connection_open_finish(ConnectionInfo *info,
|
||||
if (mode_ != expected_mode) {
|
||||
VLOG(dc) << "Change mode " << mode_ << "--->" << expected_mode;
|
||||
mode_ = expected_mode;
|
||||
if (info->connection_id == 1 && mode_ != Mode::Http) {
|
||||
if (info->connection_id_ == 1 && mode_ != Mode::Http) {
|
||||
LOG(WARNING) << "Got tcp connection for long poll connection";
|
||||
connection_add(std::move(raw_connection));
|
||||
info->state = ConnectionInfo::State::Empty;
|
||||
info->state_ = ConnectionInfo::State::Empty;
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
@ -1101,7 +1126,7 @@ void Session::connection_open_finish(ConnectionInfo *info,
|
||||
mode = mtproto::SessionConnection::Mode::Tcp;
|
||||
mode_name = Slice("Tcp");
|
||||
} else {
|
||||
if (info->connection_id == 0) {
|
||||
if (info->connection_id_ == 0) {
|
||||
mode = mtproto::SessionConnection::Mode::Http;
|
||||
mode_name = Slice("Http");
|
||||
} else {
|
||||
@ -1111,28 +1136,28 @@ void Session::connection_open_finish(ConnectionInfo *info,
|
||||
}
|
||||
auto name = PSTRING() << get_name() << "::Connect::" << mode_name << "::" << raw_connection->extra().debug_str;
|
||||
LOG(INFO) << "Finished to open connection " << name;
|
||||
info->connection = make_unique<mtproto::SessionConnection>(mode, std::move(raw_connection), &auth_data_);
|
||||
info->connection_ = make_unique<mtproto::SessionConnection>(mode, std::move(raw_connection), &auth_data_);
|
||||
if (can_destroy_auth_key()) {
|
||||
info->connection->destroy_key();
|
||||
info->connection_->destroy_key();
|
||||
}
|
||||
info->connection->set_online(connection_online_flag_, is_main_);
|
||||
info->connection->set_name(name);
|
||||
Scheduler::subscribe(info->connection->get_poll_info().extract_pollable_fd(this));
|
||||
info->mode = mode_;
|
||||
info->state = ConnectionInfo::State::Ready;
|
||||
info->created_at = Time::now_cached();
|
||||
info->wakeup_at = Time::now_cached() + 10;
|
||||
info->connection_->set_online(connection_online_flag_, is_main_);
|
||||
info->connection_->set_name(name);
|
||||
Scheduler::subscribe(info->connection_->get_poll_info().extract_pollable_fd(this));
|
||||
info->mode_ = mode_;
|
||||
info->state_ = ConnectionInfo::State::Ready;
|
||||
info->created_at_ = Time::now_cached();
|
||||
info->wakeup_at_ = Time::now_cached() + 10;
|
||||
if (unknown_queries_.size() > MAX_INFLIGHT_QUERIES) {
|
||||
LOG(ERROR) << "With current limits `Too much queries with unknown state` error must be impossible";
|
||||
on_session_failed(Status::Error("Too much queries with unknown state"));
|
||||
return;
|
||||
}
|
||||
if (info->ask_info) {
|
||||
if (info->ask_info_) {
|
||||
for (auto &id : unknown_queries_) {
|
||||
info->connection->get_state_info(id);
|
||||
info->connection_->get_state_info(id);
|
||||
}
|
||||
for (auto &id : to_cancel_) {
|
||||
info->connection->cancel_answer(id);
|
||||
info->connection_->cancel_answer(id);
|
||||
}
|
||||
to_cancel_.clear();
|
||||
}
|
||||
@ -1140,18 +1165,18 @@ void Session::connection_open_finish(ConnectionInfo *info,
|
||||
}
|
||||
|
||||
void Session::connection_flush(ConnectionInfo *info) {
|
||||
CHECK(info->state == ConnectionInfo::State::Ready);
|
||||
CHECK(info->state_ == ConnectionInfo::State::Ready);
|
||||
current_info_ = info;
|
||||
info->wakeup_at = info->connection->flush(static_cast<mtproto::SessionConnection::Callback *>(this));
|
||||
info->wakeup_at_ = info->connection_->flush(static_cast<mtproto::SessionConnection::Callback *>(this));
|
||||
}
|
||||
|
||||
void Session::connection_close(ConnectionInfo *info) {
|
||||
current_info_ = info;
|
||||
if (info->state != ConnectionInfo::State::Ready) {
|
||||
if (info->state_ != ConnectionInfo::State::Ready) {
|
||||
return;
|
||||
}
|
||||
info->connection->force_close(static_cast<mtproto::SessionConnection::Callback *>(this));
|
||||
CHECK(info->state == ConnectionInfo::State::Empty);
|
||||
info->connection_->force_close(static_cast<mtproto::SessionConnection::Callback *>(this));
|
||||
CHECK(info->state_ == ConnectionInfo::State::Empty);
|
||||
}
|
||||
|
||||
bool Session::need_send_check_main_key() const {
|
||||
@ -1166,7 +1191,7 @@ bool Session::connection_send_check_main_key(ConnectionInfo *info) {
|
||||
if (key_id == being_checked_main_auth_key_id_) {
|
||||
return false;
|
||||
}
|
||||
CHECK(info->state != ConnectionInfo::State::Empty);
|
||||
CHECK(info->state_ != ConnectionInfo::State::Empty);
|
||||
LOG(INFO) << "Check main key";
|
||||
being_checked_main_auth_key_id_ = key_id;
|
||||
last_check_query_id_ = UniqueId::next(UniqueId::BindKey);
|
||||
@ -1190,7 +1215,7 @@ bool Session::need_send_query() const {
|
||||
}
|
||||
|
||||
bool Session::connection_send_bind_key(ConnectionInfo *info) {
|
||||
CHECK(info->state != ConnectionInfo::State::Empty);
|
||||
CHECK(info->state_ != ConnectionInfo::State::Empty);
|
||||
uint64 key_id = auth_data_.get_tmp_auth_key().id();
|
||||
if (key_id == being_binded_tmp_auth_key_id_) {
|
||||
return false;
|
||||
@ -1203,7 +1228,7 @@ bool Session::connection_send_bind_key(ConnectionInfo *info) {
|
||||
auto expires_at = static_cast<int32>(auth_data_.get_server_time(auth_data_.get_tmp_auth_key().expires_at()));
|
||||
int64 message_id;
|
||||
BufferSlice encrypted;
|
||||
std::tie(message_id, encrypted) = info->connection->encrypted_bind(perm_auth_key_id, nonce, expires_at);
|
||||
std::tie(message_id, encrypted) = info->connection_->encrypted_bind(perm_auth_key_id, nonce, expires_at);
|
||||
|
||||
LOG(INFO) << "Bind key: " << tag("tmp", key_id) << tag("perm", static_cast<uint64>(perm_auth_key_id));
|
||||
NetQueryPtr query = G()->net_query_creator().create(
|
||||
@ -1342,8 +1367,8 @@ void Session::loop() {
|
||||
connection_online_update();
|
||||
|
||||
double wakeup_at = 0;
|
||||
main_connection_.wakeup_at = 0;
|
||||
long_poll_connection_.wakeup_at = 0;
|
||||
main_connection_.wakeup_at_ = 0;
|
||||
long_poll_connection_.wakeup_at_ = 0;
|
||||
|
||||
// NB: order is crucial. First long_poll_connection, then main_connection
|
||||
// Otherwise queries could be sent with big delay
|
||||
@ -1351,20 +1376,20 @@ void Session::loop() {
|
||||
connection_check_mode(&main_connection_);
|
||||
connection_check_mode(&long_poll_connection_);
|
||||
if (mode_ == Mode::Http) {
|
||||
if (long_poll_connection_.state == ConnectionInfo::State::Ready) {
|
||||
if (long_poll_connection_.state_ == ConnectionInfo::State::Ready) {
|
||||
connection_flush(&long_poll_connection_);
|
||||
}
|
||||
if (!close_flag_ && long_poll_connection_.state == ConnectionInfo::State::Empty) {
|
||||
if (!close_flag_ && long_poll_connection_.state_ == ConnectionInfo::State::Empty) {
|
||||
connection_open(&long_poll_connection_);
|
||||
}
|
||||
relax_timeout_at(&wakeup_at, long_poll_connection_.wakeup_at);
|
||||
relax_timeout_at(&wakeup_at, long_poll_connection_.wakeup_at_);
|
||||
}
|
||||
|
||||
if (main_connection_.state == ConnectionInfo::State::Ready) {
|
||||
if (main_connection_.state_ == ConnectionInfo::State::Ready) {
|
||||
// do not send queries before we have key and e.t.c
|
||||
// do not send queries before tmp_key is bound
|
||||
bool need_flush = true;
|
||||
while (main_connection_.state == ConnectionInfo::State::Ready) {
|
||||
while (main_connection_.state_ == ConnectionInfo::State::Ready) {
|
||||
if (auth_data_.is_ready(Time::now_cached())) {
|
||||
if (need_send_query()) {
|
||||
while (!pending_queries_.empty() && sent_queries_.size() < MAX_INFLIGHT_QUERIES) {
|
||||
@ -1391,11 +1416,11 @@ void Session::loop() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!close_flag_ && main_connection_.state == ConnectionInfo::State::Empty) {
|
||||
if (!close_flag_ && main_connection_.state_ == ConnectionInfo::State::Empty) {
|
||||
connection_open(&main_connection_, true /*send ask_info*/);
|
||||
}
|
||||
|
||||
relax_timeout_at(&wakeup_at, main_connection_.wakeup_at);
|
||||
relax_timeout_at(&wakeup_at, main_connection_.wakeup_at_);
|
||||
|
||||
double wakeup_in = 0;
|
||||
if (wakeup_at != 0) {
|
||||
|
@ -102,17 +102,17 @@ class Session final
|
||||
// Just re-ask answer_id each time we get information about it.
|
||||
// Though mtproto::Connection must ensure delivery of such query.
|
||||
|
||||
int32 raw_dc_id_;
|
||||
int32 dc_id_;
|
||||
int32 raw_dc_id_; // numerical datacenter ID, i.e. 2
|
||||
int32 dc_id_; // unique datacenter ID, i.e. -10002
|
||||
enum class Mode : int8 { Tcp, Http } mode_ = Mode::Tcp;
|
||||
bool is_main_;
|
||||
bool is_main_; // true only for the primary Session(s) to the main DC
|
||||
bool is_cdn_;
|
||||
bool need_destroy_;
|
||||
bool was_on_network_ = false;
|
||||
bool network_flag_ = false;
|
||||
uint32 network_generation_ = 0;
|
||||
bool online_flag_ = false;
|
||||
bool connection_online_flag_ = false;
|
||||
uint32 network_generation_ = 0;
|
||||
uint64 being_binded_tmp_auth_key_id_ = 0;
|
||||
uint64 being_checked_main_auth_key_id_ = 0;
|
||||
uint64 last_bind_query_id_ = 0;
|
||||
@ -140,14 +140,14 @@ class Session final
|
||||
ListNode sent_queries_list_;
|
||||
|
||||
struct ConnectionInfo {
|
||||
int8 connection_id = 0;
|
||||
Mode mode = Mode::Tcp;
|
||||
enum class State : int8 { Empty, Connecting, Ready } state = State::Empty;
|
||||
int8 connection_id_ = 0;
|
||||
Mode mode_ = Mode::Tcp;
|
||||
enum class State : int8 { Empty, Connecting, Ready } state_ = State::Empty;
|
||||
CancellationTokenSource cancellation_token_source_;
|
||||
unique_ptr<mtproto::SessionConnection> connection;
|
||||
bool ask_info;
|
||||
double wakeup_at = 0;
|
||||
double created_at = 0;
|
||||
unique_ptr<mtproto::SessionConnection> connection_;
|
||||
bool ask_info_ = false;
|
||||
double wakeup_at_ = 0;
|
||||
double created_at_ = 0;
|
||||
};
|
||||
|
||||
ConnectionInfo *current_info_;
|
||||
|
@ -91,7 +91,6 @@ class TimeoutManager final : public td::Actor {
|
||||
td::int32 TimeoutManager::count;
|
||||
|
||||
TEST(MultiTimeout, Destroy) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
td::ConcurrentScheduler sched;
|
||||
int threads_n = 0;
|
||||
sched.init(threads_n);
|
||||
|
@ -244,7 +244,7 @@ optional<int32> SqliteDb::get_cipher_version() const {
|
||||
|
||||
Result<SqliteDb> SqliteDb::change_key(CSlice path, bool allow_creation, const DbKey &new_db_key,
|
||||
const DbKey &old_db_key) {
|
||||
PerfWarningTimer perf("change key", 0.001);
|
||||
PerfWarningTimer perf("change key", 0.05);
|
||||
|
||||
// fast path
|
||||
{
|
||||
|
@ -8,12 +8,73 @@
|
||||
|
||||
#include "td/utils/port/thread_local.h"
|
||||
|
||||
namespace td {
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
|
||||
StackAllocator::Impl &StackAllocator::impl() {
|
||||
static TD_THREAD_LOCAL StackAllocator::Impl *impl; // static zero-initialized
|
||||
init_thread_local<Impl>(impl);
|
||||
return *impl;
|
||||
namespace td {
|
||||
namespace {
|
||||
class ArrayAllocator final : public StackAllocator::AllocatorImpl {
|
||||
static const size_t MEM_SIZE = 1024 * 1024;
|
||||
std::array<char, MEM_SIZE> mem;
|
||||
size_t pos{0};
|
||||
|
||||
MutableSlice allocate(size_t size) final {
|
||||
if (size > MEM_SIZE) {
|
||||
std::abort(); // too much memory requested
|
||||
}
|
||||
char *res = mem.data() + pos;
|
||||
pos += (size + 7) & -8;
|
||||
if (pos > MEM_SIZE) {
|
||||
std::abort(); // memory is over
|
||||
}
|
||||
return {res, size};
|
||||
}
|
||||
|
||||
void free_ptr(char *ptr, size_t size) final {
|
||||
size = (size + 7) & -8;
|
||||
if (size > pos || ptr != mem.data() + (pos - size)) {
|
||||
std::abort(); // shouldn't happen
|
||||
}
|
||||
pos -= size;
|
||||
}
|
||||
|
||||
public:
|
||||
~ArrayAllocator() final {
|
||||
if (pos != 0) {
|
||||
std::abort(); // shouldn't happen
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class NewAllocator final : public StackAllocator::AllocatorImpl {
|
||||
MutableSlice allocate(size_t size) final {
|
||||
return {new char[size], size};
|
||||
}
|
||||
|
||||
void free_ptr(char *ptr, size_t size) final {
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
~NewAllocator() final = default;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
StackAllocator::Ptr::~Ptr() {
|
||||
if (!slice_.empty()) {
|
||||
allocator_->free_ptr(slice_.data(), slice_.size());
|
||||
}
|
||||
}
|
||||
|
||||
StackAllocator::AllocatorImpl *StackAllocator::impl() {
|
||||
if (get_thread_id() != 0) {
|
||||
static TD_THREAD_LOCAL ArrayAllocator *array_allocator; // static zero-initialized
|
||||
init_thread_local<ArrayAllocator>(array_allocator);
|
||||
return array_allocator;
|
||||
} else {
|
||||
static NewAllocator new_allocator;
|
||||
return &new_allocator;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -7,76 +7,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/MovableValue.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
namespace td {
|
||||
|
||||
class StackAllocator {
|
||||
class Deleter {
|
||||
public:
|
||||
class AllocatorImpl {
|
||||
public:
|
||||
void operator()(char *ptr) {
|
||||
free_ptr(ptr);
|
||||
}
|
||||
AllocatorImpl() = default;
|
||||
AllocatorImpl(const AllocatorImpl &) = delete;
|
||||
AllocatorImpl &operator=(const AllocatorImpl &) = delete;
|
||||
AllocatorImpl(AllocatorImpl &&) = delete;
|
||||
AllocatorImpl &operator=(AllocatorImpl &&) = delete;
|
||||
virtual ~AllocatorImpl() = default;
|
||||
|
||||
virtual MutableSlice allocate(size_t size) = 0;
|
||||
|
||||
virtual void free_ptr(char *ptr, size_t size) = 0;
|
||||
};
|
||||
|
||||
// TODO: alloc memory with mmap and unload unused pages
|
||||
// memory still can be corrupted, but it is better than explicit free function
|
||||
// TODO: use pointer that can't be even copied
|
||||
using PtrImpl = std::unique_ptr<char, Deleter>;
|
||||
private:
|
||||
class Ptr {
|
||||
public:
|
||||
Ptr(char *ptr, size_t size) : ptr_(ptr), size_(size) {
|
||||
Ptr(AllocatorImpl *allocator, size_t size) : allocator_(allocator), slice_(allocator_->allocate(size)) {
|
||||
}
|
||||
Ptr(const Ptr &other) = delete;
|
||||
Ptr &operator=(const Ptr &other) = delete;
|
||||
Ptr(Ptr &&other) noexcept : allocator_(other.allocator_), slice_(other.slice_) {
|
||||
other.allocator_ = nullptr;
|
||||
other.slice_ = MutableSlice();
|
||||
}
|
||||
Ptr &operator=(Ptr &&other) = delete;
|
||||
~Ptr();
|
||||
|
||||
MutableSlice as_slice() const {
|
||||
return MutableSlice(ptr_.get(), size_.get());
|
||||
return slice_;
|
||||
}
|
||||
|
||||
private:
|
||||
PtrImpl ptr_;
|
||||
MovableValue<size_t> size_;
|
||||
AllocatorImpl *allocator_;
|
||||
MutableSlice slice_;
|
||||
};
|
||||
|
||||
static void free_ptr(char *ptr) {
|
||||
impl().free_ptr(ptr);
|
||||
}
|
||||
|
||||
struct Impl {
|
||||
static const size_t MEM_SIZE = 1024 * 1024;
|
||||
std::array<char, MEM_SIZE> mem;
|
||||
|
||||
size_t pos{0};
|
||||
char *alloc(size_t size) {
|
||||
if (size == 0) {
|
||||
size = 1;
|
||||
}
|
||||
char *res = mem.data() + pos;
|
||||
size = (size + 7) & -8;
|
||||
pos += size;
|
||||
if (pos > MEM_SIZE) {
|
||||
std::abort(); // memory is over
|
||||
}
|
||||
return res;
|
||||
}
|
||||
void free_ptr(char *ptr) {
|
||||
size_t new_pos = ptr - mem.data();
|
||||
if (new_pos >= pos) {
|
||||
std::abort(); // shouldn't happen
|
||||
}
|
||||
pos = new_pos;
|
||||
}
|
||||
};
|
||||
|
||||
static Impl &impl();
|
||||
static AllocatorImpl *impl();
|
||||
|
||||
public:
|
||||
static Ptr alloc(size_t size) {
|
||||
return Ptr(impl().alloc(size), size);
|
||||
return Ptr(impl(), size);
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,7 @@
|
||||
#include "td/utils/StringBuilder.h"
|
||||
#include "td/utils/tests.h"
|
||||
#include "td/utils/Time.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
#include "td/utils/translit.h"
|
||||
#include "td/utils/uint128.h"
|
||||
#include "td/utils/unicode.h"
|
||||
@ -68,11 +69,9 @@ struct CheckExitGuard {
|
||||
|
||||
static CheckExitGuard check_exit_guard_true{true};
|
||||
static td::ExitGuard exit_guard;
|
||||
static CheckExitGuard check_exit_guard_false{false};
|
||||
|
||||
#if TD_LINUX || TD_DARWIN
|
||||
TEST(Misc, update_atime_saves_mtime) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
td::string name = "test_file";
|
||||
td::unlink(name).ignore();
|
||||
auto r_file = td::FileFd::open(name, td::FileFd::Read | td::FileFd::Flags::Create | td::FileFd::Flags::Truncate);
|
||||
@ -102,7 +101,6 @@ TEST(Misc, update_atime_saves_mtime) {
|
||||
}
|
||||
|
||||
TEST(Misc, update_atime_change_atime) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
td::string name = "test_file";
|
||||
td::unlink(name).ignore();
|
||||
auto r_file = td::FileFd::open(name, td::FileFd::Read | td::FileFd::Flags::Create | td::FileFd::Flags::Truncate);
|
||||
@ -1232,4 +1230,17 @@ TEST(Misc, is_emoji) {
|
||||
ASSERT_TRUE(!td::is_emoji(" "));
|
||||
ASSERT_TRUE(!td::is_emoji(""));
|
||||
ASSERT_TRUE(!td::is_emoji("1234567890123456789012345678901234567890123456789012345678901234567890"));
|
||||
ASSERT_TRUE(td::is_emoji("❤️"));
|
||||
ASSERT_TRUE(td::is_emoji("❤"));
|
||||
}
|
||||
|
||||
TEST(Misc, serialize) {
|
||||
td::int32 x = 1;
|
||||
ASSERT_EQ(td::base64_encode(td::serialize(x)), td::base64_encode(td::string("\x01\x00\x00\x00", 4)));
|
||||
td::int64 y = -2;
|
||||
ASSERT_EQ(td::base64_encode(td::serialize(y)), td::base64_encode(td::string("\xfe\xff\xff\xff\xff\xff\xff\xff", 8)));
|
||||
}
|
||||
|
||||
TEST(Misc, check_reset_guard) {
|
||||
CheckExitGuard check_exit_guard{false};
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/detail/ThreadIdGuard.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/Slice.h"
|
||||
@ -274,6 +275,7 @@ static HandshakeTest pregenerated_test() {
|
||||
}
|
||||
|
||||
int main() {
|
||||
td::detail::ThreadIdGuard thread_id_guard;
|
||||
auto test = gen_test();
|
||||
run_test(test);
|
||||
run_test(pregenerated_test());
|
||||
|
@ -340,7 +340,6 @@ class BaselineKV {
|
||||
};
|
||||
|
||||
TEST(DB, key_value) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
|
||||
@ -517,7 +516,6 @@ TEST(DB, persistent_key_value) {
|
||||
using KeyValue = BinlogKeyValue<ConcurrentBinlog>;
|
||||
// using KeyValue = PersistentKeyValue;
|
||||
// using KeyValue = SqliteKV;
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
CSlice path = "test_pmc";
|
||||
|
@ -140,7 +140,6 @@ TEST(Http, reader) {
|
||||
return;
|
||||
#endif
|
||||
clear_thread_locals();
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
auto start_mem = BufferAllocator::get_buffer_mem();
|
||||
auto start_size = BufferAllocator::get_buffer_slice_size();
|
||||
{
|
||||
|
@ -6,8 +6,11 @@
|
||||
//
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/ExitGuard.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/OptionParser.h"
|
||||
#include "td/utils/port/detail/ThreadIdGuard.h"
|
||||
#include "td/utils/port/stacktrace.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/tests.h"
|
||||
#include "td/telegram/Log.h"
|
||||
@ -17,21 +20,34 @@
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL));
|
||||
td::ExitGuard exit_guard;
|
||||
td::detail::ThreadIdGuard thread_id_guard;
|
||||
td::Stacktrace::init();
|
||||
td::init_openssl_threads();
|
||||
|
||||
td::TestsRunner &runner = td::TestsRunner::get_default();
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
|
||||
int default_verbosity_level = 1;
|
||||
td::OptionParser options;
|
||||
options.add_option('f', "filter", "Run only specified tests",
|
||||
options.add_option('f', "filter", "run only specified tests",
|
||||
[&](td::Slice filter) { runner.add_substr_filter(filter.str()); });
|
||||
options.add_option('s', "stress", "Run tests infinitely", [&] { runner.set_stress_flag(true); });
|
||||
options.add_option('s', "stress", "run tests infinitely", [&] { runner.set_stress_flag(true); });
|
||||
options.add_checked_option('v', "verbosity", "log verbosity level",
|
||||
td::OptionParser::parse_integer(default_verbosity_level));
|
||||
options.add_check([&] {
|
||||
if (default_verbosity_level < 0) {
|
||||
return td::Status::Error("Wrong verbosity level specified");
|
||||
}
|
||||
return td::Status::OK();
|
||||
});
|
||||
auto r_non_options = options.run(argc, argv, 0);
|
||||
if (r_non_options.is_error()) {
|
||||
LOG(PLAIN) << argv[0] << ": " << r_non_options.error().message();
|
||||
LOG(PLAIN) << options;
|
||||
return 1;
|
||||
}
|
||||
SET_VERBOSITY_LEVEL(default_verbosity_level);
|
||||
|
||||
#if TD_EMSCRIPTEN
|
||||
emscripten_set_main_loop(
|
||||
|
@ -49,7 +49,6 @@
|
||||
using namespace td;
|
||||
|
||||
TEST(Mtproto, GetHostByNameActor) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
ConcurrentScheduler sched;
|
||||
int threads_n = 1;
|
||||
sched.init(threads_n);
|
||||
@ -667,7 +666,6 @@ TEST(Mtproto, Grease) {
|
||||
}
|
||||
|
||||
TEST(Mtproto, TlsTransport) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
ConcurrentScheduler sched;
|
||||
int threads_n = 1;
|
||||
sched.init(threads_n);
|
||||
|
@ -1001,7 +1001,6 @@ void FakeSecretChatContext::on_read_message(int64, Promise<> promise) {
|
||||
|
||||
TEST(Secret, go) {
|
||||
return;
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
ConcurrentScheduler sched;
|
||||
int threads_n = 0;
|
||||
sched.init(threads_n);
|
||||
|
@ -828,7 +828,6 @@ class Tdclient_login final : public td::Test {
|
||||
using Test::Test;
|
||||
bool step() final {
|
||||
if (!is_inited_) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG) + 2);
|
||||
sched_.init(4);
|
||||
sched_.create_actor_unsafe<LoginTestActor>(0, "LoginTestActor", &result_).release();
|
||||
sched_.start();
|
||||
@ -936,7 +935,7 @@ TEST(Client, Multi) {
|
||||
TEST(Client, Manager) {
|
||||
td::vector<td::thread> threads;
|
||||
td::ClientManager client;
|
||||
#if !TD_EVENTFD_UNSUPPORTED // Client must be used from a single thread if there is no EventFd
|
||||
#if !TD_EVENTFD_UNSUPPORTED // Client must be used from a single thread if there is no EventFd
|
||||
int threads_n = 4;
|
||||
#else
|
||||
int threads_n = 1;
|
||||
@ -973,7 +972,7 @@ TEST(Client, Manager) {
|
||||
}
|
||||
}
|
||||
|
||||
#if !TD_EVENTFD_UNSUPPORTED // Client must be used from a single thread if there is no EventFd
|
||||
#if !TD_EVENTFD_UNSUPPORTED // Client must be used from a single thread if there is no EventFd
|
||||
TEST(Client, Close) {
|
||||
std::atomic<bool> stop_send{false};
|
||||
std::atomic<bool> can_stop_receive{false};
|
||||
|
Loading…
Reference in New Issue
Block a user