Merge commit '78e45da6b9014f8efd96cee0ad5701464d911cc7'
This commit is contained in:
commit
bc0f162ad6
@ -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;
|
||||
|
@ -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';
|
||||
|
@ -55,7 +55,7 @@ class TdExample {
|
||||
TdExample() {
|
||||
td::ClientManager::execute(td_api::make_object<td_api::setLogVerbosityLevel>(1));
|
||||
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"), {});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -31,7 +31,7 @@ static td::ClientManager *get_manager() {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -18,68 +18,65 @@ 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_id = tdjson.td_create_client_id
|
||||
_td_create_client_id.restype = c_int
|
||||
_td_create_client_id.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):
|
||||
print('TDLib fatal error: ', error_message)
|
||||
sys.stdout.flush()
|
||||
|
||||
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}))
|
||||
print(str(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, '@extra': 1.01234})).encode('utf-8'))
|
||||
|
||||
|
||||
# create client
|
||||
client = td_json_client_create()
|
||||
client_id = _td_create_client_id()
|
||||
|
||||
# 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
|
||||
|
||||
# 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})
|
||||
|
||||
# main events cycle
|
||||
@ -135,8 +132,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()
|
||||
|
||||
# destroy client when it is closed and isn't needed anymore
|
||||
td_json_client_destroy(client)
|
||||
|
@ -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_id()!
|
||||
let tdlibMainLoop = DispatchQueue(label: "TDLib")
|
||||
let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery")
|
||||
var queryF = Dictionary<Int64, (Dictionary<String,Any>)->()>()
|
||||
@ -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<String,Any>)->()) {
|
||||
@ -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<String, Any>) {
|
||||
case "authorizationStateClosing":
|
||||
print("Closing...")
|
||||
|
||||
case "authorizationStateLoggingOut":
|
||||
case "authorizationStateClosed":
|
||||
print("Closed.")
|
||||
|
||||
default:
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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<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
|
||||
@ -225,7 +232,7 @@ EOT
|
||||
* \\code
|
||||
* 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!!!",
|
||||
* 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,
|
||||
* td::td_api::make_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
|
||||
* \\endcode
|
||||
|
@ -4493,7 +4493,7 @@ toggleSupergroupIsAllHistoryAvailable supergroup_id:int32 is_all_history_availab
|
||||
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
|
||||
//@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
|
||||
|
@ -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<tl::var_description> &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<std::uint32_t>(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(";
|
||||
|
@ -68,6 +68,9 @@ std::string TD_TL_writer_h::gen_output_begin() const {
|
||||
bytes_type +
|
||||
";\n\n"
|
||||
|
||||
"template <class Type>\n"
|
||||
"using array = std::vector<Type>;\n\n"
|
||||
|
||||
"using BaseObject = ::td::TlObject;\n\n"
|
||||
|
||||
"template <class Type>\n"
|
||||
|
@ -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<const tl::tl_tree_type *>(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, " +
|
||||
|
@ -91,6 +91,9 @@ std::string TD_TL_writer_jni_h::gen_output_begin() const {
|
||||
bytes_type +
|
||||
";\n\n"
|
||||
|
||||
"template <class Type>\n"
|
||||
"using array = std::vector<Type>;\n\n"
|
||||
|
||||
"class " +
|
||||
gen_base_tl_class_name() +
|
||||
";\n"
|
||||
|
@ -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<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));
|
||||
@ -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 + "&&";
|
||||
|
@ -78,7 +78,7 @@ class TdReceiver {
|
||||
|
||||
class ClientManager::Impl final {
|
||||
public:
|
||||
ClientId create_client() {
|
||||
ClientId create_client_id() {
|
||||
CHECK(client_id_ != std::numeric_limits<ClientId>::max());
|
||||
auto client_id = ++client_id_;
|
||||
pending_clients_.insert(client_id);
|
||||
@ -206,7 +206,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) {
|
||||
@ -456,7 +456,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();
|
||||
@ -640,8 +640,8 @@ Client &Client::operator=(Client &&other) = default;
|
||||
ClientManager::ClientManager() : impl_(std::make_unique<Impl>()) {
|
||||
}
|
||||
|
||||
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<td_api::Function> &&request) {
|
||||
|
@ -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.
|
||||
|
@ -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<NetQueryStats> 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<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.
|
||||
* 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<td_api::Object> execute(td_api::object_ptr<td_api::Function> request);
|
||||
@ -80,6 +83,9 @@ class ClientActor : public Actor {
|
||||
ActorOwn<Td> td_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates NetQueryStats object, which can be shared between different clients.
|
||||
*/
|
||||
std::shared_ptr<NetQueryStats> create_net_query_stats();
|
||||
|
||||
/**
|
||||
|
@ -125,8 +125,8 @@ static std::mutex extra_mutex;
|
||||
static std::unordered_map<int64, string> extra;
|
||||
static std::atomic<uint64> extra_id{1};
|
||||
|
||||
int json_create_client() {
|
||||
return static_cast<int>(get_manager()->create_client());
|
||||
int json_create_client_id() {
|
||||
return static_cast<int>(get_manager()->create_client_id());
|
||||
}
|
||||
|
||||
void json_send(int client_id, Slice request) {
|
||||
|
@ -33,7 +33,7 @@ class ClientJson final {
|
||||
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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -13,11 +13,11 @@
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
@ -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.
|
||||
|
@ -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 <class T>
|
||||
@ -177,6 +175,11 @@ bool operator!=(const unique_ptr<T> &p, std::nullptr_t) {
|
||||
}
|
||||
|
||||
} // namespace tl
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* A smart wrapper to store a pointer to a TL-object.
|
||||
*/
|
||||
template <class Type>
|
||||
using tl_object_ptr = tl::unique_ptr<Type>;
|
||||
|
||||
@ -186,7 +189,7 @@ using tl_object_ptr = tl::unique_ptr<Type>;
|
||||
* \code
|
||||
* 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!!!",
|
||||
* 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,
|
||||
* td::make_tl_object<td::td_api::inputMessageText>(std::move(message_text), false, true));
|
||||
* \endcode
|
||||
|
@ -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
|
||||
|
@ -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<td::td_api::testSquareInt>(3));
|
||||
}
|
||||
@ -1036,7 +1036,7 @@ TEST(Client, ManagerClose) {
|
||||
std::atomic<td::int64> send_count{1};
|
||||
std::atomic<td::int64> 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<td::uint64> 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));
|
||||
|
Loading…
Reference in New Issue
Block a user