New Proxy API.

GitOrigin-RevId: 2f96b8d1732c25e10a7568c6cf2dbbe26a150e4a
This commit is contained in:
levlam 2018-05-14 22:00:38 +03:00
parent b636b03e5d
commit 7de9a0c15d
11 changed files with 375 additions and 133 deletions

View File

@ -117,7 +117,7 @@ temporaryPasswordState has_password:Bool valid_for:int32 = TemporaryPasswordStat
localFile path:string can_be_downloaded:Bool can_be_deleted:Bool is_downloading_active:Bool is_downloading_completed:Bool downloaded_prefix_size:int32 downloaded_size:int32 = LocalFile;
//@description Represents a remote file
//@id Remote file identifier, may be empty. Can be used across application restarts or even from other devices for the current user. If the ID starts with "http://" or "https://", it represents the HTTP URL of the file. TDLib is currently unable to download files if only their URL is known.
//@id Remote file identifier; may be empty. Can be used across application restarts or even from other devices for the current user. If the ID starts with "http://" or "https://", it represents the HTTP URL of the file. TDLib is currently unable to download files if only their URL is known.
//-If downloadFile is called on such a file or if it is sent to a secret chat, TDLib starts a file generation process by sending updateFileGenerationStart to the client with the HTTP URL in the original_path and "#url#" as the conversion string. Clients should generate the file by downloading it to the specified location
//@is_uploading_active True, if the file is currently being uploaded (or a remote copy is being generated by some other means)
//@is_uploading_completed True, if a remote copy is fully available
@ -144,7 +144,7 @@ inputFileRemote id:string = InputFile;
//@description A file defined by a local path @path Local path to the file
inputFileLocal path:string = InputFile;
//@description A file generated by the client @original_path Local path to a file from which the file is generated, may be empty if there is no such file @conversion String specifying the conversion applied to the original file; should be persistent across application restarts @expected_size Expected size of the generated file; 0 if unknown
//@description A file generated by the client @original_path Local path to a file from which the file is generated; may be empty if there is no such file @conversion String specifying the conversion applied to the original file; should be persistent across application restarts @expected_size Expected size of the generated file; 0 if unknown
inputFileGenerated original_path:string conversion:string expected_size:int32 = InputFile;
@ -1119,7 +1119,7 @@ messageGameScore game_message_id:int53 game_id:int64 score:int32 = MessageConten
messagePaymentSuccessful invoice_message_id:int53 currency:string total_amount:int53 = MessageContent;
//@description A payment has been completed; for bots only @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for price of the product
//@total_amount Total price for the product, in the minimal quantity of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user, may be empty if not applicable @order_info Information about the order; may be null
//@total_amount Total price for the product, in the minimal quantity of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null
//@telegram_payment_charge_id Telegram payment identifier @provider_payment_charge_id Provider payment identifier
messagePaymentSuccessfulBot invoice_message_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent;
@ -1648,38 +1648,38 @@ chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool
//@class DeviceToken @description Represents a data needed to subscribe for push notifications. To use specific push notification service, you must specify the correct application platform and upload valid server authentication data at https://my.telegram.org
//@description A token for Google Cloud Messaging @token Device registration token, may be empty to de-register a device
//@description A token for Google Cloud Messaging @token Device registration token; may be empty to de-register a device
deviceTokenGoogleCloudMessaging token:string = DeviceToken;
//@description A token for Apple Push Notification service @device_token Device token, may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled
//@description A token for Apple Push Notification service @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled
deviceTokenApplePush device_token:string is_app_sandbox:Bool = DeviceToken;
//@description A token for Apple Push Notification service VoIP notifications @device_token Device token, may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled
//@description A token for Apple Push Notification service VoIP notifications @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled
deviceTokenApplePushVoIP device_token:string is_app_sandbox:Bool = DeviceToken;
//@description A token for Windows Push Notification Services @access_token The access token that will be used to send notifications, may be empty to de-register a device
//@description A token for Windows Push Notification Services @access_token The access token that will be used to send notifications; may be empty to de-register a device
deviceTokenWindowsPush access_token:string = DeviceToken;
//@description A token for Microsoft Push Notification Service @channel_uri Push notification channel URI, may be empty to de-register a device
//@description A token for Microsoft Push Notification Service @channel_uri Push notification channel URI; may be empty to de-register a device
deviceTokenMicrosoftPush channel_uri:string = DeviceToken;
//@description A token for Microsoft Push Notification Service VoIP channel @channel_uri Push notification channel URI, may be empty to de-register a device
//@description A token for Microsoft Push Notification Service VoIP channel @channel_uri Push notification channel URI; may be empty to de-register a device
deviceTokenMicrosoftPushVoIP channel_uri:string = DeviceToken;
//@description A token for web Push API @endpoint Absolute URL exposed by the push service where the application server can send push messages, may be empty to de-register a device
//@description A token for web Push API @endpoint Absolute URL exposed by the push service where the application server can send push messages; may be empty to de-register a device
//@p256dh_base64url Base64url-encoded P-256 elliptic curve Diffie-Hellman public key @auth_base64url Base64url-encoded authentication secret
deviceTokenWebPush endpoint:string p256dh_base64url:string auth_base64url:string = DeviceToken;
//@description A token for Simple Push API for Firefox OS @endpoint Absolute URL exposed by the push service where the application server can send push messages, may be empty to de-register a device
//@description A token for Simple Push API for Firefox OS @endpoint Absolute URL exposed by the push service where the application server can send push messages; may be empty to de-register a device
deviceTokenSimplePush endpoint:string = DeviceToken;
//@description A token for Ubuntu Push Client service @token Token, may be empty to de-register a device
//@description A token for Ubuntu Push Client service @token Token; may be empty to de-register a device
deviceTokenUbuntuPush token:string = DeviceToken;
//@description A token for BlackBerry Push Service @token Token, may be empty to de-register a device
//@description A token for BlackBerry Push Service @token Token; may be empty to de-register a device
deviceTokenBlackBerryPush token:string = DeviceToken;
//@description A token for Tizen Push Service @reg_id Push service registration identifier, may be empty to de-register a device
//@description A token for Tizen Push Service @reg_id Push service registration identifier; may be empty to de-register a device
deviceTokenTizenPush reg_id:string = DeviceToken;
@ -1979,6 +1979,9 @@ count count:int32 = Count;
//@description Contains some text @text Text
text text:string = Text;
//@description Contains a value representing number of seconds @seconds Number of seconds
seconds seconds:double = Seconds;
//@description Contains information about a tg:// deep link @text Text to be shown to the user @need_update_application True, if user should be asked to update the application
deepLinkInfo text:formattedText need_update_application:Bool = DeepLinkInfo;
@ -1993,16 +1996,20 @@ textParseModeMarkdown = TextParseMode;
textParseModeHTML = TextParseMode;
//@class Proxy @description Contains information about a proxy server
//@class ProxyType @description Describes the type of the proxy server
//@description An empty proxy server
proxyEmpty = Proxy;
//@description A SOCKS5 proxy server @username Username for logging in; may be empty @password Password for logging in; may be empty
proxyTypeSocks5 username:string password:string = ProxyType;
//@description A SOCKS5 proxy server @server Proxy server IP address @port Proxy server port @username Username for logging in @password Password for logging in
proxySocks5 server:string port:int32 username:string password:string = Proxy;
//@description An MTProto proxy server @secret Proxy's secret in hexadecimal encoding
proxyTypeMtproto secret:string = ProxyType;
//@description An MTProro proxy server @server Proxy server IP address @port Proxy server port @secret Server's secret
proxyMtproto server:string port:int32 secret:string = Proxy;
//@description Contains information about a proxy server @id Unique proxy identifier @server Proxy server IP address @port Proxy server port @last_used_date Point in time (Unix timestamp) when the proxy was last used; 0 if never @is_enabled True, if the proxy is enabled now @type Type of a proxy
proxy id:int32 server:string port:int32 last_used_date:int32 is_enabled:Bool type:ProxyType = Proxy;
//@description Represents a list of proxy servers @proxies List of proxy servers
proxies proxies:vector<proxy> = Proxies;
//@description Describes a sticker that should be added to a sticker set @png_sticker PNG image with the sticker; must be up to 512 kB in size and fit in a 512x512 square @emojis Emoji corresponding to the sticker @mask_position For masks, position where the mask should be placed; may be null
@ -2129,7 +2136,7 @@ updateFile file:file = Update;
//@description The file generation process needs to be started by the client
//@generation_id Unique identifier for the generation process
//@original_path The path to a file from which a new file is generated, may be empty
//@original_path The path to a file from which a new file is generated; may be empty
//@destination_path The path to a file that should be created and where the new file should be generated
//@conversion String specifying the conversion applied to the original file. If conversion is "#url#" than original_path contains a HTTP/HTTPS URL of a file, which should be downloaded by the client
updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update;
@ -3153,11 +3160,23 @@ getTermsOfService = Text;
getDeepLinkInfo link:string = DeepLinkInfo;
//@description Sets the proxy server for network requests. Can be called before authorization @proxy Proxy server to use. Specify null to remove the proxy server
setProxy proxy:Proxy = Ok;
//@description Adds a proxy server for network requests. Can be called before authorization. Can be called before initialization @server Proxy server IP address @port Proxy server port @enable True, if the proxy should be enabled @type Type of a proxy
addProxy server:string port:int32 enable:Bool type:ProxyType = Proxy;
//@description Returns the proxy that is currently set up. Can be called before authorization
getProxy = Proxy;
//@description Enables a proxy. Only one proxy can be enabled at a time. Can be called before authorization @proxy_id The proxy identifier
enableProxy proxy_id:int32 = Ok;
//@description Disables currently enabled proxy. Can be called before authorization
disableProxy = Ok;
//@description Removes a proxy server. Can be called before authorization @proxy_id The proxy identifier
removeProxy proxy_id:int32 = Ok;
//@description Returns list of proxies that are currently set up. Can be called before authorization
getProxies = Proxies;
//@description Computes time needed to receive a response from a Telegram server through the proxy. Can be called before authorization @proxy_id The proxy identifier
pingProxy proxy_id:int32 = Seconds;
//@description Does nothing; for testing only

Binary file not shown.

View File

@ -926,6 +926,9 @@ void AuthManager::update_state(State new_state, bool force, bool should_save_sta
bool AuthManager::load_state() {
auto data = G()->td_db()->get_binlog_pmc()->get("auth_state");
if (data.empty()) {
return false;
}
DbState db_state;
auto status = log_event_parse(db_state, data);
if (status.is_error()) {

View File

@ -25903,7 +25903,11 @@ void MessagesManager::set_promoted_dialog_id(DialogId dialog_id) {
}
if (G()->parameters().use_message_db) {
G()->td_db()->get_binlog_pmc()->set("promoted_dialog_id", to_string(promoted_dialog_id_.get()));
if (promoted_dialog_id_.is_valid()) {
G()->td_db()->get_binlog_pmc()->set("promoted_dialog_id", to_string(promoted_dialog_id_.get()));
} else {
G()->td_db()->get_binlog_pmc()->erase("promoted_dialog_id");
}
LOG(INFO) << "Save promoted " << promoted_dialog_id_;
}

View File

@ -7096,22 +7096,43 @@ void Td::on_request(uint64 id, td_api::getDeepLinkInfo &request) {
create_handler<GetDeepLinkInfoQuery>(std::move(promise))->send(request.link_);
}
void Td::on_request(uint64 id, const td_api::getProxy &request) {
void Td::on_request(uint64 id, td_api::addProxy &request) {
CLEAN_INPUT_STRING(request.server_);
CREATE_REQUEST_PROMISE(promise);
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<Proxy> result) mutable {
send_closure(G()->connection_creator(), &ConnectionCreator::add_proxy, std::move(request.server_), request.port_,
request.enable_, std::move(request.type_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::enableProxy &request) {
CREATE_OK_REQUEST_PROMISE(promise);
send_closure(G()->connection_creator(), &ConnectionCreator::enable_proxy, request.proxy_id_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::disableProxy &request) {
CREATE_OK_REQUEST_PROMISE(promise);
send_closure(G()->connection_creator(), &ConnectionCreator::disable_proxy, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::removeProxy &request) {
CREATE_OK_REQUEST_PROMISE(promise);
send_closure(G()->connection_creator(), &ConnectionCreator::remove_proxy, request.proxy_id_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getProxies &request) {
CREATE_REQUEST_PROMISE(promise);
send_closure(G()->connection_creator(), &ConnectionCreator::get_proxies, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::pingProxy &request) {
CREATE_REQUEST_PROMISE(promise);
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<double> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(result.move_as_ok().as_td_api());
promise.set_value(make_tl_object<td_api::seconds>(result.move_as_ok()));
}
});
send_closure(G()->connection_creator(), &ConnectionCreator::get_proxy, std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::setProxy &request) {
CREATE_OK_REQUEST_PROMISE(promise);
send_closure(G()->connection_creator(), &ConnectionCreator::set_proxy, Proxy::from_td_api(request.proxy_));
promise.set_value(Unit());
send_closure(G()->connection_creator(), &ConnectionCreator::ping_proxy, request.proxy_id_, std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::getTextEntities &request) {

View File

@ -800,9 +800,17 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::getDeepLinkInfo &request);
void on_request(uint64 id, const td_api::getProxy &request);
void on_request(uint64 id, td_api::addProxy &request);
void on_request(uint64 id, const td_api::setProxy &request);
void on_request(uint64 id, const td_api::enableProxy &request);
void on_request(uint64 id, const td_api::disableProxy &request);
void on_request(uint64 id, const td_api::removeProxy &request);
void on_request(uint64 id, const td_api::getProxies &request);
void on_request(uint64 id, const td_api::pingProxy &request);
void on_request(uint64 id, const td_api::getTextEntities &request);

View File

@ -437,10 +437,6 @@ class CliClient final : public Actor {
return to_integer<int32>(trim(std::move(str)));
}
static int32 as_call_id(string str) {
return to_integer<int32>(trim(std::move(str)));
}
static td_api::object_ptr<td_api::InputFile> as_input_file_id(string str) {
return make_tl_object<td_api::inputFileId>(as_file_id(str));
}
@ -473,6 +469,14 @@ class CliClient final : public Actor {
return as_local_file(str);
}
static int32 as_call_id(string str) {
return to_integer<int32>(trim(std::move(str)));
}
static int32 as_proxy_id(string str) {
return to_integer<int32>(trim(std::move(str)));
}
static tl_object_ptr<td_api::location> as_location(string latitude, string longitude) {
return make_tl_object<td_api::location>(to_double(latitude), to_double(longitude));
}
@ -3052,9 +3056,13 @@ class CliClient final : public Actor {
as_message_ids(message_ids)));
} else if (op == "gdiff") {
send_request(make_tl_object<td_api::testGetDifference>());
} else if (op == "cproxy") {
send_request(make_tl_object<td_api::setProxy>(make_tl_object<td_api::proxyEmpty>()));
} else if (op == "sproxy") {
} else if (op == "dproxy") {
send_request(make_tl_object<td_api::disableProxy>());
} else if (op == "eproxy") {
send_request(make_tl_object<td_api::enableProxy>(as_proxy_id(args)));
} else if (op == "rproxy") {
send_request(make_tl_object<td_api::removeProxy>(as_proxy_id(args)));
} else if (op == "aproxy" || op == "aeproxy") {
string server;
string port;
string user;
@ -3062,15 +3070,17 @@ class CliClient final : public Actor {
std::tie(server, args) = split(args);
std::tie(port, args) = split(args);
std::tie(user, password) = split(args);
td_api::object_ptr<td_api::ProxyType> type;
if (!user.empty() && password.empty()) {
send_request(make_tl_object<td_api::setProxy>(
make_tl_object<td_api::proxyMtproto>(server, to_integer<int32>(port), user)));
type = make_tl_object<td_api::proxyTypeMtproto>(user);
} else {
send_request(make_tl_object<td_api::setProxy>(
make_tl_object<td_api::proxySocks5>(server, to_integer<int32>(port), user, password)));
type = make_tl_object<td_api::proxyTypeSocks5>(user, password);
}
} else if (op == "gproxy") {
send_request(make_tl_object<td_api::getProxy>());
send_request(make_tl_object<td_api::addProxy>(server, to_integer<int32>(port), op == "aeproxy", std::move(type)));
} else if (op == "gproxy" || op == "gproxies") {
send_request(make_tl_object<td_api::getProxies>());
} else if (op == "pproxy") {
send_request(make_tl_object<td_api::pingProxy>(as_proxy_id(args)));
} else if (op == "touch") {
auto r_fd = FileFd::open(args, FileFd::Read | FileFd::Write);
if (r_fd.is_error()) {
@ -3083,7 +3093,7 @@ class CliClient final : public Actor {
fd.write("a").ignore();
fd.seek(size).ignore();
fd.truncate_to_current_position(size).ignore();
} else if (op == "SetVerbosity") {
} else if (op == "SetVerbosity" || op == "SV") {
td::Log::set_verbosity_level(to_integer<int>(args));
} else if (op == "q" || op == "Quit") {
quit();

View File

@ -32,6 +32,7 @@
#include "td/utils/tl_helpers.h"
#include <algorithm>
#include <utility>
namespace td {
@ -215,35 +216,143 @@ void ConnectionCreator::set_net_stats_callback(std::shared_ptr<NetStatsCallback>
media_net_stats_callback_ = std::move(media_callback);
}
void ConnectionCreator::set_proxy(Proxy proxy) {
set_proxy_impl(std::move(proxy), false);
loop();
void ConnectionCreator::add_proxy(string server, int32 port, bool enable,
td_api::object_ptr<td_api::ProxyType> proxy_type,
Promise<td_api::object_ptr<td_api::proxy>> promise) {
if (proxy_type == nullptr) {
return promise.set_error(Status::Error(400, "Proxy type should not be empty"));
}
if (server.empty()) {
return promise.set_error(Status::Error(400, "Server name can't be empty"));
}
if (port <= 0 || port > 65535) {
return promise.set_error(Status::Error(400, "Wrong port number"));
}
Proxy new_proxy;
switch (proxy_type->get_id()) {
case td_api::proxyTypeSocks5::ID: {
auto type = td_api::move_object_as<td_api::proxyTypeSocks5>(proxy_type);
new_proxy = Proxy::socks5(server, port, type->username_, type->password_);
break;
}
case td_api::proxyTypeMtproto::ID: {
auto type = td_api::move_object_as<td_api::proxyTypeMtproto>(proxy_type);
if (type->secret_.size() != 32 || hex_decode(type->secret_).is_error()) {
return promise.set_error(Status::Error(400, "Wrong server secret"));
}
new_proxy = Proxy::mtproto(server, port, type->secret_);
break;
}
default:
UNREACHABLE();
}
auto proxy_id = [&] {
for (auto &proxy : proxies_) {
if (proxy.second == new_proxy) {
return proxy.first;
}
}
CHECK(max_proxy_id_ >= 2);
auto proxy_id = max_proxy_id_++;
G()->td_db()->get_binlog_pmc()->set("proxy_max_id", to_string(max_proxy_id_));
CHECK(proxies_.count(proxy_id) == 0);
proxies_.emplace(proxy_id, std::move(new_proxy));
G()->td_db()->get_binlog_pmc()->set(get_proxy_database_key(proxy_id),
log_event_store(proxies_[proxy_id]).as_slice().str());
}();
if (enable) {
enable_proxy_impl(proxy_id);
}
promise.set_value(get_proxy_object(proxy_id));
}
void ConnectionCreator::set_proxy_impl(Proxy proxy, bool from_db) {
auto have_proxy = proxy.type() != Proxy::Type::None;
if (proxy_ == proxy) {
if (!have_proxy) {
on_get_proxy_info(make_tl_object<telegram_api::help_proxyDataEmpty>(0));
}
void ConnectionCreator::enable_proxy(int32 proxy_id, Promise<Unit> promise) {
if (proxies_.count(proxy_id) == 0) {
return promise.set_error(Status::Error(400, "Unknown proxy identifier"));
}
enable_proxy_impl(proxy_id);
promise.set_value(Unit());
}
void ConnectionCreator::disable_proxy(Promise<Unit> promise) {
disable_proxy_impl();
promise.set_value(Unit());
}
void ConnectionCreator::remove_proxy(int32 proxy_id, Promise<Unit> promise) {
if (proxies_.count(proxy_id) == 0) {
return promise.set_error(Status::Error(400, "Unknown proxy identifier"));
}
if (proxy_id == active_proxy_id_) {
disable_proxy_impl();
}
proxies_.erase(proxy_id);
G()->td_db()->get_binlog_pmc()->erase(get_proxy_database_key(proxy_id));
G()->td_db()->get_binlog_pmc()->erase(get_proxy_used_database_key(proxy_id));
promise.set_value(Unit());
}
void ConnectionCreator::get_proxies(Promise<td_api::object_ptr<td_api::proxies>> promise) {
promise.set_value(td_api::make_object<td_api::proxies>(
transform(proxies_, [this](const std::pair<int32, Proxy> &proxy) { return get_proxy_object(proxy.first); })));
}
void ConnectionCreator::ping_proxy(int32 proxy_id, Promise<double> promise) {
if (proxies_.count(proxy_id) == 0) {
return promise.set_error(Status::Error(400, "Unknown proxy identifier"));
}
// TODO ping
promise.set_value(0.0);
}
void ConnectionCreator::enable_proxy_impl(int32 proxy_id) {
CHECK(proxies_.count(proxy_id) == 1);
if (proxy_id == active_proxy_id_) {
return;
}
if (proxy_.type() == Proxy::Type::Mtproto || proxy.type() == Proxy::Type::Mtproto) {
G()->mtproto_header().set_proxy(proxy);
if ((active_proxy_id_ != 0 && proxies_[active_proxy_id_].type() == Proxy::Type::Mtproto) ||
proxies_[proxy_id].type() == Proxy::Type::Mtproto) {
G()->mtproto_header().set_proxy(proxies_[proxy_id]);
G()->net_query_dispatcher().update_mtproto_header();
}
proxy_ = std::move(proxy);
active_proxy_id_ = proxy_id;
G()->td_db()->get_binlog_pmc()->set("proxy_active_id", to_string(proxy_id));
send_closure(G()->state_manager(), &StateManager::on_proxy, have_proxy);
on_proxy_changed(false);
}
void ConnectionCreator::disable_proxy_impl() {
if (active_proxy_id_ == 0) {
on_get_proxy_info(make_tl_object<telegram_api::help_proxyDataEmpty>(0));
return;
}
CHECK(proxies_.count(active_proxy_id_) == 1);
if (proxies_[active_proxy_id_].type() == Proxy::Type::Mtproto) {
G()->mtproto_header().set_proxy(Proxy());
G()->net_query_dispatcher().update_mtproto_header();
}
active_proxy_id_ = 0;
G()->td_db()->get_binlog_pmc()->erase("proxy_active_id");
on_proxy_changed(false);
}
void ConnectionCreator::on_proxy_changed(bool from_db) {
send_closure(G()->state_manager(), &StateManager::on_proxy, active_proxy_id_ != 0);
if (!from_db) {
if (have_proxy) {
G()->td_db()->get_binlog_pmc()->set("proxy", log_event_store(proxy_).as_slice().str());
} else {
G()->td_db()->get_binlog_pmc()->erase("proxy");
}
for (auto &child : children_) {
child.second.reset();
}
@ -255,15 +364,47 @@ void ConnectionCreator::set_proxy_impl(Proxy proxy, bool from_db) {
get_proxy_info_query_token_ = 0;
get_proxy_info_timestamp_ = Timestamp();
if (!have_proxy || !from_db) {
if (active_proxy_id_ == 0 || !from_db) {
on_get_proxy_info(make_tl_object<telegram_api::help_proxyDataEmpty>(0));
} else {
schedule_get_proxy_info(0);
}
loop();
}
void ConnectionCreator::get_proxy(Promise<Proxy> promise) {
promise.set_value(Proxy(proxy_));
string ConnectionCreator::get_proxy_database_key(int32 proxy_id) {
CHECK(proxy_id > 0);
if (proxy_id == 1) {
return "proxy";
}
return PSTRING() << "proxy" << proxy_id;
}
string ConnectionCreator::get_proxy_used_database_key(int32 proxy_id) {
CHECK(proxy_id > 0);
return PSTRING() << "proxy_used" << proxy_id;
}
td_api::object_ptr<td_api::proxy> ConnectionCreator::get_proxy_object(int32 proxy_id) const {
auto it = proxies_.find(proxy_id);
CHECK(it != proxies_.end());
const Proxy &proxy = it->second;
td_api::object_ptr<td_api::ProxyType> type;
switch (proxy.type()) {
case Proxy::Type::Socks5:
type = make_tl_object<td_api::proxyTypeSocks5>(proxy.user().str(), proxy.password().str());
break;
case Proxy::Type::Mtproto:
type = make_tl_object<td_api::proxyTypeMtproto>(proxy.secret().str());
break;
default:
UNREACHABLE();
}
auto last_used_date_it = proxy_last_used_date_.find(proxy_id);
auto last_used_date = last_used_date_it == proxy_last_used_date_.end() ? 0 : last_used_date_it->second;
return make_tl_object<td_api::proxy>(proxy_id, proxy.server().str(), proxy.port(), last_used_date,
proxy_id == active_proxy_id_, std::move(type));
}
void ConnectionCreator::on_network(bool network_flag, uint32 network_generation) {
@ -319,7 +460,7 @@ void ConnectionCreator::request_raw_connection(DcId dc_id, bool allow_media_only
CHECK(client.allow_media_only == allow_media_only);
CHECK(client.is_media == is_media);
}
VLOG(connections) << tag("client", format::as_hex(client.hash)) << " " << dc_id << " "
VLOG(connections) << "Request connection for " << tag("client", format::as_hex(client.hash)) << " to " << dc_id << " "
<< tag("allow_media_only", allow_media_only);
client.queries.push_back(std::move(promise));
@ -346,8 +487,10 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
if (close_flag_) {
return;
}
auto proxy_type = proxy_.type();
bool use_proxy = proxy_type != Proxy::Type::None;
Proxy *proxy = active_proxy_id_ == 0 ? nullptr : &proxies_[active_proxy_id_];
auto proxy_type = proxy == nullptr ? Proxy::Type::None : proxy->type();
bool use_proxy = proxy != nullptr;
bool use_socks5_proxy = proxy_type == Proxy::Type::Socks5;
bool use_mtproto_proxy = proxy_type == Proxy::Type::Mtproto;
if (use_proxy && !proxy_ip_address_.is_valid()) {
@ -426,7 +569,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
TRY_RESULT(info, dc_options_set_.find_connection(dc_id, allow_media_only, use_proxy));
stat = nullptr;
int16 raw_dc_id = narrow_cast<int16>(info.option->is_media_only() ? -dc_id.get_raw_id() : dc_id.get_raw_id());
TRY_RESULT(secret, hex_decode(proxy_.secret()));
TRY_RESULT(secret, hex_decode(proxy->secret()));
transport_type = {mtproto::TransportType::ObfuscatedTcp, raw_dc_id, std::move(secret)};
debug_str = PSTRING() << "Mtproto " << proxy_ip_address_ << " to DC" << raw_dc_id;
@ -526,7 +669,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
LOG(INFO) << "Start socks5: " << debug_str;
auto token = next_token();
children_[token] = create_actor<Socks5>(
"Socks5", std::move(socket_fd), mtproto_ip, proxy_.user().str(), proxy_.password().str(),
"Socks5", std::move(socket_fd), mtproto_ip, proxy->user().str(), proxy->password().str(),
std::make_unique<Callback>(std::move(promise), std::move(stats_callback)), create_reference(token));
} else {
ConnectionData data;
@ -542,7 +685,8 @@ void ConnectionCreator::client_create_raw_connection(Result<ConnectionData> r_co
string debug_str, uint32 network_generation) {
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), hash, check_mode,
debug_str](Result<std::unique_ptr<mtproto::RawConnection>> result) mutable {
VLOG(connections) << "Ready " << debug_str << " " << tag("checked", check_mode) << tag("ok", result.is_ok());
VLOG(connections) << "Ready connection " << (check_mode ? "(" : "(un") << "checked) "
<< (result.is_ok() ? result.ok().get() : nullptr) << " " << debug_str;
send_closure(std::move(actor_id), &ConnectionCreator::client_add_connection, hash, std::move(result), check_mode);
});
@ -588,6 +732,7 @@ void ConnectionCreator::client_add_connection(size_t hash,
client.checking_connections--;
}
if (r_raw_connection.is_ok()) {
VLOG(connections) << "Add ready connection " << r_raw_connection.ok().get() << " for " << tag("client", hash);
client.backoff.clear();
client.ready_connections.push_back(std::make_pair(r_raw_connection.move_as_ok(), Time::now_cached()));
}
@ -652,18 +797,59 @@ void ConnectionCreator::start_up() {
on_dc_options(std::move(dc_options));
}
Proxy proxy;
auto log_event_proxy = G()->td_db()->get_binlog_pmc()->get("proxy");
if (!log_event_proxy.empty()) {
log_event_parse(proxy, log_event_proxy).ensure();
auto proxy_info = G()->td_db()->get_binlog_pmc()->prefix_get("proxy");
auto it = proxy_info.find("proxy_max_id");
if (it != proxy_info.end()) {
max_proxy_id_ = to_integer<int32>(it->second);
proxy_info.erase(it);
}
it = proxy_info.find("proxy_active_id");
if (it != proxy_info.end()) {
active_proxy_id_ = to_integer<int32>(it->second);
proxy_info.erase(it);
}
for (auto &info : proxy_info) {
if (begins_with(info.first, "proxy_used")) {
int32 proxy_id = to_integer_safe<int32>(Slice(info.first).substr(10)).move_as_ok();
int32 last_used = to_integer_safe<int32>(info.second).move_as_ok();
proxy_last_used_date_[proxy_id] = last_used;
} else {
int32 proxy_id = info.first == "proxy" ? 1 : to_integer_safe<int32>(Slice(info.first).substr(5)).move_as_ok();
CHECK(proxies_.count(proxy_id) == 0);
log_event_parse(proxies_[proxy_id], info.second).ensure();
}
}
if (max_proxy_id_ == 0) {
// legacy one-proxy version
max_proxy_id_ = 2;
if (!proxies_.empty()) {
CHECK(proxies_.begin()->first == 1);
active_proxy_id_ = 1;
G()->td_db()->get_binlog_pmc()->set("proxy_active_id", "1");
}
G()->td_db()->get_binlog_pmc()->set("proxy_max_id", "2");
} else if (max_proxy_id_ < 2) {
LOG(ERROR) << "Found wrong max_proxy_id = " << max_proxy_id_;
max_proxy_id_ = 2;
}
if (active_proxy_id_ != 0) {
if (proxies_[active_proxy_id_].type() == Proxy::Type::Mtproto) {
G()->mtproto_header().set_proxy(proxies_[active_proxy_id_]);
G()->net_query_dispatcher().update_mtproto_header();
}
on_proxy_changed(true);
}
set_proxy_impl(std::move(proxy), true);
get_host_by_name_actor_ =
create_actor_on_scheduler<GetHostByNameActor>("GetHostByNameActor", G()->get_gc_scheduler_id(), 5 * 60 - 1, 0);
ref_cnt_guard_ = create_reference(-1);
is_inited_ = true;
loop();
}
@ -730,12 +916,15 @@ DcOptions ConnectionCreator::get_default_dc_options(bool is_test) {
}
void ConnectionCreator::loop() {
if (!is_inited_) {
return;
}
if (!network_flag_) {
return;
}
Timestamp timeout;
if (proxy_.type() == Proxy::Type::Mtproto) {
if (active_proxy_id_ != 0 && proxies_[active_proxy_id_].type() == Proxy::Type::Mtproto) {
if (get_proxy_info_timestamp_.is_in_past()) {
if (get_proxy_info_query_token_ == 0) {
get_proxy_info_query_token_ = next_token();
@ -749,12 +938,13 @@ void ConnectionCreator::loop() {
}
}
if (proxy_.type() != Proxy::Type::None) {
if (active_proxy_id_ != 0) {
if (resolve_proxy_timestamp_.is_in_past()) {
if (resolve_proxy_query_token_ == 0) {
resolve_proxy_query_token_ = next_token();
const Proxy &proxy = proxies_[active_proxy_id_];
send_closure(
get_host_by_name_actor_, &GetHostByNameActor::run, proxy_.server().str(), proxy_.port(),
get_host_by_name_actor_, &GetHostByNameActor::run, proxy.server().str(), proxy.port(),
PromiseCreator::lambda([actor_id = create_reference(resolve_proxy_query_token_)](Result<IPAddress> result) {
send_closure(std::move(actor_id), &ConnectionCreator::on_proxy_resolved, std::move(result), false);
}));

View File

@ -47,40 +47,6 @@ namespace td {
class Proxy {
public:
tl_object_ptr<td_api::Proxy> as_td_api() const {
switch (type_) {
case Type::None:
return make_tl_object<td_api::proxyEmpty>();
case Type::Socks5:
return make_tl_object<td_api::proxySocks5>(server_, port_, user_, password_);
case Type::Mtproto:
return make_tl_object<td_api::proxyMtproto>(server_, port_, secret_);
}
UNREACHABLE();
return nullptr;
}
static Proxy from_td_api(const tl_object_ptr<td_api::Proxy> &proxy) {
if (proxy == nullptr) {
return Proxy();
}
switch (proxy->get_id()) {
case td_api::proxyEmpty::ID:
return Proxy();
case td_api::proxySocks5::ID: {
auto &socks5_proxy = static_cast<const td_api::proxySocks5 &>(*proxy);
return Proxy::socks5(socks5_proxy.server_, socks5_proxy.port_, socks5_proxy.username_, socks5_proxy.password_);
}
case td_api::proxyMtproto::ID: {
auto &mtproto_proxy = static_cast<const td_api::proxyMtproto &>(*proxy);
return Proxy::mtproto(mtproto_proxy.server_, mtproto_proxy.port_, mtproto_proxy.secret_);
}
}
UNREACHABLE();
return Proxy();
}
static Proxy socks5(string server, int32 port, string user, string password) {
Proxy proxy;
proxy.type_ = Type::Socks5;
@ -165,8 +131,13 @@ class ConnectionCreator : public NetQueryCallback {
void set_net_stats_callback(std::shared_ptr<NetStatsCallback> common_callback,
std::shared_ptr<NetStatsCallback> media_callback);
void set_proxy(Proxy proxy);
void get_proxy(Promise<Proxy> promise);
void add_proxy(string server, int32 port, bool enable, td_api::object_ptr<td_api::ProxyType> proxy_type,
Promise<td_api::object_ptr<td_api::proxy>> promise);
void enable_proxy(int32 proxy_id, Promise<Unit> promise);
void disable_proxy(Promise<Unit> promise);
void remove_proxy(int32 proxy_id, Promise<Unit> promise);
void get_proxies(Promise<td_api::object_ptr<td_api::proxies>> promise);
void ping_proxy(int32 proxy_id, Promise<double> promise);
private:
ActorShared<> parent_;
@ -174,8 +145,12 @@ class ConnectionCreator : public NetQueryCallback {
bool network_flag_ = false;
uint32 network_generation_ = 0;
bool online_flag_ = false;
bool is_inited_ = false;
Proxy proxy_;
std::map<int32, Proxy> proxies_;
std::map<int32, int32> proxy_last_used_date_;
int32 max_proxy_id_ = 0;
int32 active_proxy_id_ = 0;
ActorOwn<GetHostByNameActor> get_host_by_name_actor_;
IPAddress proxy_ip_address_;
Timestamp resolve_proxy_timestamp_;
@ -243,7 +218,13 @@ class ConnectionCreator : public NetQueryCallback {
uint64 next_token() {
return ++current_token_;
}
void set_proxy_impl(Proxy proxy, bool from_db);
void enable_proxy_impl(int32 proxy_id);
void disable_proxy_impl();
void on_proxy_changed(bool from_db);
static string get_proxy_database_key(int32 proxy_id);
static string get_proxy_used_database_key(int32 proxy_id);
td_api::object_ptr<td_api::proxy> get_proxy_object(int32 proxy_id) const;
void start_up() override;
void hangup_shared() override;

View File

@ -37,6 +37,7 @@
namespace td {
namespace detail {
class GenAuthKeyActor : public Actor {
public:
GenAuthKeyActor(std::unique_ptr<mtproto::AuthKeyHandshake> handshake,
@ -83,13 +84,16 @@ class GenAuthKeyActor : public Actor {
handshake_promise_.set_value(std::move(handshake_));
return;
}
auto raw_connection = r_raw_connection.move_as_ok();
VLOG(dc) << "Receive raw connection " << raw_connection.get();
network_generation_ = raw_connection->extra_;
child_ = create_actor_on_scheduler<mtproto::HandshakeActor>(
"HandshakeActor", G()->get_slow_net_scheduler_id(), std::move(handshake_), std::move(raw_connection),
std::move(context_), 10, std::move(connection_promise_), std::move(handshake_promise_));
}
};
} // namespace detail
Session::Session(unique_ptr<Callback> callback, std::shared_ptr<AuthDataShared> shared_auth_data, bool is_main,
@ -178,7 +182,7 @@ void Session::connection_online_update(bool force) {
return;
}
connection_online_flag_ = new_connection_online_flag;
LOG(INFO) << "Set connection_online " << connection_online_flag_;
VLOG(dc) << "Set connection_online " << connection_online_flag_;
if (is_main_) {
if (main_connection_.connection) {
main_connection_.connection->set_online(connection_online_flag_);
@ -847,9 +851,10 @@ void Session::connection_open(ConnectionInfo *info, bool ask_info) {
});
if (cached_connection_) {
LOG(INFO) << "Reuse cached connection";
VLOG(dc) << "Reuse cached connection";
promise.set_value(std::move(cached_connection_));
} else {
VLOG(dc) << "Request new connection";
callback_->request_raw_connection(std::move(promise));
}
@ -857,7 +862,7 @@ void Session::connection_open(ConnectionInfo *info, bool ask_info) {
}
void Session::connection_add(std::unique_ptr<mtproto::RawConnection> raw_connection) {
LOG(INFO) << "Cache connection";
VLOG(dc) << "Cache connection " << raw_connection.get();
cached_connection_ = std::move(raw_connection);
cached_connection_timestamp_ = Time::now();
}
@ -875,10 +880,10 @@ void Session::connection_check_mode(ConnectionInfo *info) {
void Session::connection_open_finish(ConnectionInfo *info,
Result<std::unique_ptr<mtproto::RawConnection>> r_raw_connection) {
if (close_flag_ || info->state != ConnectionInfo::State::Connecting) {
VLOG(dc) << "Ignore raw connection while closing";
return;
}
current_info_ = info;
// Create new connection
if (r_raw_connection.is_error()) {
LOG(WARNING) << "Failed to open socket: " << r_raw_connection.error();
info->state = ConnectionInfo::State::Empty;
@ -887,6 +892,7 @@ void Session::connection_open_finish(ConnectionInfo *info,
}
auto raw_connection = r_raw_connection.move_as_ok();
VLOG(dc) << "Receive raw connection " << raw_connection.get();
if (raw_connection->extra_ != network_generation_) {
LOG(WARNING) << "Got RawConnection with old network_generation";
info->state = ConnectionInfo::State::Empty;
@ -897,10 +903,10 @@ void Session::connection_open_finish(ConnectionInfo *info,
Mode expected_mode =
raw_connection->get_transport_type().type == mtproto::TransportType::Http ? Mode::Http : Mode::Tcp;
if (mode_ != expected_mode) {
LOG(INFO) << "Change mode " << mode_ << "--->" << expected_mode;
VLOG(dc) << "Change mode " << mode_ << "--->" << expected_mode;
mode_ = expected_mode;
if (info->connection_id == 1 && mode_ != Mode::Http) {
LOG(WARNING) << "Got tcp connection, for long poll connection";
LOG(WARNING) << "Got tcp connection for long poll connection";
connection_add(std::move(raw_connection));
info->state = ConnectionInfo::State::Empty;
yield();

View File

@ -409,7 +409,7 @@ void Scheduler::set_actor_timeout_in(ActorInfo *actor_info, double timeout) {
void Scheduler::set_actor_timeout_at(ActorInfo *actor_info, double timeout_at) {
HeapNode *heap_node = actor_info->get_heap_node();
VLOG(actor) << "set actor " << *actor_info << " " << tag("timeout", timeout_at) << timeout_at - Time::now_cached();
VLOG(actor) << "Set actor " << *actor_info << " timeout in " << timeout_at - Time::now_cached();
if (heap_node->in_heap()) {
timeout_queue_.fix(timeout_at, heap_node);
} else {