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() private static Td.Client CreateTdClient()
{ {
Td.Client result = Td.Client.Create(new UpdateHandler()); return Td.Client.Create(new UpdateHandler());
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
result.Run();
}).Start();
return result;
} }
private static void Print(string str) private static void Print(string str)
@ -133,7 +127,6 @@ namespace TdExample
else if (_authorizationState is TdApi.AuthorizationStateClosed) else if (_authorizationState is TdApi.AuthorizationStateClosed)
{ {
Print("Closed"); Print("Closed");
_client.Dispose(); // _client is closed and native resources can be disposed now
if (!_needQuit) if (!_needQuit)
{ {
_client = CreateTdClient(); // recreate _client after previous has closed _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"); 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 // create Td.Client
_client = CreateTdClient(); _client = CreateTdClient();

View File

@ -30,11 +30,11 @@ namespace TdApp
Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0)); 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.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile(Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "log"), 1 << 27, false)));
Td.Client.SetLogMessageCallback(100, LogMessageCallback); Td.Client.SetLogMessageCallback(100, LogMessageCallback);
System.Threading.Tasks.Task.Run(() => System.Threading.Tasks.Task.Run(() =>
{ {
try Td.Client.Run();
{ });
_client = Td.Client.Create(_handler); _client = Td.Client.Create(_handler);
var parameters = new TdApi.TdlibParameters(); var parameters = new TdApi.TdlibParameters();
parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path; parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
@ -47,13 +47,6 @@ namespace TdApp
parameters.ApplicationVersion = "1.0.0"; parameters.ApplicationVersion = "1.0.0";
_client.Send(new TdApi.SetTdlibParameters(parameters), null); _client.Send(new TdApi.SetTdlibParameters(parameters), null);
_client.Send(new TdApi.CheckDatabaseEncryptionKey(), null); _client.Send(new TdApi.CheckDatabaseEncryptionKey(), null);
_client.Run();
}
catch (Exception ex)
{
Print(ex.ToString());
}
});
} }
public void Print(String str) 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> /// 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> /// <exception cref="NullReferenceException">Thrown when query is null.</exception>
void Send(Api::Function^ function, ClientResultHandler^ handler) { void Send(Api::Function^ function, ClientResultHandler^ handler) {
if (function == nullptr) { std::uint64_t requestId = Increment(currentRequestId);
throw REF_NEW NullReferenceException("Function can't be null");
}
std::uint64_t queryId = Increment(currentId);
if (handler != nullptr) { if (handler != nullptr) {
handlers[queryId] = handler; handlers[requestId] = handler;
} }
td::Client::Request request; auto request = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
request.id = queryId; td::ClientManager::get_manager_singleton()->send(clientId, requestId, std::move(request));
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
client->send(std::move(request));
} }
/// <summary> /// <summary>
@ -77,31 +71,32 @@ public:
/// <returns>Returns request result.</returns> /// <returns>Returns request result.</returns>
/// <exception cref="NullReferenceException">Thrown when query is null.</exception> /// <exception cref="NullReferenceException">Thrown when query is null.</exception>
static Api::BaseObject^ Execute(Api::Function^ function) { static Api::BaseObject^ Execute(Api::Function^ function) {
if (function == nullptr) { auto request = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
throw REF_NEW NullReferenceException("Function can't be null"); return Api::FromUnmanaged(*td::ClientManager::execute(std::move(request)));
}
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);
} }
/// <summary> /// <summary>
/// Launches a cycle which will fetch all results of queries to TDLib and incoming updates from TDLib. /// 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. /// Must be called once on a separate dedicated thread, on which all updates and query results from all Clients will be handled.
/// Returns only when TDLib instance is closed. /// Never returns.
/// </summary> /// </summary>
void Run() { static void Run() {
while (true) { while (true) {
auto response = client->receive(10.0); auto response = td::ClientManager::get_manager_singleton()->receive(300.0);
if (response.object != nullptr) { if (response.object != nullptr) {
ProcessResult(response.id, Api::FromUnmanaged(*response.object)); bool isClosed = response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
if (response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<td::td_api::updateAuthorizationState &>(*response.object).authorization_state_->get_id() == static_cast<td::td_api::updateAuthorizationState &>(*response.object).authorization_state_->get_id() ==
td::td_api::authorizationStateClosed::ID) { td::td_api::authorizationStateClosed::ID && response.request_id == 0;
break;
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,37 +122,32 @@ public:
static void SetLogMessageCallback(std::int32_t max_verbosity_level, LogMessageCallback^ callback) { static void SetLogMessageCallback(std::int32_t max_verbosity_level, LogMessageCallback^ callback) {
std::lock_guard<std::mutex> lock(logMutex); std::lock_guard<std::mutex> lock(logMutex);
if (callback == nullptr) { 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; logMessageCallback = nullptr;
} else { } else {
logMessageCallback = callback; logMessageCallback = callback;
::td::ClientManager::set_log_message_callback(max_verbosity_level, LogMessageCallbackWrapper); td::ClientManager::set_log_message_callback(max_verbosity_level, LogMessageCallbackWrapper);
} }
} }
#endif #endif
private: private:
Client(ClientResultHandler^ updateHandler) { Client(ClientResultHandler^ updateHandler) {
client = new td::Client(); clientId = td::ClientManager::get_manager_singleton()->create_client_id();
handlers[0] = updateHandler; if (updateHandler != nullptr) {
updateHandlers[clientId] = updateHandler;
}
Send(REF_NEW Api::GetOption("version"), nullptr);
} }
~Client() { #if !TD_CLI
delete client; static std::int64_t currentRequestId;
} #else
static std::int64_t currentRequestId = 0;
std::int64_t currentId = 0; #endif
ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers; static ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers;
td::Client *client = nullptr; static ConcurrentDictionary<std::int32_t, ClientResultHandler^> updateHandlers;
std::int32_t clientId;
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);
}
}
#if !TD_CLI #if !TD_CLI
static std::mutex logMutex; static std::mutex logMutex;
@ -173,6 +163,10 @@ private:
}; };
#if !TD_CLI #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; std::mutex Client::logMutex;
LogMessageCallback^ Client::logMessageCallback; LogMessageCallback^ Client::logMessageCallback;
#endif #endif