class TD::Client
Simple client for TDLib.
Constants
- TIMEOUT
Public Class Methods
@param [FFI::Pointer] td_client @param [TD::UpdateManager] update_manager @param [Numeric] timeout @param [Hash] extra_config optional configuration hash that will be merged into tdlib client configuration
# File lib/tdlib/client.rb, line 18 def initialize(td_client = TD::Api.client_create, update_manager = TD::UpdateManager.new(td_client), timeout: TIMEOUT, **extra_config) @td_client = td_client @ready = false @alive = true @update_manager = update_manager @timeout = timeout @config = TD.config.client.to_h.merge(extra_config) @ready_condition_mutex = Mutex.new @ready_condition = ConditionVariable.new end
# File lib/tdlib/client.rb, line 10 def self.ready(*args) new(*args).connect end
Public Instance Methods
# File lib/tdlib/client.rb, line 155 def alive? @alive end
Sends asynchronous request to the TDLib client and returns Promise object @see TD::ClientMethods List of available queries as methods @see github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md
Concurrent::Promise documentation
@example
client.broadcast(some_query).then { |result| puts result }.rescue { |error| puts [error.code, error.message] }
@param [Hash] query @return [Concurrent::Promises::Future]
# File lib/tdlib/client.rb, line 64 def broadcast(query) return dead_client_promise if dead? Promises.future do condition = ConditionVariable.new extra = SecureRandom.uuid result = nil mutex = Mutex.new @update_manager << TD::UpdateHandler.new(TD::Types::Base, extra, disposable: true) do |update| mutex.synchronize do result = update condition.signal end end query['@extra'] = extra mutex.synchronize do send_to_td_client(query) condition.wait(mutex, @timeout) error = nil error = result if result.is_a?(TD::Types::Error) error = timeout_error if result.nil? raise TD::Error.new(error) if error result end end end
Adds initial authorization state handler and runs update manager Returns future that will be fulfilled when client is ready @return [Concurrent::Promises::Future]
# File lib/tdlib/client.rb, line 35 def connect on TD::Types::Update::AuthorizationState do |update| case update.authorization_state when TD::Types::AuthorizationState::WaitTdlibParameters set_tdlib_parameters(parameters: TD::Types::TdlibParameters.new(**@config)) when TD::Types::AuthorizationState::WaitEncryptionKey check_database_encryption_key(encryption_key: TD.config.encryption_key).then do @ready_condition_mutex.synchronize do @ready = true @ready_condition.broadcast end end else # do nothing end end @update_manager.run(callback: method(:handle_update)) ready end
# File lib/tdlib/client.rb, line 159 def dead? !alive? end
Stops update manager and destroys TDLib client
# File lib/tdlib/client.rb, line 150 def dispose return if dead? close.then { get_authorization_state } end
Synchronously executes TDLib request Only a few requests can be executed synchronously @param [Hash] query
# File lib/tdlib/client.rb, line 106 def execute(query) return dead_client_error if dead? TD::Api.client_execute(@td_client, query) end
Sends asynchronous request to the TDLib client and returns received update synchronously @param [Hash] query @return [Hash]
# File lib/tdlib/client.rb, line 97 def fetch(query) broadcast(query).value! end
Binds passed block as a handler for updates with type of update_type @param [String, Class] update_type @yield [update] yields update to the block as soon as it's received
# File lib/tdlib/client.rb, line 114 def on(update_type, &action) if update_type.is_a?(String) if (type_const = TD::Types::LOOKUP_TABLE[update_type]) update_type = TD::Types.const_get("TD::Types::#{type_const}") else raise ArgumentError.new("Can't find class for #{update_type}") end end unless update_type < TD::Types::Base raise ArgumentError.new("Wrong type specified (#{update_type}). Should be of kind TD::Types::Base") end @update_manager << TD::UpdateHandler.new(update_type, &action) end
@deprecated
# File lib/tdlib/client.rb, line 145 def on_ready(&action) ready.then(&action).value! end
returns future that will be fulfilled when client is ready @return [Concurrent::Promises::Future]
# File lib/tdlib/client.rb, line 132 def ready return dead_client_promise if dead? return Promises.fulfilled_future(self) if ready? Promises.future do @ready_condition_mutex.synchronize do next self if @ready || (@ready_condition.wait(@ready_condition_mutex, @timeout) && @ready) raise TD::Error.new(timeout_error) end end end
# File lib/tdlib/client.rb, line 163 def ready? @ready end
Private Instance Methods
# File lib/tdlib/client.rb, line 191 def dead_client_error TD::Error.new(TD::Types::Error.new(code: 0, message: 'TD client is dead')) end
# File lib/tdlib/client.rb, line 187 def dead_client_promise Promises.rejected_future(dead_client_error) end
# File lib/tdlib/client.rb, line 169 def handle_update(update) return unless update.is_a?(TD::Types::Update::AuthorizationState) && update.authorization_state.is_a?(TD::Types::AuthorizationState::Closed) @alive = false @ready = false sleep 0.001 TD::Api.client_destroy(@td_client) throw(:client_closed) end
# File lib/tdlib/client.rb, line 178 def send_to_td_client(query) return unless alive? TD::Api.client_send(@td_client, query) end
# File lib/tdlib/client.rb, line 183 def timeout_error TD::Types::Error.new(code: 0, message: 'Timeout error') end