ARTICLE AD BOX
I'm working on a C++ program using TDLib
to log into Telegram. I want to prompt the user for their phone number, verification code, and 2FA password.
However, the program loops infinitely and never waits for input at std::getline. Here’s the full chunk:
#include <iostream> #include <string> #include <memory> #include <nlohmann/json.hpp> #include <filesystem> #include <thread> #include <chrono> #include <atomic> #include "td/telegram/td_json_client.h" using json = nlohmann::json; struct Credentials { static constexpr int64_t API_ID = 38753935; static constexpr const char* API_HASH = "4b80a6b40a8b2fd3396f7e8599d7ef16"; }; enum class AuthState { WaitTdlibParameters, WaitPhoneNumber, WaitCode, WaitPassword, Ready, Closed }; class TelegramClient { private: void* client_; AuthState current_state_ = AuthState::WaitTdlibParameters; std::atomic<bool> input_pending_{false}; void cleanup_tdl_db(const std::string& db_dir) { std::filesystem::path db_path(db_dir); if (std::filesystem::exists(db_path)) { std::cout << "🧹 Cleaning TDLib database..." << std::endl; std::filesystem::remove_all(db_path); } std::filesystem::create_directory(db_path); } std::string create_request(const std::string& type, const json& params) { json request = {{"@type", type}}; for (auto& [key, value] : params.items()) { request[key] = value; } return request.dump(); } public: TelegramClient() : client_(td_json_client_create()) {} ~TelegramClient() { if (client_) td_json_client_destroy(client_); } bool init() { cleanup_tdl_db("tdlib"); json params = { {"database_directory", "tdlib"}, {"use_file_database", false}, {"use_chat_info_database", false}, {"use_message_database", false}, {"api_id", Credentials::API_ID}, {"api_hash", Credentials::API_HASH}, {"system_language_code", "en"}, {"device_model", "Desktop"}, {"application_version", "1.0"} }; std::string request = create_request("setTdlibParameters", params); td_json_client_send(client_, request.c_str()); std::cout << "📱 TDLib ready. Waiting for auth..." << std::endl; return true; } AuthState get_state() const { return current_state_; } void* get_client() const { return client_; } bool input_pending() const { return input_pending_; } void set_input_pending(bool pending) { input_pending_ = pending; } void process_update(const std::string& raw_update) { try { json update = json::parse(raw_update); if (update["@type"] != "updateAuthorizationState") return; std::string state_type = update["authorization_state"]["@type"]; std::cout << "🔄 Auth: " << state_type << std::endl; if (state_type == "authorizationStateWaitPhoneNumber") { current_state_ = AuthState::WaitPhoneNumber; } else if (state_type == "authorizationStateWaitCode") { current_state_ = AuthState::WaitCode; } else if (state_type == "authorizationStateWaitPassword") { current_state_ = AuthState::WaitPassword; } else if (state_type == "authorizationStateReady") { current_state_ = AuthState::Ready; std::cout << "✅ AUTHORIZED!" << std::endl; } } catch (...) {} } void send_phone(const std::string& phone) { json params = {{"phone_number", phone}}; td_json_client_send(client_, create_request("setAuthenticationPhoneNumber", params).c_str()); std::cout << "📤 Phone sent!" << std::endl; } void send_code(const std::string& code) { json params = {{"code", code}}; td_json_client_send(client_, create_request("checkAuthenticationCode", params).c_str()); std::cout << "📤 Code sent!" << std::endl; } void send_password(const std::string& password) { json params = {{"password", password}}; td_json_client_send(client_, create_request("checkAuthenticationPassword", params).c_str()); std::cout << "📤 Password sent!" << std::endl; } }; std::string safe_getline() { std::string input; if (!std::getline(std::cin, input)) { input.clear(); } // Trim whitespace input.erase(0, input.find_first_not_of(" \t\n\r\f\v")); input.erase(input.find_last_not_of(" \t\n\r\f\v") + 1); return input; } int main() { TelegramClient client; std::string input; if (!client.init()) { return 1; } std::cout << "📱 Telegram client starting..." << std::endl; while (true) { AuthState state = client.get_state(); if (state == AuthState::Ready) { break; } // Non-blocking check first - TDLib auto-frees results on next call [web:11] const char* result = td_json_client_receive(client.get_client(), 0.0); if (result) { client.process_update(result); // NO destroy_result needed - TDLib handles it automatically continue; } // Handle input states with proper blocking if (state == AuthState::WaitPhoneNumber && !client.input_pending()) { std::cout << "\n📱 Enter phone number (e.g. +1234567890): "; std::cout.flush(); client.set_input_pending(true); input = safe_getline(); if (!input.empty()) { client.send_phone(input); } client.set_input_pending(false); } else if (state == AuthState::WaitCode && !client.input_pending()) { std::cout << "\n🔑 Enter verification code: "; std::cout.flush(); client.set_input_pending(true); input = safe_getline(); if (!input.empty()) { client.send_code(input); } client.set_input_pending(false); } else if (state == AuthState::WaitPassword && !client.input_pending()) { std::cout << "\n🔒 Enter 2FA password: "; std::cout.flush(); client.set_input_pending(true); input = safe_getline(); if (!input.empty()) { client.send_password(input); } client.set_input_pending(false); } else { // Small sleep to prevent busy waiting std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } std::cout << "\n🎉 SUCCESS! Telegram client authorized. Press Enter to exit." << std::endl; std::string dummy; std::getline(std::cin, dummy); // Close TDLib td_json_client_send(client.get_client(), "{\"@type\": \"close\"}"); // Drain remaining updates - TDLib auto-manages memory [web:11] while (true) { const char* result = td_json_client_receive(client.get_client(), 0.1); if (!result) break; // NO explicit destroy needed } return 0; }I’ve tried using std::cin directly and safe_getline(), but it still doesn’t block; the loop keeps spinning.
I understand TDLib is asynchronous, but I want a simple way to block the main thread for input when needed without busy looping.
How can I restructure the loop to properly wait for phone/code/password input while still processing TDLib updates?
Environment:
TDLib 1.x
C++17
Linux
What I’ve tried:
Non-blocking td_json_client_receive with timeout=0.0
Using atomic input_pending_ flag
std::getline and std::cin
I have tried api_id and api_has with python script below and it worked
from telethon import TelegramClient api_id = 38753935 api_hash = "4b80a6b40a8b2fd3396f7e8599d7ef16" client = TelegramClient("session", api_id, api_hash) async def main(): print("Your dialogs:") async for dialog in client.iter_dialogs(): print("-", dialog.name) with client: client.loop.run_until_complete(main())Question: How can I make the program properly wait for user input when TDLib asks for a phone number, verification code, or 2FA password, without losing incoming TDLib updates?
