From 0e824976fc3fada254aea7e7801708e194ae939a Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 13 Nov 2020 21:23:32 +0300 Subject: [PATCH 01/10] Use new JSON interface in Python example. --- example/python/tdjson_example.py | 49 ++++++++++++++------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/example/python/tdjson_example.py b/example/python/tdjson_example.py index 568d8533e..5ca3d75ba 100644 --- a/example/python/tdjson_example.py +++ b/example/python/tdjson_example.py @@ -18,31 +18,27 @@ if tdjson_path is None: tdjson = CDLL(tdjson_path) # load TDLib functions from shared library -td_json_client_create = tdjson.td_json_client_create -td_json_client_create.restype = c_void_p -td_json_client_create.argtypes = [] +_td_create_client = tdjson.td_create_client +_td_create_client.restype = c_int +_td_create_client.argtypes = [] -td_json_client_receive = tdjson.td_json_client_receive -td_json_client_receive.restype = c_char_p -td_json_client_receive.argtypes = [c_void_p, c_double] +_td_receive = tdjson.td_receive +_td_receive.restype = c_char_p +_td_receive.argtypes = [c_double] -td_json_client_send = tdjson.td_json_client_send -td_json_client_send.restype = None -td_json_client_send.argtypes = [c_void_p, c_char_p] +_td_send = tdjson.td_send +_td_send.restype = None +_td_send.argtypes = [c_int, c_char_p] -td_json_client_execute = tdjson.td_json_client_execute -td_json_client_execute.restype = c_char_p -td_json_client_execute.argtypes = [c_void_p, c_char_p] - -td_json_client_destroy = tdjson.td_json_client_destroy -td_json_client_destroy.restype = None -td_json_client_destroy.argtypes = [c_void_p] +_td_execute = tdjson.td_execute +_td_execute.restype = c_char_p +_td_execute.argtypes = [c_char_p] fatal_error_callback_type = CFUNCTYPE(None, c_char_p) -td_set_log_fatal_error_callback = tdjson.td_set_log_fatal_error_callback -td_set_log_fatal_error_callback.restype = None -td_set_log_fatal_error_callback.argtypes = [fatal_error_callback_type] +_td_set_log_fatal_error_callback = tdjson.td_set_log_fatal_error_callback +_td_set_log_fatal_error_callback.restype = None +_td_set_log_fatal_error_callback.argtypes = [fatal_error_callback_type] # initialize TDLib log with desired parameters def on_fatal_error_callback(error_message): @@ -50,28 +46,28 @@ def on_fatal_error_callback(error_message): def td_execute(query): query = json.dumps(query).encode('utf-8') - result = td_json_client_execute(None, query) + result = _td_execute(query) if result: result = json.loads(result.decode('utf-8')) return result c_on_fatal_error_callback = fatal_error_callback_type(on_fatal_error_callback) -td_set_log_fatal_error_callback(c_on_fatal_error_callback) +_td_set_log_fatal_error_callback(c_on_fatal_error_callback) # setting TDLib log verbosity level to 1 (errors) print(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, '@extra': 1.01234})) # create client -client = td_json_client_create() +client_id = _td_create_client() # simple wrappers for client usage def td_send(query): query = json.dumps(query).encode('utf-8') - td_json_client_send(client, query) + _td_send(client_id, query) def td_receive(): - result = td_json_client_receive(client, 1.0) + result = _td_receive(1.0) if result: result = json.loads(result.decode('utf-8')) return result @@ -79,7 +75,7 @@ def td_receive(): # another test for TDLib execute method print(td_execute({'@type': 'getTextEntities', 'text': '@telegram /test_command https://telegram.org telegram.me', '@extra': ['5', 7.0]})) -# testing TDLib send method +# start the client by sending request to it td_send({'@type': 'getAuthorizationState', '@extra': 1.01234}) # main events cycle @@ -137,6 +133,3 @@ while True: # handle an incoming update or an answer to a previously sent request print(event) sys.stdout.flush() - -# destroy client when it is closed and isn't needed anymore -td_json_client_destroy(client) From 583a8f41d61fd232c0584769d320a5d9880a9a41 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 13 Nov 2020 23:49:33 +0300 Subject: [PATCH 02/10] Python example: encode strings to UTF-8 before printing to mitigate possible encoding errors. --- example/python/tdjson_example.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/python/tdjson_example.py b/example/python/tdjson_example.py index 5ca3d75ba..6d1b8d85c 100644 --- a/example/python/tdjson_example.py +++ b/example/python/tdjson_example.py @@ -42,7 +42,7 @@ _td_set_log_fatal_error_callback.argtypes = [fatal_error_callback_type] # initialize TDLib log with desired parameters def on_fatal_error_callback(error_message): - print('TDLib fatal error: ', error_message) + print('TDLib fatal error: ', error_message.encode('utf-8')) def td_execute(query): query = json.dumps(query).encode('utf-8') @@ -55,7 +55,7 @@ c_on_fatal_error_callback = fatal_error_callback_type(on_fatal_error_callback) _td_set_log_fatal_error_callback(c_on_fatal_error_callback) # setting TDLib log verbosity level to 1 (errors) -print(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, '@extra': 1.01234})) +print(str(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, '@extra': 1.01234})).encode('utf-8')) # create client @@ -73,7 +73,7 @@ def td_receive(): return result # another test for TDLib execute method -print(td_execute({'@type': 'getTextEntities', 'text': '@telegram /test_command https://telegram.org telegram.me', '@extra': ['5', 7.0]})) +print(str(td_execute({'@type': 'getTextEntities', 'text': '@telegram /test_command https://telegram.org telegram.me', '@extra': ['5', 7.0, 'รค']})).encode('utf-8')) # start the client by sending request to it td_send({'@type': 'getAuthorizationState', '@extra': 1.01234}) @@ -131,5 +131,5 @@ while True: td_send({'@type': 'checkAuthenticationPassword', 'password': password}) # handle an incoming update or an answer to a previously sent request - print(event) + print(str(event).encode('utf-8')) sys.stdout.flush() From 94fc06c9fcd6093505cd4a237dd5618f2fea562f Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 14 Nov 2020 22:12:48 +0300 Subject: [PATCH 03/10] Install php-cli instead of php on Debian/Ubuntu in build instructions as suggested by @Cavallium. --- build.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.html b/build.html index ae6629c72..3027240a3 100644 --- a/build.html +++ b/build.html @@ -645,9 +645,9 @@ function onOptionsChanged() { commands.push(sudo + 'apt-get upgrade'); var packages = 'make git zlib1g-dev libssl-dev gperf'; if (linux_distro === 'Ubuntu 14' || linux_distro === 'Debian 8') { - packages += ' php5'; + packages += ' php5-cli'; } else { - packages += ' php'; + packages += ' php-cli'; } if (linux_distro === 'Ubuntu 14') { packages += ' cmake3'; From cde8acf23010816f78156a7aaa6a59c88c28fb91 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 14 Nov 2020 22:45:18 +0300 Subject: [PATCH 04/10] Use new JSON interface in Swift example. --- example/swift/src/main.swift | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/example/swift/src/main.swift b/example/swift/src/main.swift index a19b62969..ea29b8fec 100644 --- a/example/swift/src/main.swift +++ b/example/swift/src/main.swift @@ -9,8 +9,7 @@ import Foundation // TDLib Client Swift binding class TdClient { - typealias Client = UnsafeMutableRawPointer - var client = td_json_client_create()! + var client_id = td_create_client()! let tdlibMainLoop = DispatchQueue(label: "TDLib") let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery") var queryF = Dictionary)->()>() @@ -27,7 +26,7 @@ class TdClient { self.queryF[nextQueryId] = f self.queryId = nextQueryId } - td_json_client_send(self.client, to_json(newQuery)) + td_send(self.client_id, to_json(newQuery)) } } @@ -46,7 +45,6 @@ class TdClient { } deinit { - td_json_client_destroy(client) } func run(updateHandler: @escaping (Dictionary)->()) { @@ -54,7 +52,7 @@ class TdClient { tdlibMainLoop.async { [weak self] in while (true) { if let s = self { - if let res = td_json_client_receive(s.client, 10) { + if let res = td_receive(10) { let event = String(cString: res) s.queryResultAsync(event) } @@ -91,11 +89,11 @@ func to_json(_ obj: Any) -> String { } -// An example of usage -td_set_log_verbosity_level(1); - var client = TdClient() +// start the client by sending request to it +client.queryAsync(query: ["@type":"getOption", "name":"version"]) + func myReadLine() -> String { while (true) { if let line = readLine() { @@ -159,7 +157,7 @@ func updateAuthorizationState(authorizationState: Dictionary) { case "authorizationStateClosing": print("Closing...") - case "authorizationStateLoggingOut": + case "authorizationStateClosed": print("Closed.") default: From 66af1a439af79f81b89241787eaf0194ed194bbc Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 14 Nov 2020 22:57:59 +0300 Subject: [PATCH 05/10] Use getOptions as first request. --- example/java/org/drinkless/tdlib/Client.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/java/org/drinkless/tdlib/Client.java b/example/java/org/drinkless/tdlib/Client.java index b923df391..e6a30f33c 100644 --- a/example/java/org/drinkless/tdlib/Client.java +++ b/example/java/org/drinkless/tdlib/Client.java @@ -188,7 +188,7 @@ public final class Client { if (defaultExceptionHandler != null) { defaultExceptionHandlers.put(nativeClientId, defaultExceptionHandler); } - send(new TdApi.GetAuthorizationState(), null, null); + send(new TdApi.GetOption("version"), null, null); } @Override From 6d46662804840b6addfabb5358182b0ccbe9c064 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 14 Nov 2020 22:58:21 +0300 Subject: [PATCH 06/10] Fix documentation misprint. --- td/generate/scheme/td_api.tl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 183bad19f..5d9cce0ed 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4489,7 +4489,7 @@ toggleSupergroupIsAllHistoryAvailable supergroup_id:int32 is_all_history_availab reportSupergroupSpam supergroup_id:int32 user_id:int32 message_ids:vector = Ok; //@description Returns information about members or banned users in a supergroup or channel. Can be used only if SupergroupFullInfo.can_get_members == true; additionally, administrator privileges may be required for some filters @supergroup_id Identifier of the supergroup or channel -//@filter The type of users to return. By default, supergroupMembersRecent @offset Number of users to skip @limit The maximum number of users be returned; up to 200 +//@filter The type of users to return. By default, supergroupMembersFilterRecent @offset Number of users to skip @limit The maximum number of users be returned; up to 200 getSupergroupMembers supergroup_id:int32 filter:SupergroupMembersFilter offset:int32 limit:int32 = ChatMembers; //@description Deletes a supergroup or channel along with all messages in the corresponding chat. This will release the supergroup or channel username and remove all members; requires owner privileges in the supergroup or channel. Chats with more than 1000 members can't be deleted using this method @supergroup_id Identifier of the supergroup or channel From 21f6ddc6fbd355221de9817930b0c30ccac5c4e8 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 15 Nov 2020 00:41:29 +0300 Subject: [PATCH 07/10] Fix fatal error handler in Python example. --- example/python/tdjson_example.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/python/tdjson_example.py b/example/python/tdjson_example.py index 6d1b8d85c..ff1d2dd02 100644 --- a/example/python/tdjson_example.py +++ b/example/python/tdjson_example.py @@ -42,7 +42,8 @@ _td_set_log_fatal_error_callback.argtypes = [fatal_error_callback_type] # initialize TDLib log with desired parameters def on_fatal_error_callback(error_message): - print('TDLib fatal error: ', error_message.encode('utf-8')) + print('TDLib fatal error: ', error_message) + sys.stdout.flush() def td_execute(query): query = json.dumps(query).encode('utf-8') From 5eea5b75010fe6649254faba1ca7a879f93eb8cc Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 15 Nov 2020 01:13:11 +0300 Subject: [PATCH 08/10] Rename create_client to create_client_id. --- benchmark/check_proxy.cpp | 2 +- example/cpp/td_example.cpp | 2 +- example/cpp/tdjson_example.cpp | 2 +- example/java/td_jni.cpp | 2 +- example/python/tdjson_example.py | 8 ++++---- example/swift/src/main.swift | 2 +- example/web/tdweb/src/worker.js | 6 +++--- td/telegram/Client.cpp | 10 +++++----- td/telegram/Client.h | 23 ++++++++++++++--------- td/telegram/ClientJson.cpp | 4 ++-- td/telegram/ClientJson.h | 2 +- td/telegram/td_emscripten.cpp | 4 ++-- td/telegram/td_json_client.cpp | 4 ++-- td/telegram/td_json_client.h | 11 ++++++----- tdclientjson_export_list | 2 +- test/tdclient.cpp | 6 +++--- 16 files changed, 48 insertions(+), 42 deletions(-) diff --git a/benchmark/check_proxy.cpp b/benchmark/check_proxy.cpp index e1ff5523e..7b9a1480d 100644 --- a/benchmark/check_proxy.cpp +++ b/benchmark/check_proxy.cpp @@ -161,7 +161,7 @@ int main(int argc, char **argv) { SET_VERBOSITY_LEVEL(new_verbosity_level); td::ClientManager client_manager; - auto client_id = client_manager.create_client(); + auto client_id = client_manager.create_client_id(); for (size_t i = 0; i < requests.size(); i++) { auto &request = requests[i].second; request->dc_id_ = dc_id; diff --git a/example/cpp/td_example.cpp b/example/cpp/td_example.cpp index 4bb493857..5715501fa 100644 --- a/example/cpp/td_example.cpp +++ b/example/cpp/td_example.cpp @@ -55,7 +55,7 @@ class TdExample { TdExample() { td::ClientManager::execute(td_api::make_object(1)); client_manager_ = std::make_unique(); - client_id_ = client_manager_->create_client(); + client_id_ = client_manager_->create_client_id(); send_query(td_api::make_object("version"), {}); } diff --git a/example/cpp/tdjson_example.cpp b/example/cpp/tdjson_example.cpp index 62978f178..080de9698 100644 --- a/example/cpp/tdjson_example.cpp +++ b/example/cpp/tdjson_example.cpp @@ -15,7 +15,7 @@ int main() { // disable TDLib logging td_execute("{\"@type\":\"setLogVerbosityLevel\", \"new_verbosity_level\":0}"); - int client_id = td_create_client(); + int client_id = td_create_client_id(); // somehow share the client_id with other threads, which will be able to send requests via td_send // start the client by sending request to it diff --git a/example/java/td_jni.cpp b/example/java/td_jni.cpp index e0106e258..61df8b090 100644 --- a/example/java/td_jni.cpp +++ b/example/java/td_jni.cpp @@ -31,7 +31,7 @@ static td::ClientManager *get_manager() { } static jint Client_createNativeClient(JNIEnv *env, jclass clazz) { - return static_cast(get_manager()->create_client()); + return static_cast(get_manager()->create_client_id()); } static void Client_nativeClientSend(JNIEnv *env, jclass clazz, jint client_id, jlong id, jobject function) { diff --git a/example/python/tdjson_example.py b/example/python/tdjson_example.py index ff1d2dd02..e0f46f82c 100644 --- a/example/python/tdjson_example.py +++ b/example/python/tdjson_example.py @@ -18,9 +18,9 @@ if tdjson_path is None: tdjson = CDLL(tdjson_path) # load TDLib functions from shared library -_td_create_client = tdjson.td_create_client -_td_create_client.restype = c_int -_td_create_client.argtypes = [] +_td_create_client_id = tdjson.td_create_client_id +_td_create_client_id.restype = c_int +_td_create_client_id.argtypes = [] _td_receive = tdjson.td_receive _td_receive.restype = c_char_p @@ -60,7 +60,7 @@ print(str(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, # create client -client_id = _td_create_client() +client_id = _td_create_client_id() # simple wrappers for client usage def td_send(query): diff --git a/example/swift/src/main.swift b/example/swift/src/main.swift index ea29b8fec..333301762 100644 --- a/example/swift/src/main.swift +++ b/example/swift/src/main.swift @@ -9,7 +9,7 @@ import Foundation // TDLib Client Swift binding class TdClient { - var client_id = td_create_client()! + var client_id = td_create_client_id()! let tdlibMainLoop = DispatchQueue(label: "TDLib") let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery") var queryF = Dictionary)->()>() diff --git a/example/web/tdweb/src/worker.js b/example/web/tdweb/src/worker.js index ad6c32e0a..363a96e15 100644 --- a/example/web/tdweb/src/worker.js +++ b/example/web/tdweb/src/worker.js @@ -614,7 +614,7 @@ class TdClient { this.TdModule = await loadTdlib(mode, this.onFS, options.wasmUrl); log.info('got TdModule'); this.td_functions = { - td_create: this.TdModule.cwrap('td_emscripten_create', 'number', []), + td_create: this.TdModule.cwrap('td_emscripten_create_client_id', 'number', []), td_send: this.TdModule.cwrap('td_emscripten_send', null, [ 'number', 'string' @@ -679,7 +679,7 @@ class TdClient { options.logVerbosityLevel = 2; } this.td_functions.td_set_verbosity(options.logVerbosityLevel); - this.client = this.td_functions.td_create(); + this.client_id = this.td_functions.td_create(); this.savingFiles = new Map(); this.send({ @@ -842,7 +842,7 @@ class TdClient { return; } query = this.prepareQuery(query); - this.td_functions.td_send(this.client, JSON.stringify(query)); + this.td_functions.td_send(this.client_id, JSON.stringify(query)); this.scheduleReceiveSoon(); } diff --git a/td/telegram/Client.cpp b/td/telegram/Client.cpp index c56fdd82a..3a2058a87 100644 --- a/td/telegram/Client.cpp +++ b/td/telegram/Client.cpp @@ -77,7 +77,7 @@ class TdReceiver { class ClientManager::Impl final { public: - ClientId create_client() { + ClientId create_client_id() { CHECK(client_id_ != std::numeric_limits::max()); auto client_id = ++client_id_; pending_clients_.insert(client_id); @@ -205,7 +205,7 @@ class ClientManager::Impl final { class Client::Impl final { public: - Impl() : client_id_(impl_.create_client()) { + Impl() : client_id_(impl_.create_client_id()) { } void send(Request request) { @@ -455,7 +455,7 @@ class MultiImplPool { class ClientManager::Impl final { public: - ClientId create_client() { + ClientId create_client_id() { auto client_id = MultiImpl::create_id(); { auto lock = impls_mutex_.lock_write().move_as_ok(); @@ -639,8 +639,8 @@ Client &Client::operator=(Client &&other) = default; ClientManager::ClientManager() : impl_(std::make_unique()) { } -ClientManager::ClientId ClientManager::create_client() { - return impl_->create_client(); +ClientManager::ClientId ClientManager::create_client_id() { + return impl_->create_client_id(); } void ClientManager::send(ClientId client_id, RequestId request_id, td_api::object_ptr &&request) { diff --git a/td/telegram/Client.h b/td/telegram/Client.h index ee1e2d755..cbe7f3d25 100644 --- a/td/telegram/Client.h +++ b/td/telegram/Client.h @@ -134,20 +134,24 @@ class Client final { /** * The future native C++ interface for interaction with TDLib. * - * The TDLib client instance is created using the ClientManager::create_client method, returning a client identifier. - * Requests to TDLib can be sent using the ClientManager::send method from any thread. - * New updates and responses to requests can be received using the ClientManager::receive method from any thread, - * this function must not be called simultaneously from two different threads. Also note that all updates and - * responses to requests should be applied in the same order as they were received, to ensure consistency. + * The TDLib client instance is created using the ClientManager::create_client_id method, returning a client identifier. + * Requests to a TDLib client instance can be sent using the ClientManager::send method from any thread. + * New updates and responses to requests can be received using the ClientManager::receive method from any thread + * after a first request is sent to the client instance. ClientManager::receive must not be called simultaneously from + * two different threads. Also note that all updates and responses to requests should be applied in the same order as + * they were received, to ensure consistency. * Some TDLib requests can be executed synchronously from any thread by using the ClientManager::execute method. * * General pattern of usage: * \code * td::ClientManager manager; - * auto client_id = manager.create_client(); + * auto client_id = manager.create_client_id(); * // somehow share the manager and the client_id with other threads, * // which will be able to send requests via manager.send(client_id, ...) * + * // send some dummy requests to the new instance to activate it + * manager.send(client_id, ...); + * * const double WAIT_TIMEOUT = 10.0; // seconds * while (true) { * auto response = manager.receive(WAIT_TIMEOUT); @@ -183,10 +187,11 @@ class ClientManager final { using RequestId = std::uint64_t; /** - * Creates a new TDLib client and returns its opaque identifier. - * The client will not send updates until the first request is sent to it. + * Returns an opaque identifier of a new TDLib instance. + * The TDLib instance will not send updates until the first request is sent to it. + * \return Opaque indentifier of a new TDLib instance. */ - ClientId create_client(); + ClientId create_client_id(); /** * Sends request to TDLib. May be called from any thread. diff --git a/td/telegram/ClientJson.cpp b/td/telegram/ClientJson.cpp index 960b55207..78d34c42a 100644 --- a/td/telegram/ClientJson.cpp +++ b/td/telegram/ClientJson.cpp @@ -125,8 +125,8 @@ static std::mutex extra_mutex; static std::unordered_map extra; static std::atomic extra_id{1}; -int json_create_client() { - return static_cast(get_manager()->create_client()); +int json_create_client_id() { + return static_cast(get_manager()->create_client_id()); } void json_send(int client_id, Slice request) { diff --git a/td/telegram/ClientJson.h b/td/telegram/ClientJson.h index d7bc85125..195fb7078 100644 --- a/td/telegram/ClientJson.h +++ b/td/telegram/ClientJson.h @@ -33,7 +33,7 @@ class ClientJson final { std::atomic extra_id_{1}; }; -int json_create_client(); +int json_create_client_id(); void json_send(int client_id, Slice request); diff --git a/td/telegram/td_emscripten.cpp b/td/telegram/td_emscripten.cpp index 77435bfec..0cedf79e7 100644 --- a/td/telegram/td_emscripten.cpp +++ b/td/telegram/td_emscripten.cpp @@ -13,8 +13,8 @@ extern "C" { -EMSCRIPTEN_KEEPALIVE double td_emscripten_create() { - return td_create_client(); +EMSCRIPTEN_KEEPALIVE double td_emscripten_create_client_id() { + return td_create_client_id(); } EMSCRIPTEN_KEEPALIVE void td_emscripten_send(double client_id, const char *query) { diff --git a/td/telegram/td_json_client.cpp b/td/telegram/td_json_client.cpp index c346a9048..dde62d7a6 100644 --- a/td/telegram/td_json_client.cpp +++ b/td/telegram/td_json_client.cpp @@ -30,8 +30,8 @@ const char *td_json_client_execute(void *client, const char *request) { return td::ClientJson::execute(td::Slice(request == nullptr ? "" : request)); } -int td_create_client() { - return td::json_create_client(); +int td_create_client_id() { + return td::json_create_client_id(); } void td_send(int client_id, const char *request) { diff --git a/td/telegram/td_json_client.h b/td/telegram/td_json_client.h index f98705210..417f92424 100644 --- a/td/telegram/td_json_client.h +++ b/td/telegram/td_json_client.h @@ -102,7 +102,7 @@ TDJSON_EXPORT void td_json_client_destroy(void *client); * Each returned object will have an "@client_id" field, containing and identifier of the client for which * a response or an update is received. * - * A TDLib client instance can be created through td_create_client. + * A TDLib client instance can be created through td_create_client_id. * Requests then can be sent using td_send from any thread and the received client identifier. * New updates and request responses can be received through td_receive from any thread. This function * must not be called simultaneously from two different threads. Also note that all updates and request responses @@ -112,7 +112,7 @@ TDJSON_EXPORT void td_json_client_destroy(void *client); * * General pattern of usage: * \code - * int client_id = td_create_client(); + * int client_id = td_create_client_id(); * // share the client_id with other threads, which will be able to send requests via td_send * * const double WAIT_TIMEOUT = 10.0; // seconds @@ -126,10 +126,11 @@ TDJSON_EXPORT void td_json_client_destroy(void *client); */ /** - * Creates a new instance of TDLib. The TDLib instance will not send updates until the first request is sent to it. - * \return Opaque indentifier of the created TDLib instance. + * Returns an opaque identifier of a new TDLib instance. + * The TDLib instance will not send updates until the first request is sent to it. + * \return Opaque indentifier of a new TDLib instance. */ -TDJSON_EXPORT int td_create_client(); +TDJSON_EXPORT int td_create_client_id(); /** * Sends request to the TDLib client. May be called from any thread. diff --git a/tdclientjson_export_list b/tdclientjson_export_list index 9a1891049..d70976f7d 100644 --- a/tdclientjson_export_list +++ b/tdclientjson_export_list @@ -7,7 +7,7 @@ _td_set_log_file_path _td_set_log_max_file_size _td_set_log_verbosity_level _td_set_log_fatal_error_callback -_td_create_client +_td_create_client_id _td_send _td_receive _td_execute diff --git a/test/tdclient.cpp b/test/tdclient.cpp index 800108b82..1937150ce 100644 --- a/test/tdclient.cpp +++ b/test/tdclient.cpp @@ -942,7 +942,7 @@ TEST(Client, Manager) { for (int i = 0; i < threads_n; i++) { threads.emplace_back([&] { for (int i = 0; i <= clients_n; i++) { - auto id = client.create_client(); + auto id = client.create_client_id(); if (i != 0) { client.send(id, 3, td::make_tl_object(3)); } @@ -1036,7 +1036,7 @@ TEST(Client, ManagerClose) { std::atomic send_count{1}; std::atomic receive_count{0}; td::ClientManager client_manager; - auto client_id = client_manager.create_client(); + auto client_id = client_manager.create_client_id(); std::mutex request_ids_mutex; std::set request_ids; @@ -1141,7 +1141,7 @@ TEST(Client, ManagerCloseOneThread) { receive(); - auto client_id = client_manager.create_client(); + auto client_id = client_manager.create_client_id(); for (td::int32 i = -5; i < 5; i++) { send_request(i, i == client_id ? 0 : (i > 0 && i < client_id ? 500 : 400)); From f693874c509fed92f505dc78a5334855bdc9abc4 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 15 Nov 2020 17:38:10 +0300 Subject: [PATCH 09/10] Improve documentation. --- td/telegram/ClientActor.h | 12 +++++++++--- td/telegram/td_json_client.h | 2 +- td/tl/TlObject.h | 9 ++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/td/telegram/ClientActor.h b/td/telegram/ClientActor.h index 3a6fd5729..73022ba1f 100644 --- a/td/telegram/ClientActor.h +++ b/td/telegram/ClientActor.h @@ -8,10 +8,9 @@ ///\file -#include "td/telegram/TdCallback.h" - #include "td/telegram/td_api.h" #include "td/telegram/td_api.hpp" +#include "td/telegram/TdCallback.h" #include "td/actor/actor.h" @@ -30,9 +29,12 @@ class Td; */ class ClientActor : public Actor { public: + /// Options for ClientActor creation. struct Options { + /// NetQueryStats object for this client. std::shared_ptr net_query_stats; + /// Default constructor. Options() { } }; @@ -40,6 +42,7 @@ class ClientActor : public Actor { /** * Creates a ClientActor using the specified callback. * \param[in] callback Callback for outgoing notifications from TDLib. + * \param[in] options Options to create the TDLib. */ explicit ClientActor(unique_ptr callback, Options options = {}); @@ -53,7 +56,7 @@ class ClientActor : public Actor { /** * Synchronously executes a TDLib request. Only a few requests can be executed synchronously. * May be called from any thread. - * \param[in] request Request to the TDLib. + * \param[in] request Request to the TDLib instance. * \return The request response. */ static td_api::object_ptr execute(td_api::object_ptr request); @@ -80,6 +83,9 @@ class ClientActor : public Actor { ActorOwn td_; }; +/** + * Creates NetQueryStats object, which can be shared between different clients. + */ std::shared_ptr create_net_query_stats(); /** diff --git a/td/telegram/td_json_client.h b/td/telegram/td_json_client.h index 417f92424..6e667536c 100644 --- a/td/telegram/td_json_client.h +++ b/td/telegram/td_json_client.h @@ -13,7 +13,7 @@ * and is able to work with JSON. * * The JSON serialization of TDLib API objects is straightforward: all API objects are represented as JSON objects with - * the same keys as the API object field names. The object type name is stored in the special field '@type' which is + * the same keys as the API object field names. The object type name is stored in the special field "@type" which is * optional in places where type is uniquely determined by the context. * Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of * int64 and string types are stored as String, fields of bytes type are base64 encoded and then stored as String, diff --git a/td/tl/TlObject.h b/td/tl/TlObject.h index 85b540f1b..9e954d0bc 100644 --- a/td/tl/TlObject.h +++ b/td/tl/TlObject.h @@ -87,9 +87,7 @@ class TlObject { virtual ~TlObject() = default; }; -/** - * A smart wrapper to store a pointer to a TL-object. - */ +/// @cond UNDOCUMENTED namespace tl { template @@ -177,6 +175,11 @@ bool operator!=(const unique_ptr &p, std::nullptr_t) { } } // namespace tl +/// @endcond + +/** + * A smart wrapper to store a pointer to a TL-object. + */ template using tl_object_ptr = tl::unique_ptr; From 78e45da6b9014f8efd96cee0ad5701464d911cc7 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 15 Nov 2020 19:57:03 +0300 Subject: [PATCH 10/10] Use array instead of std::vector in the generated C++ classes. --- example/web/tdweb/README.md | 2 +- td/generate/DoxygenTlDocumentationGenerator.php | 13 ++++++++++--- td/generate/tl_writer_cpp.cpp | 4 ++-- td/generate/tl_writer_h.cpp | 3 +++ td/generate/tl_writer_jni_cpp.cpp | 6 +++--- td/generate/tl_writer_jni_h.cpp | 3 +++ td/generate/tl_writer_td.cpp | 4 ++-- td/telegram/td_json_client.h | 2 +- td/tl/TlObject.h | 2 +- 9 files changed, 26 insertions(+), 13 deletions(-) diff --git a/example/web/tdweb/README.md b/example/web/tdweb/README.md index 4d8d545ca..591bc941f 100644 --- a/example/web/tdweb/README.md +++ b/example/web/tdweb/README.md @@ -15,7 +15,7 @@ The JSON representation of TDLib API objects is straightforward: all API objects [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore which shouldn't be used in the JSON interface. The object type name is stored in the special field '@type' which is optional in places where type is uniquely determined by the context. Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of int64 and string types are stored as String, -fields of bytes type are base64 encoded and then stored as String, fields of vector type are stored as Array. +fields of bytes type are base64 encoded and then stored as String, fields of array type are stored as Array. You can also add the field '@extra' to any query to TDLib and the response will contain the field '@extra' with exactly the same value. ## Installation diff --git a/td/generate/DoxygenTlDocumentationGenerator.php b/td/generate/DoxygenTlDocumentationGenerator.php index 99675fb7c..8f727a047 100644 --- a/td/generate/DoxygenTlDocumentationGenerator.php +++ b/td/generate/DoxygenTlDocumentationGenerator.php @@ -27,7 +27,7 @@ class DoxygenTlDocumentationGenerator extends TlDocumentationGenerator if ($type[6] !== '<' || $type[strlen($type) - 1] !== '>') { return ''; } - return 'std::vector<'.$this->getTypeName(substr($type, 7, -1)).'> &&'; + return 'array<'.$this->getTypeName(substr($type, 7, -1)).'> &&'; } if (preg_match('/[^A-Za-z0-9.]/', $type)) { @@ -99,7 +99,7 @@ class DoxygenTlDocumentationGenerator extends TlDocumentationGenerator $this->printError("Wrong vector subtype in $type"); return ''; } - return 'std::vector<'.$this->getTypeName(substr($type, 7, -1)).'>'; + return 'array<'.$this->getTypeName(substr($type, 7, -1)).'>'; } if (preg_match('/[^A-Za-z0-9.]/', $type)) { @@ -202,6 +202,13 @@ EOT * This type is used to store arbitrary sequences of bytes. In JSON interface the bytes are base64-encoded. */ EOT +); + + $this->addDocumentation('using array = std::vector;', <<addDocumentation('using BaseObject', <<(); * auto message_text = td::td_api::make_object("Hello, world!!!", - * std::vector>()); + * td::td_api::array>()); * auto send_message_request = td::td_api::make_object(chat_id, 0, 0, nullptr, nullptr, * td::td_api::make_object(std::move(message_text), false, true)); * \\endcode diff --git a/td/generate/tl_writer_cpp.cpp b/td/generate/tl_writer_cpp.cpp index f9c5029a7..044a228d7 100644 --- a/td/generate/tl_writer_cpp.cpp +++ b/td/generate/tl_writer_cpp.cpp @@ -305,7 +305,7 @@ std::string TD_TL_writer_cpp::get_pretty_class_name(std::string class_name) cons std::string TD_TL_writer_cpp::gen_vector_store(const std::string &field_name, const tl::tl_tree_type *t, const std::vector &vars, int storer_type) const { std::string num = field_name.back() == ']' ? "2" : ""; - return "{ const std::vector<" + gen_type_name(t) + "> &v" + num + " = " + field_name + + return "{ const array<" + gen_type_name(t) + "> &v" + num + " = " + field_name + "; const std::uint32_t multiplicity" + num + " = static_cast(v" + num + ".size()); const auto vector_name" + num + " = \"" + get_pretty_class_name("vector") + "[\" + td::to_string(multiplicity" + num + ")+ \"]\"; s.store_class_begin(\"" + @@ -662,7 +662,7 @@ std::string TD_TL_writer_cpp::gen_constructor_field_init(int field_num, const st } std::string move_begin; std::string move_end; - if ((field_type == "bytes" || field_type.compare(0, 11, "std::vector") == 0 || + if ((field_type == "bytes" || field_type.compare(0, 5, "array") == 0 || field_type.compare(0, 10, "object_ptr") == 0) && !is_default) { move_begin = "std::move("; diff --git a/td/generate/tl_writer_h.cpp b/td/generate/tl_writer_h.cpp index cc3951958..d7e701cbe 100644 --- a/td/generate/tl_writer_h.cpp +++ b/td/generate/tl_writer_h.cpp @@ -68,6 +68,9 @@ std::string TD_TL_writer_h::gen_output_begin() const { bytes_type + ";\n\n" + "template \n" + "using array = std::vector;\n\n" + "using BaseObject = ::td::TlObject;\n\n" "template \n" diff --git a/td/generate/tl_writer_jni_cpp.cpp b/td/generate/tl_writer_jni_cpp.cpp index 645903a65..a0f2137bc 100644 --- a/td/generate/tl_writer_jni_cpp.cpp +++ b/td/generate/tl_writer_jni_cpp.cpp @@ -100,13 +100,13 @@ std::string TD_TL_writer_jni_cpp::gen_vector_fetch(std::string field_name, const std::string template_type; if (vector_type == "string") { template_type = "string"; - } else if (vector_type.compare(0, 11, "std::vector") == 0) { + } else if (vector_type.compare(0, 5, "array") == 0) { const tl::tl_tree_type *child = static_cast(t->children[0]); template_type = gen_type_name(child); if (template_type.compare(0, 10, "object_ptr") == 0) { template_type = gen_main_class_name(child->type); } - template_type = "std::vector<" + template_type + ">"; + template_type = "array<" + template_type + ">"; } else if (vector_type == "bytes") { template_type = "jbyteArray"; } else { @@ -248,7 +248,7 @@ std::string TD_TL_writer_jni_cpp::gen_vector_store(const std::string &field_name assert(false); // TODO } if (vector_type == "int32" || vector_type == "int53" || vector_type == "int64" || vector_type == "double" || - vector_type == "string" || vector_type.compare(0, 11, "std::vector") == 0 || + vector_type == "string" || vector_type.compare(0, 5, "array") == 0 || vector_type.compare(0, 10, "object_ptr") == 0) { return "{ " "auto arr_tmp_ = jni::store_vector(env, " + diff --git a/td/generate/tl_writer_jni_h.cpp b/td/generate/tl_writer_jni_h.cpp index d050edae6..42aa7cd60 100644 --- a/td/generate/tl_writer_jni_h.cpp +++ b/td/generate/tl_writer_jni_h.cpp @@ -91,6 +91,9 @@ std::string TD_TL_writer_jni_h::gen_output_begin() const { bytes_type + ";\n\n" + "template \n" + "using array = std::vector;\n\n" + "class " + gen_base_tl_class_name() + ";\n" diff --git a/td/generate/tl_writer_td.cpp b/td/generate/tl_writer_td.cpp index 1a9cdb431..3d5447c46 100644 --- a/td/generate/tl_writer_td.cpp +++ b/td/generate/tl_writer_td.cpp @@ -200,7 +200,7 @@ std::string TD_TL_writer::gen_type_name(const tl::tl_tree_type *tree_type) const assert(tree_type->children[0]->get_type() == tl::NODE_TYPE_TYPE); const tl::tl_tree_type *child = static_cast(tree_type->children[0]); - return "std::vector<" + gen_type_name(child) + ">"; + return "array<" + gen_type_name(child) + ">"; } assert(!is_built_in_simple_type(name) && !is_built_in_complex_type(name)); @@ -248,7 +248,7 @@ std::string TD_TL_writer::gen_constructor_parameter(int field_num, const std::st } else if (field_type == "UInt128 " || field_type == "UInt256 " || field_type == "string " || (string_type == bytes_type && field_type == "bytes ")) { res += field_type + "const &"; - } else if (field_type.compare(0, 11, "std::vector") == 0 || field_type == "bytes ") { + } else if (field_type.compare(0, 5, "array") == 0 || field_type == "bytes ") { res += field_type + "&&"; } else if (field_type.compare(0, 10, "object_ptr") == 0) { res += field_type + "&&"; diff --git a/td/telegram/td_json_client.h b/td/telegram/td_json_client.h index 6e667536c..a5562dd20 100644 --- a/td/telegram/td_json_client.h +++ b/td/telegram/td_json_client.h @@ -17,7 +17,7 @@ * optional in places where type is uniquely determined by the context. * Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of * int64 and string types are stored as String, fields of bytes type are base64 encoded and then stored as String, - * fields of vector type are stored as Array. + * fields of array type are stored as Array. * The main TDLib interface is asynchronous. To match requests with a corresponding response a field "@extra" can * be added to the request object. The corresponding response will have an "@extra" field with exactly the same value. * diff --git a/td/tl/TlObject.h b/td/tl/TlObject.h index 9e954d0bc..d6a5819aa 100644 --- a/td/tl/TlObject.h +++ b/td/tl/TlObject.h @@ -189,7 +189,7 @@ using tl_object_ptr = tl::unique_ptr; * \code * auto get_authorization_state_request = td::make_tl_object(); * auto message_text = td::make_tl_object("Hello, world!!!", - * std::vector>()); + * td::td_api::array>()); * auto send_message_request = td::make_tl_object(chat_id, 0, 0, nullptr, nullptr, * td::make_tl_object(std::move(message_text), false, true)); * \endcode