2018-12-31 20:04:05 +01:00
|
|
|
//
|
2021-01-01 13:57:46 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
///\file
|
|
|
|
|
|
|
|
#include "td/telegram/td_api.h"
|
|
|
|
#include "td/telegram/td_api.hpp"
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Native C++ interface for interaction with TDLib.
|
|
|
|
*
|
|
|
|
* The TDLib instance is created for the lifetime of the Client object.
|
|
|
|
* Requests to TDLib can be sent using the Client::send method from any thread.
|
|
|
|
* New updates and responses to requests can be received using the Client::receive method from any thread,
|
2020-10-05 13:32:23 +02:00
|
|
|
* this function must not be called simultaneously from two different threads. Also note that all updates and
|
2018-12-31 20:04:05 +01:00
|
|
|
* responses to requests should be applied in the same order as they were received, to ensure consistency.
|
|
|
|
* Given this information, it's advisable to call this function from a dedicated thread.
|
2020-11-18 21:42:26 +01:00
|
|
|
* Some service TDLib requests can be executed synchronously from any thread using the Client::execute method.
|
2018-12-31 20:04:05 +01:00
|
|
|
*
|
|
|
|
* General pattern of usage:
|
|
|
|
* \code
|
|
|
|
* std::shared_ptr<td::Client> client = std::make_shared<td::Client>();
|
|
|
|
* // somehow share the client with other threads, which will be able to send requests via client->send
|
|
|
|
*
|
|
|
|
* const double WAIT_TIMEOUT = 10.0; // seconds
|
|
|
|
* bool is_closed = false; // should be set to true, when updateAuthorizationState with
|
|
|
|
* // authorizationStateClosed is received
|
|
|
|
* while (!is_closed) {
|
|
|
|
* auto response = client->receive(WAIT_TIMEOUT);
|
|
|
|
* if (response.object == nullptr) {
|
|
|
|
* continue;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* if (response.id == 0) {
|
|
|
|
* // process response.object as an incoming update of type td_api::Update
|
|
|
|
* } else {
|
|
|
|
* // process response.object as an answer to a sent request with id response.id
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* \endcode
|
|
|
|
*/
|
|
|
|
class Client final {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Creates a new TDLib client.
|
|
|
|
*/
|
|
|
|
Client();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A request to the TDLib.
|
|
|
|
*/
|
|
|
|
struct Request {
|
|
|
|
/**
|
|
|
|
* Request identifier.
|
|
|
|
* Responses to TDLib requests will have the same id as the corresponding request.
|
|
|
|
* Updates from TDLib will have id == 0, incoming requests are thus disallowed to have id == 0.
|
|
|
|
*/
|
|
|
|
std::uint64_t id;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TDLib API function representing a request to TDLib.
|
|
|
|
*/
|
|
|
|
td_api::object_ptr<td_api::Function> function;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends request to TDLib. May be called from any thread.
|
|
|
|
* \param[in] request Request to TDLib.
|
|
|
|
*/
|
2018-03-11 21:49:38 +01:00
|
|
|
void send(Request &&request);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A response to a request, or an incoming update from TDLib.
|
|
|
|
*/
|
|
|
|
struct Response {
|
|
|
|
/**
|
2020-10-05 13:32:23 +02:00
|
|
|
* TDLib request identifier, which corresponds to the response, or 0 for incoming updates from TDLib.
|
2018-12-31 20:04:05 +01:00
|
|
|
*/
|
|
|
|
std::uint64_t id;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TDLib API object representing a response to a TDLib request or an incoming update.
|
|
|
|
*/
|
|
|
|
td_api::object_ptr<td_api::Object> object;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receives incoming updates and request responses from TDLib. May be called from any thread, but shouldn't be
|
|
|
|
* called simultaneously from two different threads.
|
2020-01-06 19:44:09 +01:00
|
|
|
* \param[in] timeout The maximum number of seconds allowed for this function to wait for new data.
|
2018-12-31 20:04:05 +01:00
|
|
|
* \return An incoming update or request response. The object returned in the response may be a nullptr
|
|
|
|
* if the timeout expires.
|
|
|
|
*/
|
|
|
|
Response receive(double timeout);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Synchronously executes TDLib requests. Only a few requests can be executed synchronously.
|
|
|
|
* May be called from any thread.
|
|
|
|
* \param[in] request Request to the TDLib.
|
|
|
|
* \return The request response.
|
|
|
|
*/
|
2018-03-11 21:49:38 +01:00
|
|
|
static Response execute(Request &&request);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroys the client and TDLib instance.
|
|
|
|
*/
|
|
|
|
~Client();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Move constructor.
|
|
|
|
*/
|
|
|
|
Client(Client &&other);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Move assignment operator.
|
|
|
|
*/
|
|
|
|
Client &operator=(Client &&other);
|
|
|
|
|
|
|
|
private:
|
2020-07-29 15:49:35 +02:00
|
|
|
class Impl;
|
|
|
|
std::unique_ptr<Impl> impl_;
|
|
|
|
};
|
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* The future native C++ interface for interaction with TDLib.
|
|
|
|
*
|
2020-11-18 21:42:26 +01:00
|
|
|
* A TDLib client instance can be created through the method ClientManager::create_client_id.
|
2020-11-19 23:32:58 +01:00
|
|
|
* Requests can be sent using the method ClientManager::send from any thread.
|
2020-11-18 21:42:26 +01:00
|
|
|
* New updates and responses to requests can be received using the method ClientManager::receive from any thread after
|
|
|
|
* the first request has been sent to the client instance. ClientManager::receive must not be called simultaneously from
|
2020-11-14 23:13:11 +01:00
|
|
|
* 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.
|
2020-11-18 21:42:26 +01:00
|
|
|
* Some TDLib requests can be executed synchronously from any thread using the method ClientManager::execute.
|
2020-10-05 13:32:23 +02:00
|
|
|
*
|
|
|
|
* General pattern of usage:
|
|
|
|
* \code
|
|
|
|
* td::ClientManager manager;
|
2020-11-14 23:13:11 +01:00
|
|
|
* auto client_id = manager.create_client_id();
|
2020-10-05 13:32:23 +02:00
|
|
|
* // somehow share the manager and the client_id with other threads,
|
|
|
|
* // which will be able to send requests via manager.send(client_id, ...)
|
|
|
|
*
|
2020-11-14 23:13:11 +01:00
|
|
|
* // send some dummy requests to the new instance to activate it
|
|
|
|
* manager.send(client_id, ...);
|
|
|
|
*
|
2020-10-05 13:32:23 +02:00
|
|
|
* const double WAIT_TIMEOUT = 10.0; // seconds
|
|
|
|
* while (true) {
|
|
|
|
* auto response = manager.receive(WAIT_TIMEOUT);
|
|
|
|
* if (response.object == nullptr) {
|
|
|
|
* continue;
|
|
|
|
* }
|
|
|
|
*
|
2020-11-18 21:42:26 +01:00
|
|
|
* if (response.request_id == 0) {
|
|
|
|
* // process response.object as an incoming update of the type td_api::Update for the client response.client_id
|
2020-10-05 13:32:23 +02:00
|
|
|
* } else {
|
|
|
|
* // process response.object as an answer to a request response.request_id for the client response.client_id
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* \endcode
|
|
|
|
*/
|
|
|
|
class ClientManager final {
|
2020-07-29 15:49:35 +02:00
|
|
|
public:
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* Creates a new TDLib client manager.
|
|
|
|
*/
|
|
|
|
ClientManager();
|
2020-07-29 15:49:35 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* Opaque TDLib client instance identifier.
|
|
|
|
*/
|
2020-07-29 15:49:35 +02:00
|
|
|
using ClientId = std::int32_t;
|
2020-10-05 13:32:23 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Request identifier.
|
|
|
|
* Responses to TDLib requests will have the same request id as the corresponding request.
|
2020-11-18 21:42:26 +01:00
|
|
|
* Updates from TDLib will have the request_id == 0, incoming requests are thus not allowed to have request_id == 0.
|
2020-10-05 13:32:23 +02:00
|
|
|
*/
|
2020-07-29 15:49:35 +02:00
|
|
|
using RequestId = std::uint64_t;
|
2020-10-05 13:32:23 +02:00
|
|
|
|
|
|
|
/**
|
2020-11-14 23:13:11 +01:00
|
|
|
* Returns an opaque identifier of a new TDLib instance.
|
|
|
|
* The TDLib instance will not send updates until the first request is sent to it.
|
2020-11-18 21:42:26 +01:00
|
|
|
* \return Opaque identifier of a new TDLib instance.
|
2020-10-05 13:32:23 +02:00
|
|
|
*/
|
2020-11-14 23:13:11 +01:00
|
|
|
ClientId create_client_id();
|
2020-10-05 13:32:23 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends request to TDLib. May be called from any thread.
|
|
|
|
* \param[in] client_id TDLib client instance identifier.
|
|
|
|
* \param[in] request_id Request identifier. Must be non-zero.
|
|
|
|
* \param[in] request Request to TDLib.
|
|
|
|
*/
|
|
|
|
void send(ClientId client_id, RequestId request_id, td_api::object_ptr<td_api::Function> &&request);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A response to a request, or an incoming update from TDLib.
|
|
|
|
*/
|
2020-07-29 15:49:35 +02:00
|
|
|
struct Response {
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
2020-11-18 21:42:26 +01:00
|
|
|
* TDLib client instance identifier, for which the response was received.
|
2020-10-05 13:32:23 +02:00
|
|
|
*/
|
2020-07-29 15:49:35 +02:00
|
|
|
ClientId client_id;
|
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* Request identifier, to which the response corresponds, or 0 for incoming updates from TDLib.
|
|
|
|
*/
|
|
|
|
RequestId request_id;
|
2020-07-30 03:04:57 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* TDLib API object representing a response to a TDLib request or an incoming update.
|
|
|
|
*/
|
|
|
|
td_api::object_ptr<td_api::Object> object;
|
|
|
|
};
|
2020-07-30 03:04:57 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
2020-11-18 21:42:26 +01:00
|
|
|
* Receives incoming updates and responses to requests from TDLib. May be called from any thread, but must not be
|
2020-10-05 13:32:23 +02:00
|
|
|
* called simultaneously from two different threads.
|
|
|
|
* \param[in] timeout The maximum number of seconds allowed for this function to wait for new data.
|
2020-11-18 21:42:26 +01:00
|
|
|
* \return An incoming update or response to a request. The object returned in the response may be a nullptr
|
2020-10-05 13:32:23 +02:00
|
|
|
* if the timeout expires.
|
|
|
|
*/
|
2020-07-29 15:49:35 +02:00
|
|
|
Response receive(double timeout);
|
2020-07-30 03:04:57 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
2020-11-18 21:42:26 +01:00
|
|
|
* Synchronously executes a TDLib request.
|
|
|
|
* A request can be executed synchronously, only if it is documented with "Can be called synchronously".
|
2020-10-05 13:32:23 +02:00
|
|
|
* \param[in] request Request to the TDLib.
|
|
|
|
* \return The request response.
|
|
|
|
*/
|
|
|
|
static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> &&request);
|
2020-07-29 15:49:35 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
2020-11-18 21:42:26 +01:00
|
|
|
* Destroys the client manager and all TDLib client instances managed by it.
|
2020-10-05 13:32:23 +02:00
|
|
|
*/
|
|
|
|
~ClientManager();
|
2020-07-30 03:04:57 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* Move constructor.
|
|
|
|
*/
|
|
|
|
ClientManager(ClientManager &&other);
|
2020-07-30 03:04:57 +02:00
|
|
|
|
2020-10-05 13:32:23 +02:00
|
|
|
/**
|
|
|
|
* Move assignment operator.
|
|
|
|
*/
|
|
|
|
ClientManager &operator=(ClientManager &&other);
|
2020-07-29 15:49:35 +02:00
|
|
|
|
2020-10-11 10:08:56 +02:00
|
|
|
/**
|
|
|
|
* Returns a pointer to a singleton ClientManager instance.
|
|
|
|
* \return A unique singleton ClientManager instance.
|
|
|
|
*/
|
|
|
|
static ClientManager *get_manager_singleton();
|
|
|
|
|
2020-07-29 15:49:35 +02:00
|
|
|
private:
|
2020-08-25 15:32:22 +02:00
|
|
|
friend class Client;
|
2018-12-31 20:04:05 +01:00
|
|
|
class Impl;
|
|
|
|
std::unique_ptr<Impl> impl_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace td
|