176 lines
5.7 KiB
C++
176 lines
5.7 KiB
C++
#include <functional>
|
|
#include <unistd.h>
|
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
#include "tg.h"
|
|
#include "td/telegram/td_api.h"
|
|
|
|
using namespace tg;
|
|
|
|
TelegramClient::TelegramClient(uv_loop_t *eventLoop, long apiId, std::string apiHash, std::string phoneNumber)
|
|
: m_eventLoop(eventLoop), m_apiId(apiId), m_apiHash(apiHash), m_phoneNumber(phoneNumber) {}
|
|
|
|
bool TelegramClient::start() {
|
|
spdlog::debug("tg: start");
|
|
if (m_running) return false;
|
|
m_running = true;
|
|
|
|
spdlog::debug("tg: creating uv handle");
|
|
m_uvHandle = new uv_async_t;
|
|
m_uvHandle->data = (void*)this;
|
|
uv_async_init(m_eventLoop, m_uvHandle, TelegramClient::uv_callback);
|
|
|
|
spdlog::debug("tg: starting telegram thread");
|
|
m_thread = std::thread([this](){
|
|
run_thread();
|
|
});
|
|
return true;
|
|
}
|
|
|
|
TelegramClient::~TelegramClient() {
|
|
if (m_thread.joinable()) {
|
|
send_query(td_api::make_object<td_api::close>(), {});
|
|
m_thread.join();
|
|
|
|
if (m_uvHandle)
|
|
uv_close((uv_handle_t*)m_uvHandle, TelegramClient::uv_close_handle_callback);
|
|
}
|
|
}
|
|
|
|
void TelegramClient::run_thread() {
|
|
spdlog::debug("tg: i am telegram thread");
|
|
td::ClientManager::execute(td_api::make_object<td_api::setLogVerbosityLevel>(0));
|
|
m_clientManager = std::make_unique<td::ClientManager>();
|
|
m_clientId = m_clientManager->create_client_id();
|
|
send_query(td_api::make_object<td_api::getOption>("version"), {});
|
|
run_telegram_main_loop();
|
|
}
|
|
|
|
void TelegramClient::run_telegram_main_loop() {
|
|
spdlog::info("tg: begin telegram main loop");
|
|
while (m_running) {
|
|
if (!process_response(m_clientManager->receive(500))) {
|
|
spdlog::info("tg: closed");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TelegramClient::send_query(td_api::object_ptr<td_api::Function> f, std::function<void(TgObject)> callback) {
|
|
std::uint64_t query_id = m_nextQueryId++;
|
|
if (callback) {
|
|
m_handlers.emplace(query_id, std::move(callback));
|
|
}
|
|
m_clientManager->send(m_clientId, query_id, std::move(f));
|
|
}
|
|
|
|
bool TelegramClient::process_response(td::ClientManager::Response response) {
|
|
if (!response.object) {
|
|
return true;
|
|
}
|
|
if (response.object->get_id() == td_api::updateAuthorizationState::ID) {
|
|
auto authUpdate = (td_api::updateAuthorizationState*) response.object.get();
|
|
spdlog::debug("updateAuthorizationState: {}", authUpdate->authorization_state_->get_id());
|
|
switch (authUpdate->authorization_state_->get_id()) {
|
|
case td_api::authorizationStateClosed::ID:
|
|
spdlog::debug("closed");
|
|
return false;
|
|
case td_api::authorizationStateWaitTdlibParameters::ID:
|
|
spdlog::debug("setting tdlib parameters");
|
|
set_tdlib_parameters();
|
|
return true;
|
|
case td_api::authorizationStateWaitPhoneNumber::ID:
|
|
spdlog::debug("setting phone number");
|
|
set_phone_number();
|
|
return true;
|
|
case td_api::authorizationStateWaitPassword::ID:
|
|
spdlog::debug("setting password");
|
|
if (passwordProvider)
|
|
passwordProvider(std::bind(&TelegramClient::set_password, this, std::placeholders::_1));
|
|
return true;
|
|
case td_api::authorizationStateWaitCode::ID:
|
|
spdlog::debug("setting 2FA code");
|
|
if (authCodeProvider)
|
|
authCodeProvider(std::bind(&TelegramClient::set_code, this, std::placeholders::_1));
|
|
return true;
|
|
}
|
|
}
|
|
m_responseQueueMutex.lock();
|
|
m_responseQueue.push_back(std::move(response));
|
|
m_responseQueueMutex.unlock();
|
|
|
|
uv_async_send(m_uvHandle);
|
|
return true;
|
|
}
|
|
|
|
void TelegramClient::set_tdlib_parameters() {
|
|
auto query = td_api::make_object<td_api::setTdlibParameters>();
|
|
query->database_directory_ = "tdata";
|
|
query->use_message_database_ = true;
|
|
query->use_secret_chats_ = false;
|
|
query->api_id_ = m_apiId;
|
|
query->api_hash_ = m_apiHash;
|
|
query->system_language_code_ = "en";
|
|
query->device_model_ = "server";
|
|
query->application_version_ = "0.1.0";
|
|
send_query(std::move(query), {});
|
|
}
|
|
|
|
void TelegramClient::set_phone_number() {
|
|
auto query = td_api::make_object<td_api::setAuthenticationPhoneNumber>();
|
|
query->phone_number_ = m_phoneNumber;
|
|
send_query(std::move(query), {});
|
|
}
|
|
|
|
void TelegramClient::set_code(std::string code) {
|
|
spdlog::debug("setting auth code {}", code);
|
|
send_query(td_api::make_object<td_api::checkAuthenticationCode>(code), {});
|
|
}
|
|
|
|
void TelegramClient::set_password(std::string password) {
|
|
spdlog::debug("setting password {}", password);
|
|
send_query(td_api::make_object<td_api::checkAuthenticationPassword>(password), {});
|
|
}
|
|
|
|
void TelegramClient::uv_callback(uv_async_t *h) {
|
|
//spdlog::debug("tg: libuv callback");
|
|
TelegramClient *self = (TelegramClient*)h->data;
|
|
|
|
self->m_responseQueueMutex.lock();
|
|
while (self->m_responseQueue.size() > 0) {
|
|
auto response = std::move(self->m_responseQueue.front());
|
|
self->m_responseQueue.pop_front();
|
|
if (response.request_id == 0) {
|
|
self->dispatch_update(response.object);
|
|
} else {
|
|
self->dispatch_response(response.request_id, std::move(response.object));
|
|
}
|
|
}
|
|
self->m_responseQueueMutex.unlock();
|
|
}
|
|
|
|
void TelegramClient::dispatch_update(TgObject &update) {
|
|
//spdlog::debug("tg: update");
|
|
for (auto i = m_updateHandlers.begin(); i != m_updateHandlers.end(); i++) {
|
|
i->first(i->second, *update.get());
|
|
}
|
|
}
|
|
|
|
void TelegramClient::dispatch_response(std::uint64_t queryId, TgObject response) {
|
|
spdlog::debug("tg: response to {}", queryId);
|
|
auto queryHandler = m_handlers.find(queryId);
|
|
if (queryHandler != m_handlers.end()) {
|
|
queryHandler->second(std::move(response));
|
|
}
|
|
}
|
|
|
|
void TelegramClient::uv_close_handle_callback(uv_handle_t *h) {
|
|
spdlog::debug("tg: closing uv handle");
|
|
delete h;
|
|
}
|
|
|
|
void TelegramClient::add_update_handler(std::function<void(void*, td_api::Object&)> handler, void *context) {
|
|
m_updateHandlers.push_back({std::move(handler), context});
|
|
}
|