class TD::Client

Simple client for TDLib.

Constants

TIMEOUT

Public Class Methods

new(td_client = TD::Api.client_create, update_manager = TD::UpdateManager.new(td_client), timeout: TIMEOUT, **extra_config) click to toggle source

@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
ready(*args) click to toggle source
# File lib/tdlib/client.rb, line 10
def self.ready(*args)
  new(*args).connect
end

Public Instance Methods

alive?() click to toggle source
# File lib/tdlib/client.rb, line 155
def alive?
  @alive
end
broadcast(query) click to toggle source

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
broadcast_and_receive(query)
Alias for: fetch
connect() click to toggle source

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
dead?() click to toggle source
# File lib/tdlib/client.rb, line 159
def dead?
  !alive?
end
dispose() click to toggle source

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
execute(query) click to toggle source

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
fetch(query) click to toggle source

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
Also aliased as: broadcast_and_receive
on(update_type, &action) click to toggle source

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
on_ready(&action) click to toggle source

@deprecated

# File lib/tdlib/client.rb, line 145
def on_ready(&action)
  ready.then(&action).value!
end
ready() click to toggle source

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
ready?() click to toggle source
# File lib/tdlib/client.rb, line 163
def ready?
  @ready
end

Private Instance Methods

dead_client_error() click to toggle source
# 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
dead_client_promise() click to toggle source
# File lib/tdlib/client.rb, line 187
def dead_client_promise
  Promises.rejected_future(dead_client_error)
end
handle_update(update) click to toggle source
# 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
send_to_td_client(query) click to toggle source
# File lib/tdlib/client.rb, line 178
def send_to_td_client(query)
  return unless alive?
  TD::Api.client_send(@td_client, query)
end
timeout_error() click to toggle source
# File lib/tdlib/client.rb, line 183
def timeout_error
  TD::Types::Error.new(code: 0, message: 'Timeout error')
end