summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/example/cpp
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2018-04-27 21:33:17 +0300
committeraunsane <aunsane@gmail.com>2018-04-27 21:33:17 +0300
commite1ec72eab6d00b3ba38e5932bc88920f103b6e4a (patch)
tree999de2725a83e30fbbf6576200525d4ef0c5fe38 /protocols/Telegram/tdlib/td/example/cpp
parentb9ce1d4d98525490ca1a38e2d9fd4f3369adb3e0 (diff)
Telegram: initial commit
- tdlib moved to telegram dir
Diffstat (limited to 'protocols/Telegram/tdlib/td/example/cpp')
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/.gitignore1
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt13
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/README.md24
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/td_example.cpp308
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp33
5 files changed, 379 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/example/cpp/.gitignore b/protocols/Telegram/tdlib/td/example/cpp/.gitignore
new file mode 100644
index 0000000000..336dc7d458
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/.gitignore
@@ -0,0 +1 @@
+td/
diff --git a/protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt b/protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt
new file mode 100644
index 0000000000..3e7794d4fa
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+project(TdExample VERSION 1.0 LANGUAGES CXX)
+
+find_package(Td 1.2.0 REQUIRED)
+
+add_executable(tdjson_example tdjson_example.cpp)
+target_link_libraries(tdjson_example PRIVATE Td::TdJson)
+set_property(TARGET tdjson_example PROPERTY CXX_STANDARD 11)
+
+add_executable(td_example td_example.cpp)
+target_link_libraries(td_example PRIVATE Td::TdStatic)
+set_property(TARGET td_example PROPERTY CXX_STANDARD 14)
diff --git a/protocols/Telegram/tdlib/td/example/cpp/README.md b/protocols/Telegram/tdlib/td/example/cpp/README.md
new file mode 100644
index 0000000000..9e5de531ba
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/README.md
@@ -0,0 +1,24 @@
+# TDLib cpp basic usage examples
+
+TDLib should be prebuilt and installed to local subdirectory `td/`:
+```
+cd <path to TDLib sources>
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../example/cpp/td ..
+cmake --build . --target install
+```
+Also see [building](https://github.com/tdlib/td#building) for additional details on TDLib building.
+
+Then you can build the examples:
+```
+cd <path to TDLib sources>/example/cpp
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DTd_DIR=<full path to TDLib sources>/example/cpp/td/lib/cmake/Td ..
+cmake --build .
+```
+
+Documentation for all available classes and methods can be found at https://core.telegram.org/tdlib/docs.
+
+To run `tdjson_example` you may need to manually copy a `tdjson` shared library from `td/bin` to a directory containing built binaries.
diff --git a/protocols/Telegram/tdlib/td/example/cpp/td_example.cpp b/protocols/Telegram/tdlib/td/example/cpp/td_example.cpp
new file mode 100644
index 0000000000..1efbf465b9
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/td_example.cpp
@@ -0,0 +1,308 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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/Client.h>
+#include <td/telegram/Log.h>
+#include <td/telegram/td_api.h>
+#include <td/telegram/td_api.hpp>
+
+#include <cstdint>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Simple single-threaded example of TDLib usage.
+// Real world programs should use separate thread for the user input.
+// Example includes user authentication, receiving updates, getting chat list and sending text messages.
+
+// overloaded
+namespace detail {
+template <class... Fs>
+struct overload;
+
+template <class F>
+struct overload<F> : public F {
+ explicit overload(F f) : F(f) {
+ }
+};
+template <class F, class... Fs>
+struct overload<F, Fs...>
+ : public overload<F>
+ , overload<Fs...> {
+ overload(F f, Fs... fs) : overload<F>(f), overload<Fs...>(fs...) {
+ }
+ using overload<F>::operator();
+ using overload<Fs...>::operator();
+};
+} // namespace detail
+
+template <class... F>
+auto overloaded(F... f) {
+ return detail::overload<F...>(f...);
+}
+
+namespace td_api = td::td_api;
+
+class TdExample {
+ public:
+ TdExample() {
+ td::Log::set_verbosity_level(1);
+ client_ = std::make_unique<td::Client>();
+ }
+
+ void loop() {
+ while (true) {
+ if (need_restart_) {
+ restart();
+ } else if (!are_authorized_) {
+ process_response(client_->receive(10));
+ } else {
+ std::cerr << "Enter action [q] quit [u] check for updates and request results [c] show chats [m <id> <text>] "
+ "send message [l] logout: "
+ << std::endl;
+ std::string line;
+ std::getline(std::cin, line);
+ std::istringstream ss(line);
+ std::string action;
+ if (!(ss >> action)) {
+ continue;
+ }
+ if (action == "q") {
+ return;
+ }
+ if (action == "u") {
+ std::cerr << "Checking for updates..." << std::endl;
+ while (true) {
+ auto response = client_->receive(0);
+ if (response.object) {
+ process_response(std::move(response));
+ } else {
+ break;
+ }
+ }
+ } else if (action == "l") {
+ std::cerr << "Logging out..." << std::endl;
+ send_query(td_api::make_object<td_api::logOut>(), {});
+ } else if (action == "m") {
+ std::int64_t chat_id;
+ ss >> chat_id;
+ ss.get();
+ std::string text;
+ std::getline(ss, text);
+
+ std::cerr << "Sending message to chat " << chat_id << "..." << std::endl;
+ auto send_message = td_api::make_object<td_api::sendMessage>();
+ send_message->chat_id_ = chat_id;
+ auto message_content = td_api::make_object<td_api::inputMessageText>();
+ message_content->text_ = td_api::make_object<td_api::formattedText>();
+ message_content->text_->text_ = std::move(text);
+ send_message->input_message_content_ = std::move(message_content);
+
+ send_query(std::move(send_message), {});
+ } else if (action == "c") {
+ std::cerr << "Loading chat list..." << std::endl;
+ send_query(td_api::make_object<td_api::getChats>(std::numeric_limits<std::int64_t>::max(), 0, 20),
+ [this](Object object) {
+ if (object->get_id() == td_api::error::ID) {
+ return;
+ }
+ auto chats = td::move_tl_object_as<td_api::chats>(object);
+ for (auto chat_id : chats->chat_ids_) {
+ std::cerr << "[id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
+ }
+ });
+ }
+ }
+ }
+ }
+
+ private:
+ using Object = td_api::object_ptr<td_api::Object>;
+ std::unique_ptr<td::Client> client_;
+
+ td_api::object_ptr<td_api::AuthorizationState> authorization_state_;
+ bool are_authorized_{false};
+ bool need_restart_{false};
+ std::uint64_t current_query_id_{0};
+ std::uint64_t authentication_query_id_{0};
+
+ std::map<std::uint64_t, std::function<void(Object)>> handlers_;
+
+ std::map<std::int32_t, td_api::object_ptr<td_api::user>> users_;
+
+ std::map<std::int64_t, std::string> chat_title_;
+
+ void restart() {
+ client_.reset();
+ *this = TdExample();
+ }
+
+ void send_query(td_api::object_ptr<td_api::Function> f, std::function<void(Object)> handler) {
+ auto query_id = next_query_id();
+ if (handler) {
+ handlers_.emplace(query_id, std::move(handler));
+ }
+ client_->send({query_id, std::move(f)});
+ }
+
+ void process_response(td::Client::Response response) {
+ if (!response.object) {
+ return;
+ }
+ //std::cerr << response.id << " " << to_string(response.object) << std::endl;
+ if (response.id == 0) {
+ return process_update(std::move(response.object));
+ }
+ auto it = handlers_.find(response.id);
+ if (it != handlers_.end()) {
+ it->second(std::move(response.object));
+ }
+ }
+
+ std::string get_user_name(std::int32_t user_id) {
+ auto it = users_.find(user_id);
+ if (it == users_.end()) {
+ return "unknown user";
+ }
+ return it->second->first_name_ + " " + it->second->last_name_;
+ }
+
+ void process_update(td_api::object_ptr<td_api::Object> update) {
+ td_api::downcast_call(
+ *update, overloaded(
+ [this](td_api::updateAuthorizationState &update_authorization_state) {
+ authorization_state_ = std::move(update_authorization_state.authorization_state_);
+ on_authorization_state_update();
+ },
+ [this](td_api::updateNewChat &update_new_chat) {
+ chat_title_[update_new_chat.chat_->id_] = update_new_chat.chat_->title_;
+ },
+ [this](td_api::updateChatTitle &update_chat_title) {
+ chat_title_[update_chat_title.chat_id_] = update_chat_title.title_;
+ },
+ [this](td_api::updateUser &update_user) {
+ auto user_id = update_user.user_->id_;
+ users_[user_id] = std::move(update_user.user_);
+ },
+ [this](td_api::updateNewMessage &update_new_message) {
+ auto chat_id = update_new_message.message_->chat_id_;
+ auto sender_user_name = get_user_name(update_new_message.message_->sender_user_id_);
+ std::string text;
+ if (update_new_message.message_->content_->get_id() == td_api::messageText::ID) {
+ text = static_cast<td_api::messageText &>(*update_new_message.message_->content_).text_->text_;
+ }
+ std::cerr << "Got message: [chat_id:" << chat_id << "] [from:" << sender_user_name << "] ["
+ << text << "]" << std::endl;
+ },
+ [](auto &update) {}));
+ }
+
+ auto create_authentication_query_handler() {
+ return [this, id = authentication_query_id_](Object object) {
+ if (id == authentication_query_id_) {
+ check_authentication_error(std::move(object));
+ }
+ };
+ }
+
+ void on_authorization_state_update() {
+ authentication_query_id_++;
+ td_api::downcast_call(
+ *authorization_state_,
+ overloaded(
+ [this](td_api::authorizationStateReady &) {
+ are_authorized_ = true;
+ std::cerr << "Got authorization" << std::endl;
+ },
+ [this](td_api::authorizationStateLoggingOut &) {
+ are_authorized_ = false;
+ std::cerr << "Logging out" << std::endl;
+ },
+ [this](td_api::authorizationStateClosing &) { std::cerr << "Closing" << std::endl; },
+ [this](td_api::authorizationStateClosed &) {
+ are_authorized_ = false;
+ need_restart_ = true;
+ std::cerr << "Terminated" << std::endl;
+ },
+ [this](td_api::authorizationStateWaitCode &wait_code) {
+ std::string first_name;
+ std::string last_name;
+ if (!wait_code.is_registered_) {
+ std::cerr << "Enter your first name: ";
+ std::cin >> first_name;
+ std::cerr << "Enter your last name: ";
+ std::cin >> last_name;
+ }
+ std::cerr << "Enter authentication code: ";
+ std::string code;
+ std::cin >> code;
+ send_query(td_api::make_object<td_api::checkAuthenticationCode>(code, first_name, last_name),
+ create_authentication_query_handler());
+ },
+ [this](td_api::authorizationStateWaitPassword &) {
+ std::cerr << "Enter authentication password: ";
+ std::string password;
+ std::cin >> password;
+ send_query(td_api::make_object<td_api::checkAuthenticationPassword>(password),
+ create_authentication_query_handler());
+ },
+ [this](td_api::authorizationStateWaitPhoneNumber &) {
+ std::cerr << "Enter phone number: ";
+ std::string phone_number;
+ std::cin >> phone_number;
+ send_query(td_api::make_object<td_api::setAuthenticationPhoneNumber>(
+ phone_number, false /*allow_flash_calls*/, false /*is_current_phone_number*/),
+ create_authentication_query_handler());
+ },
+ [this](td_api::authorizationStateWaitEncryptionKey &) {
+ std::cerr << "Enter encryption key or DESTROY: ";
+ std::string key;
+ std::getline(std::cin, key);
+ if (key == "DESTROY") {
+ send_query(td_api::make_object<td_api::destroy>(), create_authentication_query_handler());
+ } else {
+ send_query(td_api::make_object<td_api::checkDatabaseEncryptionKey>(std::move(key)),
+ create_authentication_query_handler());
+ }
+ },
+ [this](td_api::authorizationStateWaitTdlibParameters &) {
+ auto parameters = td_api::make_object<td_api::tdlibParameters>();
+ parameters->database_directory_ = "tdlib";
+ parameters->use_message_database_ = true;
+ parameters->use_secret_chats_ = true;
+ parameters->api_id_ = 94575;
+ parameters->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2";
+ parameters->system_language_code_ = "en";
+ parameters->device_model_ = "Desktop";
+ parameters->system_version_ = "Unknown";
+ parameters->application_version_ = "1.0";
+ parameters->enable_storage_optimizer_ = true;
+ send_query(td_api::make_object<td_api::setTdlibParameters>(std::move(parameters)),
+ create_authentication_query_handler());
+ }));
+ }
+
+ void check_authentication_error(Object object) {
+ if (object->get_id() == td_api::error::ID) {
+ auto error = td::move_tl_object_as<td_api::error>(object);
+ std::cerr << "Error: " << to_string(error);
+ on_authorization_state_update();
+ }
+ }
+
+ std::uint64_t next_query_id() {
+ return ++current_query_id_;
+ }
+};
+
+int main() {
+ TdExample example;
+ example.loop();
+}
diff --git a/protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp b/protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp
new file mode 100644
index 0000000000..6787b37f86
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 <iostream>
+#include <td/telegram/td_json_client.h>
+
+// Basic example of TDLib JSON interface usage.
+// Native interface should be preferred instead in C++, so here is only an example of
+// the main event cycle, which should be essentially the same for all languages.
+
+int main() {
+ void *client = td_json_client_create();
+ // somehow share the client with other threads, which will be able to send requests via td_json_client_send
+
+ const double WAIT_TIMEOUT = 10.0; // seconds
+ while (true) {
+ const char *result = td_json_client_receive(client, WAIT_TIMEOUT);
+ if (result != nullptr) {
+ // parse the result as JSON object and process it as an incoming update or an answer to a previously sent request
+
+ // if (result is UpdateAuthorizationState with authorizationStateClosed) {
+ // break;
+ // }
+
+ std::cout << result << std::endl;
+ }
+ }
+
+ td_json_client_destroy(client);
+}