Use ClientManager instead of Client in ClientDotNet.

This commit is contained in:
levlam 2021-09-27 21:43:14 +03:00
parent 0208b7058b
commit ad2cc6e534
3 changed files with 61 additions and 76 deletions

View File

@ -34,13 +34,7 @@ namespace TdExample
private static Td.Client CreateTdClient()
{
Td.Client result = Td.Client.Create(new UpdateHandler());
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
result.Run();
}).Start();
return result;
return Td.Client.Create(new UpdateHandler());
}
private static void Print(string str)
@ -133,7 +127,6 @@ namespace TdExample
else if (_authorizationState is TdApi.AuthorizationStateClosed)
{
Print("Closed");
_client.Dispose(); // _client is closed and native resources can be disposed now
if (!_needQuit)
{
_client = CreateTdClient(); // recreate _client after previous has closed
@ -223,6 +216,11 @@ namespace TdExample
{
throw new System.IO.IOException("Write access to the current directory is required");
}
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Td.Client.Run();
}).Start();
// create Td.Client
_client = CreateTdClient();

View File

@ -30,30 +30,23 @@ namespace TdApp
Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0));
Td.Client.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile(Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "log"), 1 << 27, false)));
Td.Client.SetLogMessageCallback(100, LogMessageCallback);
System.Threading.Tasks.Task.Run(() =>
{
try
{
_client = Td.Client.Create(_handler);
var parameters = new TdApi.TdlibParameters();
parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
parameters.UseSecretChats = true;
parameters.UseMessageDatabase = true;
parameters.ApiId = 94575;
parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
parameters.SystemLanguageCode = "en";
parameters.DeviceModel = "Desktop";
parameters.ApplicationVersion = "1.0.0";
_client.Send(new TdApi.SetTdlibParameters(parameters), null);
_client.Send(new TdApi.CheckDatabaseEncryptionKey(), null);
_client.Run();
}
catch (Exception ex)
{
Print(ex.ToString());
}
Td.Client.Run();
});
_client = Td.Client.Create(_handler);
var parameters = new TdApi.TdlibParameters();
parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
parameters.UseSecretChats = true;
parameters.UseMessageDatabase = true;
parameters.ApiId = 94575;
parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
parameters.SystemLanguageCode = "en";
parameters.DeviceModel = "Desktop";
parameters.ApplicationVersion = "1.0.0";
_client.Send(new TdApi.SetTdlibParameters(parameters), null);
_client.Send(new TdApi.CheckDatabaseEncryptionKey(), null);
}
public void Print(String str)

View File

@ -56,18 +56,12 @@ public:
/// of the query or with Telegram.Td.Api.Error as parameter. If it is null, nothing will be called.</param>
/// <exception cref="NullReferenceException">Thrown when query is null.</exception>
void Send(Api::Function^ function, ClientResultHandler^ handler) {
if (function == nullptr) {
throw REF_NEW NullReferenceException("Function can't be null");
}
std::uint64_t queryId = Increment(currentId);
std::uint64_t requestId = Increment(currentRequestId);
if (handler != nullptr) {
handlers[queryId] = handler;
handlers[requestId] = handler;
}
td::Client::Request request;
request.id = queryId;
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
client->send(std::move(request));
auto request = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
td::ClientManager::get_manager_singleton()->send(clientId, requestId, std::move(request));
}
/// <summary>
@ -77,31 +71,32 @@ public:
/// <returns>Returns request result.</returns>
/// <exception cref="NullReferenceException">Thrown when query is null.</exception>
static Api::BaseObject^ Execute(Api::Function^ function) {
if (function == nullptr) {
throw REF_NEW NullReferenceException("Function can't be null");
}
td::Client::Request request;
request.id = 0;
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
return Api::FromUnmanaged(*td::Client::execute(std::move(request)).object);
auto request = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
return Api::FromUnmanaged(*td::ClientManager::execute(std::move(request)));
}
/// <summary>
/// Launches a cycle which will fetch all results of queries to TDLib and incoming updates from TDLib.
/// Must be called once on a separate dedicated thread, on which all updates and query results will be handled.
/// Returns only when TDLib instance is closed.
/// Must be called once on a separate dedicated thread, on which all updates and query results from all Clients will be handled.
/// Never returns.
/// </summary>
void Run() {
static void Run() {
while (true) {
auto response = client->receive(10.0);
auto response = td::ClientManager::get_manager_singleton()->receive(300.0);
if (response.object != nullptr) {
ProcessResult(response.id, Api::FromUnmanaged(*response.object));
if (response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
bool isClosed = response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<td::td_api::updateAuthorizationState &>(*response.object).authorization_state_->get_id() ==
td::td_api::authorizationStateClosed::ID) {
break;
td::td_api::authorizationStateClosed::ID && response.request_id == 0;
ClientResultHandler^ handler;
if (response.request_id == 0 ? updateHandlers.TryGetValue(response.client_id, handler) :
handlers.TryRemove(response.request_id, handler)) {
// TODO try/catch
handler->OnResult(Api::FromUnmanaged(*response.object));
}
if (isClosed) {
updateHandlers.TryRemove(response.client_id, handler);
}
}
}
@ -127,38 +122,33 @@ public:
static void SetLogMessageCallback(std::int32_t max_verbosity_level, LogMessageCallback^ callback) {
std::lock_guard<std::mutex> lock(logMutex);
if (callback == nullptr) {
::td::ClientManager::set_log_message_callback(max_verbosity_level, nullptr);
td::ClientManager::set_log_message_callback(max_verbosity_level, nullptr);
logMessageCallback = nullptr;
} else {
logMessageCallback = callback;
::td::ClientManager::set_log_message_callback(max_verbosity_level, LogMessageCallbackWrapper);
td::ClientManager::set_log_message_callback(max_verbosity_level, LogMessageCallbackWrapper);
}
}
#endif
private:
Client(ClientResultHandler^ updateHandler) {
client = new td::Client();
handlers[0] = updateHandler;
}
~Client() {
delete client;
}
std::int64_t currentId = 0;
ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers;
td::Client *client = nullptr;
void ProcessResult(std::uint64_t id, Api::BaseObject^ object) {
ClientResultHandler^ handler;
// update handler stays forever
if (id == 0 ? handlers.TryGetValue(id, handler) : handlers.TryRemove(id, handler)) {
// TODO try/catch
handler->OnResult(object);
clientId = td::ClientManager::get_manager_singleton()->create_client_id();
if (updateHandler != nullptr) {
updateHandlers[clientId] = updateHandler;
}
Send(REF_NEW Api::GetOption("version"), nullptr);
}
#if !TD_CLI
static std::int64_t currentRequestId;
#else
static std::int64_t currentRequestId = 0;
#endif
static ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers;
static ConcurrentDictionary<std::int32_t, ClientResultHandler^> updateHandlers;
std::int32_t clientId;
#if !TD_CLI
static std::mutex logMutex;
static LogMessageCallback^ logMessageCallback;
@ -173,6 +163,10 @@ private:
};
#if !TD_CLI
std::int64_t Client::currentRequestId = 0;
ConcurrentDictionary<std::uint64_t, ClientResultHandler^> Client::handlers;
ConcurrentDictionary<std::int32_t, ClientResultHandler^> Client::updateHandlers;
std::mutex Client::logMutex;
LogMessageCallback^ Client::logMessageCallback;
#endif