Merge commit '78e45da6b9014f8efd96cee0ad5701464d911cc7'

This commit is contained in:
Andrea Cavalli 2020-11-15 18:16:02 +01:00
commit bc0f162ad6
28 changed files with 121 additions and 101 deletions

View File

@ -161,7 +161,7 @@ int main(int argc, char **argv) {
SET_VERBOSITY_LEVEL(new_verbosity_level); SET_VERBOSITY_LEVEL(new_verbosity_level);
td::ClientManager client_manager; 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++) { for (size_t i = 0; i < requests.size(); i++) {
auto &request = requests[i].second; auto &request = requests[i].second;
request->dc_id_ = dc_id; request->dc_id_ = dc_id;

View File

@ -645,9 +645,9 @@ function onOptionsChanged() {
commands.push(sudo + 'apt-get upgrade'); commands.push(sudo + 'apt-get upgrade');
var packages = 'make git zlib1g-dev libssl-dev gperf'; var packages = 'make git zlib1g-dev libssl-dev gperf';
if (linux_distro === 'Ubuntu 14' || linux_distro === 'Debian 8') { if (linux_distro === 'Ubuntu 14' || linux_distro === 'Debian 8') {
packages += ' php5'; packages += ' php5-cli';
} else { } else {
packages += ' php'; packages += ' php-cli';
} }
if (linux_distro === 'Ubuntu 14') { if (linux_distro === 'Ubuntu 14') {
packages += ' cmake3'; packages += ' cmake3';

View File

@ -55,7 +55,7 @@ class TdExample {
TdExample() { TdExample() {
td::ClientManager::execute(td_api::make_object<td_api::setLogVerbosityLevel>(1)); td::ClientManager::execute(td_api::make_object<td_api::setLogVerbosityLevel>(1));
client_manager_ = std::make_unique<td::ClientManager>(); client_manager_ = std::make_unique<td::ClientManager>();
client_id_ = client_manager_->create_client(); client_id_ = client_manager_->create_client_id();
send_query(td_api::make_object<td_api::getOption>("version"), {}); send_query(td_api::make_object<td_api::getOption>("version"), {});
} }

View File

@ -15,7 +15,7 @@ int main() {
// disable TDLib logging // disable TDLib logging
td_execute("{\"@type\":\"setLogVerbosityLevel\", \"new_verbosity_level\":0}"); 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 // 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 // start the client by sending request to it

View File

@ -188,7 +188,7 @@ public final class Client {
if (defaultExceptionHandler != null) { if (defaultExceptionHandler != null) {
defaultExceptionHandlers.put(nativeClientId, defaultExceptionHandler); defaultExceptionHandlers.put(nativeClientId, defaultExceptionHandler);
} }
send(new TdApi.GetAuthorizationState(), null, null); send(new TdApi.GetOption("version"), null, null);
} }
@Override @Override

View File

@ -31,7 +31,7 @@ static td::ClientManager *get_manager() {
} }
static jint Client_createNativeClient(JNIEnv *env, jclass clazz) { static jint Client_createNativeClient(JNIEnv *env, jclass clazz) {
return static_cast<jint>(get_manager()->create_client()); return static_cast<jint>(get_manager()->create_client_id());
} }
static void Client_nativeClientSend(JNIEnv *env, jclass clazz, jint client_id, jlong id, jobject function) { static void Client_nativeClientSend(JNIEnv *env, jclass clazz, jint client_id, jlong id, jobject function) {

View File

@ -18,68 +18,65 @@ if tdjson_path is None:
tdjson = CDLL(tdjson_path) tdjson = CDLL(tdjson_path)
# load TDLib functions from shared library # load TDLib functions from shared library
td_json_client_create = tdjson.td_json_client_create _td_create_client_id = tdjson.td_create_client_id
td_json_client_create.restype = c_void_p _td_create_client_id.restype = c_int
td_json_client_create.argtypes = [] _td_create_client_id.argtypes = []
td_json_client_receive = tdjson.td_json_client_receive _td_receive = tdjson.td_receive
td_json_client_receive.restype = c_char_p _td_receive.restype = c_char_p
td_json_client_receive.argtypes = [c_void_p, c_double] _td_receive.argtypes = [c_double]
td_json_client_send = tdjson.td_json_client_send _td_send = tdjson.td_send
td_json_client_send.restype = None _td_send.restype = None
td_json_client_send.argtypes = [c_void_p, c_char_p] _td_send.argtypes = [c_int, c_char_p]
td_json_client_execute = tdjson.td_json_client_execute _td_execute = tdjson.td_execute
td_json_client_execute.restype = c_char_p _td_execute.restype = c_char_p
td_json_client_execute.argtypes = [c_void_p, c_char_p] _td_execute.argtypes = [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]
fatal_error_callback_type = CFUNCTYPE(None, 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 = tdjson.td_set_log_fatal_error_callback
td_set_log_fatal_error_callback.restype = None _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.argtypes = [fatal_error_callback_type]
# initialize TDLib log with desired parameters # initialize TDLib log with desired parameters
def on_fatal_error_callback(error_message): def on_fatal_error_callback(error_message):
print('TDLib fatal error: ', error_message) print('TDLib fatal error: ', error_message)
sys.stdout.flush()
def td_execute(query): def td_execute(query):
query = json.dumps(query).encode('utf-8') query = json.dumps(query).encode('utf-8')
result = td_json_client_execute(None, query) result = _td_execute(query)
if result: if result:
result = json.loads(result.decode('utf-8')) result = json.loads(result.decode('utf-8'))
return result return result
c_on_fatal_error_callback = fatal_error_callback_type(on_fatal_error_callback) 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) # 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 # create client
client = td_json_client_create() client_id = _td_create_client_id()
# simple wrappers for client usage # simple wrappers for client usage
def td_send(query): def td_send(query):
query = json.dumps(query).encode('utf-8') query = json.dumps(query).encode('utf-8')
td_json_client_send(client, query) _td_send(client_id, query)
def td_receive(): def td_receive():
result = td_json_client_receive(client, 1.0) result = _td_receive(1.0)
if result: if result:
result = json.loads(result.decode('utf-8')) result = json.loads(result.decode('utf-8'))
return result return result
# another test for TDLib execute method # 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'))
# testing TDLib send method # start the client by sending request to it
td_send({'@type': 'getAuthorizationState', '@extra': 1.01234}) td_send({'@type': 'getAuthorizationState', '@extra': 1.01234})
# main events cycle # main events cycle
@ -135,8 +132,5 @@ while True:
td_send({'@type': 'checkAuthenticationPassword', 'password': password}) td_send({'@type': 'checkAuthenticationPassword', 'password': password})
# handle an incoming update or an answer to a previously sent request # handle an incoming update or an answer to a previously sent request
print(event) print(str(event).encode('utf-8'))
sys.stdout.flush() sys.stdout.flush()
# destroy client when it is closed and isn't needed anymore
td_json_client_destroy(client)

View File

@ -9,8 +9,7 @@ import Foundation
// TDLib Client Swift binding // TDLib Client Swift binding
class TdClient { class TdClient {
typealias Client = UnsafeMutableRawPointer var client_id = td_create_client_id()!
var client = td_json_client_create()!
let tdlibMainLoop = DispatchQueue(label: "TDLib") let tdlibMainLoop = DispatchQueue(label: "TDLib")
let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery") let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery")
var queryF = Dictionary<Int64, (Dictionary<String,Any>)->()>() var queryF = Dictionary<Int64, (Dictionary<String,Any>)->()>()
@ -27,7 +26,7 @@ class TdClient {
self.queryF[nextQueryId] = f self.queryF[nextQueryId] = f
self.queryId = nextQueryId 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 { deinit {
td_json_client_destroy(client)
} }
func run(updateHandler: @escaping (Dictionary<String,Any>)->()) { func run(updateHandler: @escaping (Dictionary<String,Any>)->()) {
@ -54,7 +52,7 @@ class TdClient {
tdlibMainLoop.async { [weak self] in tdlibMainLoop.async { [weak self] in
while (true) { while (true) {
if let s = self { 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) let event = String(cString: res)
s.queryResultAsync(event) 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() var client = TdClient()
// start the client by sending request to it
client.queryAsync(query: ["@type":"getOption", "name":"version"])
func myReadLine() -> String { func myReadLine() -> String {
while (true) { while (true) {
if let line = readLine() { if let line = readLine() {
@ -159,7 +157,7 @@ func updateAuthorizationState(authorizationState: Dictionary<String, Any>) {
case "authorizationStateClosing": case "authorizationStateClosing":
print("Closing...") print("Closing...")
case "authorizationStateLoggingOut": case "authorizationStateClosed":
print("Closed.") print("Closed.")
default: default:

View File

@ -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 [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. 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 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. 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 ## Installation

View File

@ -614,7 +614,7 @@ class TdClient {
this.TdModule = await loadTdlib(mode, this.onFS, options.wasmUrl); this.TdModule = await loadTdlib(mode, this.onFS, options.wasmUrl);
log.info('got TdModule'); log.info('got TdModule');
this.td_functions = { 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, [ td_send: this.TdModule.cwrap('td_emscripten_send', null, [
'number', 'number',
'string' 'string'
@ -679,7 +679,7 @@ class TdClient {
options.logVerbosityLevel = 2; options.logVerbosityLevel = 2;
} }
this.td_functions.td_set_verbosity(options.logVerbosityLevel); 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.savingFiles = new Map();
this.send({ this.send({
@ -842,7 +842,7 @@ class TdClient {
return; return;
} }
query = this.prepareQuery(query); 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(); this.scheduleReceiveSoon();
} }

View File

@ -27,7 +27,7 @@ class DoxygenTlDocumentationGenerator extends TlDocumentationGenerator
if ($type[6] !== '<' || $type[strlen($type) - 1] !== '>') { if ($type[6] !== '<' || $type[strlen($type) - 1] !== '>') {
return ''; 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)) { if (preg_match('/[^A-Za-z0-9.]/', $type)) {
@ -99,7 +99,7 @@ class DoxygenTlDocumentationGenerator extends TlDocumentationGenerator
$this->printError("Wrong vector subtype in $type"); $this->printError("Wrong vector subtype in $type");
return ''; 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)) { 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. * This type is used to store arbitrary sequences of bytes. In JSON interface the bytes are base64-encoded.
*/ */
EOT EOT
);
$this->addDocumentation('using array = std::vector<Type>;', <<<EOT
/**
* This type is used to store a list of objects of any type and is represented as Array in JSON.
*/
EOT
); );
$this->addDocumentation('using BaseObject', <<<EOT $this->addDocumentation('using BaseObject', <<<EOT
@ -225,7 +232,7 @@ EOT
* \\code * \\code
* auto get_authorization_state_request = td::td_api::make_object<td::td_api::getAuthorizationState>(); * auto get_authorization_state_request = td::td_api::make_object<td::td_api::getAuthorizationState>();
* auto message_text = td::td_api::make_object<td::td_api::formattedText>("Hello, world!!!", * auto message_text = td::td_api::make_object<td::td_api::formattedText>("Hello, world!!!",
* std::vector<td::td_api::object_ptr<td::td_api::textEntity>>()); * td::td_api::array<td::td_api::object_ptr<td::td_api::textEntity>>());
* auto send_message_request = td::td_api::make_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr, * auto send_message_request = td::td_api::make_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr,
* td::td_api::make_object<td::td_api::inputMessageText>(std::move(message_text), false, true)); * td::td_api::make_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
* \\endcode * \\endcode

View File

@ -4493,7 +4493,7 @@ toggleSupergroupIsAllHistoryAvailable supergroup_id:int32 is_all_history_availab
reportSupergroupSpam supergroup_id:int32 user_id:int32 message_ids:vector<int53> = Ok; reportSupergroupSpam supergroup_id:int32 user_id:int32 message_ids:vector<int53> = 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 //@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; 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 //@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

View File

@ -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, std::string TD_TL_writer_cpp::gen_vector_store(const std::string &field_name, const tl::tl_tree_type *t,
const std::vector<tl::var_description> &vars, int storer_type) const { const std::vector<tl::var_description> &vars, int storer_type) const {
std::string num = field_name.back() == ']' ? "2" : ""; 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<std::uint32_t>(v" + num + "; const std::uint32_t multiplicity" + num + " = static_cast<std::uint32_t>(v" + num +
".size()); const auto vector_name" + num + " = \"" + get_pretty_class_name("vector") + ".size()); const auto vector_name" + num + " = \"" + get_pretty_class_name("vector") +
"[\" + td::to_string(multiplicity" + num + ")+ \"]\"; s.store_class_begin(\"" + "[\" + 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_begin;
std::string move_end; 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) && field_type.compare(0, 10, "object_ptr") == 0) &&
!is_default) { !is_default) {
move_begin = "std::move("; move_begin = "std::move(";

View File

@ -68,6 +68,9 @@ std::string TD_TL_writer_h::gen_output_begin() const {
bytes_type + bytes_type +
";\n\n" ";\n\n"
"template <class Type>\n"
"using array = std::vector<Type>;\n\n"
"using BaseObject = ::td::TlObject;\n\n" "using BaseObject = ::td::TlObject;\n\n"
"template <class Type>\n" "template <class Type>\n"

View File

@ -100,13 +100,13 @@ std::string TD_TL_writer_jni_cpp::gen_vector_fetch(std::string field_name, const
std::string template_type; std::string template_type;
if (vector_type == "string") { if (vector_type == "string") {
template_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<const tl::tl_tree_type *>(t->children[0]); const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(t->children[0]);
template_type = gen_type_name(child); template_type = gen_type_name(child);
if (template_type.compare(0, 10, "object_ptr") == 0) { if (template_type.compare(0, 10, "object_ptr") == 0) {
template_type = gen_main_class_name(child->type); template_type = gen_main_class_name(child->type);
} }
template_type = "std::vector<" + template_type + ">"; template_type = "array<" + template_type + ">";
} else if (vector_type == "bytes") { } else if (vector_type == "bytes") {
template_type = "jbyteArray"; template_type = "jbyteArray";
} else { } else {
@ -248,7 +248,7 @@ std::string TD_TL_writer_jni_cpp::gen_vector_store(const std::string &field_name
assert(false); // TODO assert(false); // TODO
} }
if (vector_type == "int32" || vector_type == "int53" || vector_type == "int64" || vector_type == "double" || 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) { vector_type.compare(0, 10, "object_ptr") == 0) {
return "{ " return "{ "
"auto arr_tmp_ = jni::store_vector(env, " + "auto arr_tmp_ = jni::store_vector(env, " +

View File

@ -91,6 +91,9 @@ std::string TD_TL_writer_jni_h::gen_output_begin() const {
bytes_type + bytes_type +
";\n\n" ";\n\n"
"template <class Type>\n"
"using array = std::vector<Type>;\n\n"
"class " + "class " +
gen_base_tl_class_name() + gen_base_tl_class_name() +
";\n" ";\n"

View File

@ -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); assert(tree_type->children[0]->get_type() == tl::NODE_TYPE_TYPE);
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(tree_type->children[0]); const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(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)); 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 " || } else if (field_type == "UInt128 " || field_type == "UInt256 " || field_type == "string " ||
(string_type == bytes_type && field_type == "bytes ")) { (string_type == bytes_type && field_type == "bytes ")) {
res += field_type + "const &"; 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 + "&&"; res += field_type + "&&";
} else if (field_type.compare(0, 10, "object_ptr") == 0) { } else if (field_type.compare(0, 10, "object_ptr") == 0) {
res += field_type + "&&"; res += field_type + "&&";

View File

@ -78,7 +78,7 @@ class TdReceiver {
class ClientManager::Impl final { class ClientManager::Impl final {
public: public:
ClientId create_client() { ClientId create_client_id() {
CHECK(client_id_ != std::numeric_limits<ClientId>::max()); CHECK(client_id_ != std::numeric_limits<ClientId>::max());
auto client_id = ++client_id_; auto client_id = ++client_id_;
pending_clients_.insert(client_id); pending_clients_.insert(client_id);
@ -206,7 +206,7 @@ class ClientManager::Impl final {
class Client::Impl final { class Client::Impl final {
public: public:
Impl() : client_id_(impl_.create_client()) { Impl() : client_id_(impl_.create_client_id()) {
} }
void send(Request request) { void send(Request request) {
@ -456,7 +456,7 @@ class MultiImplPool {
class ClientManager::Impl final { class ClientManager::Impl final {
public: public:
ClientId create_client() { ClientId create_client_id() {
auto client_id = MultiImpl::create_id(); auto client_id = MultiImpl::create_id();
{ {
auto lock = impls_mutex_.lock_write().move_as_ok(); auto lock = impls_mutex_.lock_write().move_as_ok();
@ -640,8 +640,8 @@ Client &Client::operator=(Client &&other) = default;
ClientManager::ClientManager() : impl_(std::make_unique<Impl>()) { ClientManager::ClientManager() : impl_(std::make_unique<Impl>()) {
} }
ClientManager::ClientId ClientManager::create_client() { ClientManager::ClientId ClientManager::create_client_id() {
return impl_->create_client(); return impl_->create_client_id();
} }
void ClientManager::send(ClientId client_id, RequestId request_id, td_api::object_ptr<td_api::Function> &&request) { void ClientManager::send(ClientId client_id, RequestId request_id, td_api::object_ptr<td_api::Function> &&request) {

View File

@ -134,20 +134,24 @@ class Client final {
/** /**
* The future native C++ interface for interaction with TDLib. * 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. * The TDLib client instance is created using the ClientManager::create_client_id method, returning a client identifier.
* Requests to TDLib can be sent using the ClientManager::send method from any thread. * 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, * 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 * after a first request is sent to the client instance. ClientManager::receive must not be called simultaneously from
* responses to requests should be applied in the same order as they were received, to ensure consistency. * 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. * Some TDLib requests can be executed synchronously from any thread by using the ClientManager::execute method.
* *
* General pattern of usage: * General pattern of usage:
* \code * \code
* td::ClientManager manager; * 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, * // somehow share the manager and the client_id with other threads,
* // which will be able to send requests via manager.send(client_id, ...) * // 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 * const double WAIT_TIMEOUT = 10.0; // seconds
* while (true) { * while (true) {
* auto response = manager.receive(WAIT_TIMEOUT); * auto response = manager.receive(WAIT_TIMEOUT);
@ -183,10 +187,11 @@ class ClientManager final {
using RequestId = std::uint64_t; using RequestId = std::uint64_t;
/** /**
* Creates a new TDLib client and returns its opaque identifier. * Returns an opaque identifier of a new TDLib instance.
* The client will not send updates until the first request is sent to it. * 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. * Sends request to TDLib. May be called from any thread.

View File

@ -8,10 +8,9 @@
///\file ///\file
#include "td/telegram/TdCallback.h"
#include "td/telegram/td_api.h" #include "td/telegram/td_api.h"
#include "td/telegram/td_api.hpp" #include "td/telegram/td_api.hpp"
#include "td/telegram/TdCallback.h"
#include "td/actor/actor.h" #include "td/actor/actor.h"
@ -30,9 +29,12 @@ class Td;
*/ */
class ClientActor : public Actor { class ClientActor : public Actor {
public: public:
/// Options for ClientActor creation.
struct Options { struct Options {
/// NetQueryStats object for this client.
std::shared_ptr<NetQueryStats> net_query_stats; std::shared_ptr<NetQueryStats> net_query_stats;
/// Default constructor.
Options() { Options() {
} }
}; };
@ -40,6 +42,7 @@ class ClientActor : public Actor {
/** /**
* Creates a ClientActor using the specified callback. * Creates a ClientActor using the specified callback.
* \param[in] callback Callback for outgoing notifications from TDLib. * \param[in] callback Callback for outgoing notifications from TDLib.
* \param[in] options Options to create the TDLib.
*/ */
explicit ClientActor(unique_ptr<TdCallback> callback, Options options = {}); explicit ClientActor(unique_ptr<TdCallback> callback, Options options = {});
@ -53,7 +56,7 @@ class ClientActor : public Actor {
/** /**
* Synchronously executes a TDLib request. Only a few requests can be executed synchronously. * Synchronously executes a TDLib request. Only a few requests can be executed synchronously.
* May be called from any thread. * 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. * \return The request response.
*/ */
static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> request); static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> request);
@ -80,6 +83,9 @@ class ClientActor : public Actor {
ActorOwn<Td> td_; ActorOwn<Td> td_;
}; };
/**
* Creates NetQueryStats object, which can be shared between different clients.
*/
std::shared_ptr<NetQueryStats> create_net_query_stats(); std::shared_ptr<NetQueryStats> create_net_query_stats();
/** /**

View File

@ -125,8 +125,8 @@ static std::mutex extra_mutex;
static std::unordered_map<int64, string> extra; static std::unordered_map<int64, string> extra;
static std::atomic<uint64> extra_id{1}; static std::atomic<uint64> extra_id{1};
int json_create_client() { int json_create_client_id() {
return static_cast<int>(get_manager()->create_client()); return static_cast<int>(get_manager()->create_client_id());
} }
void json_send(int client_id, Slice request) { void json_send(int client_id, Slice request) {

View File

@ -33,7 +33,7 @@ class ClientJson final {
std::atomic<std::uint64_t> extra_id_{1}; std::atomic<std::uint64_t> extra_id_{1};
}; };
int json_create_client(); int json_create_client_id();
void json_send(int client_id, Slice request); void json_send(int client_id, Slice request);

View File

@ -13,8 +13,8 @@
extern "C" { extern "C" {
EMSCRIPTEN_KEEPALIVE double td_emscripten_create() { EMSCRIPTEN_KEEPALIVE double td_emscripten_create_client_id() {
return td_create_client(); return td_create_client_id();
} }
EMSCRIPTEN_KEEPALIVE void td_emscripten_send(double client_id, const char *query) { EMSCRIPTEN_KEEPALIVE void td_emscripten_send(double client_id, const char *query) {

View File

@ -30,8 +30,8 @@ const char *td_json_client_execute(void *client, const char *request) {
return td::ClientJson::execute(td::Slice(request == nullptr ? "" : request)); return td::ClientJson::execute(td::Slice(request == nullptr ? "" : request));
} }
int td_create_client() { int td_create_client_id() {
return td::json_create_client(); return td::json_create_client_id();
} }
void td_send(int client_id, const char *request) { void td_send(int client_id, const char *request) {

View File

@ -13,11 +13,11 @@
* and is able to work with JSON. * 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 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. * 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 * 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, * 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 * 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. * be added to the request object. The corresponding response will have an "@extra" field with exactly the same value.
* *
@ -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 * 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 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. * 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 * 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 * 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: * General pattern of usage:
* \code * \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 * // share the client_id with other threads, which will be able to send requests via td_send
* *
* const double WAIT_TIMEOUT = 10.0; // seconds * 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. * Returns an opaque identifier of a new TDLib instance.
* \return Opaque indentifier of the created 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. * Sends request to the TDLib client. May be called from any thread.

View File

@ -87,9 +87,7 @@ class TlObject {
virtual ~TlObject() = default; virtual ~TlObject() = default;
}; };
/** /// @cond UNDOCUMENTED
* A smart wrapper to store a pointer to a TL-object.
*/
namespace tl { namespace tl {
template <class T> template <class T>
@ -177,6 +175,11 @@ bool operator!=(const unique_ptr<T> &p, std::nullptr_t) {
} }
} // namespace tl } // namespace tl
/// @endcond
/**
* A smart wrapper to store a pointer to a TL-object.
*/
template <class Type> template <class Type>
using tl_object_ptr = tl::unique_ptr<Type>; using tl_object_ptr = tl::unique_ptr<Type>;
@ -186,7 +189,7 @@ using tl_object_ptr = tl::unique_ptr<Type>;
* \code * \code
* auto get_authorization_state_request = td::make_tl_object<td::td_api::getAuthorizationState>(); * auto get_authorization_state_request = td::make_tl_object<td::td_api::getAuthorizationState>();
* auto message_text = td::make_tl_object<td::td_api::formattedText>("Hello, world!!!", * auto message_text = td::make_tl_object<td::td_api::formattedText>("Hello, world!!!",
* std::vector<td::tl_object_ptr<td::td_api::textEntity>>()); * td::td_api::array<td::tl_object_ptr<td::td_api::textEntity>>());
* auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr, * auto send_message_request = td::make_tl_object<td::td_api::sendMessage>(chat_id, 0, 0, nullptr, nullptr,
* td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), false, true)); * td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
* \endcode * \endcode

View File

@ -7,7 +7,7 @@ _td_set_log_file_path
_td_set_log_max_file_size _td_set_log_max_file_size
_td_set_log_verbosity_level _td_set_log_verbosity_level
_td_set_log_fatal_error_callback _td_set_log_fatal_error_callback
_td_create_client _td_create_client_id
_td_send _td_send
_td_receive _td_receive
_td_execute _td_execute

View File

@ -942,7 +942,7 @@ TEST(Client, Manager) {
for (int i = 0; i < threads_n; i++) { for (int i = 0; i < threads_n; i++) {
threads.emplace_back([&] { threads.emplace_back([&] {
for (int i = 0; i <= clients_n; i++) { for (int i = 0; i <= clients_n; i++) {
auto id = client.create_client(); auto id = client.create_client_id();
if (i != 0) { if (i != 0) {
client.send(id, 3, td::make_tl_object<td::td_api::testSquareInt>(3)); client.send(id, 3, td::make_tl_object<td::td_api::testSquareInt>(3));
} }
@ -1036,7 +1036,7 @@ TEST(Client, ManagerClose) {
std::atomic<td::int64> send_count{1}; std::atomic<td::int64> send_count{1};
std::atomic<td::int64> receive_count{0}; std::atomic<td::int64> receive_count{0};
td::ClientManager client_manager; 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::mutex request_ids_mutex;
std::set<td::uint64> request_ids; std::set<td::uint64> request_ids;
@ -1141,7 +1141,7 @@ TEST(Client, ManagerCloseOneThread) {
receive(); receive();
auto client_id = client_manager.create_client(); auto client_id = client_manager.create_client_id();
for (td::int32 i = -5; i < 5; i++) { for (td::int32 i = -5; i < 5; i++) {
send_request(i, i == client_id ? 0 : (i > 0 && i < client_id ? 500 : 400)); send_request(i, i == client_id ? 0 : (i > 0 && i < client_id ? 500 : 400));