From 3386e427a081ec640f6888e6f466b2dee80f2a58 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 3 Apr 2026 16:25:49 +0300 Subject: [PATCH] Added ability to check status from connection box. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/boxes/connection_box.cpp | 211 ++++++++++++++---- Telegram/SourceFiles/boxes/connection_box.h | 1 - 3 files changed, 174 insertions(+), 39 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1f9f61d5f4..2eca1fc8e9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -333,6 +333,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_proxy_box_port" = "Port"; "lng_proxy_box_secret" = "Secret"; "lng_proxy_box_status" = "Status"; +"lng_proxy_box_check_status" = "Check Status"; "lng_proxy_box_username" = "Username"; "lng_proxy_box_password" = "Password"; "lng_proxy_invalid" = "The proxy link is invalid."; diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index 757586b04c..07e5185dba 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -1355,6 +1355,100 @@ void ProxyBox::addLabel( st::proxyEditTitlePadding); } +struct ProxyChecker { + using Checker = MTP::details::ConnectionPointer; + + Checker v4; + Checker v6; + + void start( + not_null mtproto, + const ProxyData &proxy, + Fn done, + Fn fail) { + using Connection = MTP::details::AbstractConnection; + using Variants = MTP::DcOptions::Variants; + + v4 = nullptr; + v6 = nullptr; + const auto connType = (proxy.type == ProxyData::Type::Http) + ? Variants::Http + : Variants::Tcp; + const auto dcId = mtproto->mainDcId(); + const auto setup = [&]( + Checker &checker, + const bytes::vector &secret) { + checker = Connection::Create( + mtproto, + connType, + QThread::currentThread(), + secret, + proxy); + const auto raw = checker.get(); + raw->connect(raw, &Connection::connected, [=] { + const auto ping = raw->pingTime(); + v4 = nullptr; + v6 = nullptr; + if (done) { + done(ping); + } + }); + const auto failed = [=] { + if (v4.get() == raw) { + v4 = nullptr; + } else if (v6.get() == raw) { + v6 = nullptr; + } + if (!v4 && !v6 && fail) { + fail(); + } + }; + raw->connect(raw, &Connection::disconnected, failed); + raw->connect(raw, &Connection::error, failed); + }; + if (proxy.type == ProxyData::Type::Mtproto) { + const auto secret = proxy.secretFromMtprotoPassword(); + setup(v4, secret); + v4->connectToServer( + proxy.host, + proxy.port, + secret, + dcId, + false); + } else { + const auto options = mtproto->dcOptions().lookup( + dcId, + MTP::DcType::Regular, + true); + const auto tryConnect = [&]( + Checker &checker, + Variants::Address address) { + const auto &list = options.data[address][connType]; + if (list.empty() + || ((address == Variants::IPv6) + && !Core::App().settings().proxy() + .tryIPv6())) { + checker = nullptr; + return; + } + const auto &endpoint = list.front(); + setup(checker, endpoint.secret); + checker->connectToServer( + QString::fromStdString(endpoint.ip), + endpoint.port, + endpoint.secret, + dcId, + false); + }; + tryConnect(v4, Variants::IPv4); + tryConnect(v6, Variants::IPv6); + if (!v4 && !v6 && fail) { + fail(); + } + } + } +}; + } // namespace ProxiesBoxController::ProxiesBoxController(not_null account) @@ -1419,7 +1513,7 @@ void ProxiesBoxController::ShowApplyConfirmation( QString() ).replace(UrlEndRegExp, QString()); const auto box = [=](not_null box) { - box->setTitle(tr::lng_proxy_box_title()); + box->setTitle(tr::lng_proxy_box_table_title()); box->setStyle(st::proxyApplyBox); box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); @@ -1463,6 +1557,51 @@ void ProxiesBoxController::ShowApplyConfirmation( add(proxy.password, tr::lng_proxy_box_secret()); } + { + const auto checker = box->lifetime().make_state< + ProxyChecker>(); + const auto statusValue = box->lifetime().make_state< + rpl::variable + >(Ui::Text::Link( + tr::lng_proxy_box_check_status(tr::now))); + const auto statusLabel = Ui::AddTableRow( + table, + tr::lng_proxy_box_status(), + statusValue->value()); + const auto relayout = [=] { + table->resizeToWidth(table->width()); + }; + statusLabel->setClickHandlerFilter([=](const auto &...) { + const auto account = controller + ? &controller->session().account() + : &Core::App().activeAccount(); + *statusValue = TextWithEntities{ + tr::lng_proxy_box_table_checking(tr::now), + }; + statusLabel->setTextColorOverride(st::creditsBg3->c); + relayout(); + checker->start(&account->mtp(), proxy, [=](int ping) { + *statusValue = TextWithEntities{ + tr::lng_proxy_box_table_available( + tr::now, + lt_ping, + QString::number(ping)), + }; + statusLabel->setTextColorOverride( + st::proxyRowStatusFgAvailable->c); + relayout(); + }, [=] { + *statusValue = TextWithEntities{ + tr::lng_proxy_box_table_unavailable(tr::now), + }; + statusLabel->setTextColorOverride( + st::proxyRowStatusFgOffline->c); + relayout(); + }); + return false; + }); + } + if (type == Type::Mtproto) { table->addRow( object_ptr( @@ -1475,7 +1614,7 @@ void ProxiesBoxController::ShowApplyConfirmation( } const auto enableButton = box->addButton( - tr::lng_sure_enable(), + tr::lng_proxy_box_table_button(), [=] { auto &proxies = Core::App().settings().proxy().list(); if (!ranges::contains(proxies, proxy)) { @@ -1519,9 +1658,9 @@ void ProxiesBoxController::refreshChecker(Item &item) { : Variants::Tcp; const auto mtproto = &_account->mtp(); const auto dcId = mtproto->mainDcId(); - const auto forFiles = false; item.state = ItemState::Checking; + const auto id = item.id; const auto setup = [&](Checker &checker, const bytes::vector &secret) { checker = MTP::details::AbstractConnection::Create( mtproto, @@ -1529,7 +1668,35 @@ void ProxiesBoxController::refreshChecker(Item &item) { QThread::currentThread(), secret, item.data); - setupChecker(item.id, checker); + using Connection = MTP::details::AbstractConnection; + const auto pointer = checker.get(); + pointer->connect(pointer, &Connection::connected, [=] { + const auto item = findById(id); + const auto pingTime = pointer->pingTime(); + item->checker = nullptr; + item->checkerv6 = nullptr; + if (item->state == ItemState::Checking) { + item->state = ItemState::Available; + item->ping = pingTime; + updateView(*item); + } + }); + const auto failed = [=] { + const auto item = findById(id); + if (item->checker == pointer) { + item->checker = nullptr; + } else if (item->checkerv6 == pointer) { + item->checkerv6 = nullptr; + } + if (!item->checker + && !item->checkerv6 + && item->state == ItemState::Checking) { + item->state = ItemState::Unavailable; + updateView(*item); + } + }; + pointer->connect(pointer, &Connection::disconnected, failed); + pointer->connect(pointer, &Connection::error, failed); }; if (item.data.type == Type::Mtproto) { const auto secret = item.data.secretFromMtprotoPassword(); @@ -1539,7 +1706,7 @@ void ProxiesBoxController::refreshChecker(Item &item) { item.data.port, secret, dcId, - forFiles); + false); item.checkerv6 = nullptr; } else { const auto options = mtproto->dcOptions().lookup( @@ -1563,7 +1730,7 @@ void ProxiesBoxController::refreshChecker(Item &item) { endpoint.port, endpoint.secret, dcId, - forFiles); + false); }; connect(item.checker, Variants::IPv4); connect(item.checkerv6, Variants::IPv6); @@ -1573,38 +1740,6 @@ void ProxiesBoxController::refreshChecker(Item &item) { } } -void ProxiesBoxController::setupChecker(int id, const Checker &checker) { - using Connection = MTP::details::AbstractConnection; - const auto pointer = checker.get(); - pointer->connect(pointer, &Connection::connected, [=] { - const auto item = findById(id); - const auto pingTime = pointer->pingTime(); - item->checker = nullptr; - item->checkerv6 = nullptr; - if (item->state == ItemState::Checking) { - item->state = ItemState::Available; - item->ping = pingTime; - updateView(*item); - } - }); - const auto failed = [=] { - const auto item = findById(id); - if (item->checker == pointer) { - item->checker = nullptr; - } else if (item->checkerv6 == pointer) { - item->checkerv6 = nullptr; - } - if (!item->checker - && !item->checkerv6 - && item->state == ItemState::Checking) { - item->state = ItemState::Unavailable; - updateView(*item); - } - }; - pointer->connect(pointer, &Connection::disconnected, failed); - pointer->connect(pointer, &Connection::error, failed); -} - object_ptr ProxiesBoxController::CreateOwningBox( not_null account, const QString &highlightId) { diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index fcbe5ad6f6..c33f8ea0f4 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -117,7 +117,6 @@ private: void share(const ProxyData &proxy, bool qr = false); void saveDelayed(); void refreshChecker(Item &item); - void setupChecker(int id, const Checker &checker); void replaceItemWith( std::vector::iterator which,