From 9cbf51d5a0a514f5d2cb73fd1a8cb5be4cb8212c Mon Sep 17 00:00:00 2001 From: Vladislav Yashin Date: Thu, 24 May 2018 19:18:52 +0300 Subject: [PATCH 1/3] Return Concurrent::Promise from TD::Client#broadcast --- lib/tdlib/client.rb | 56 +++++++++++++++++----------------- spec/integration/tdlib_spec.rb | 13 ++------ 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/lib/tdlib/client.rb b/lib/tdlib/client.rb index d85024d..958c754 100644 --- a/lib/tdlib/client.rb +++ b/lib/tdlib/client.rb @@ -58,6 +58,8 @@ # # p @me class TD::Client + include Concurrent + TIMEOUT = 20 def initialize(td_client = TD::Api.client_create, @@ -74,49 +76,47 @@ def initialize(td_client = TD::Api.client_create, @update_manager.run end - # Sends asynchronous request to the TDLib client + # Sends asynchronous request to the TDLib client and returns Promise object + # @see https://www.rubydoc.info/github/ruby-concurrency/concurrent-ruby/Concurrent/Promise) + # @example + # client.broadcast(some_query).then { |result| puts result }.rescue # @param [Hash] query - # @yield [update] yields update to the block as soon as it's received - def broadcast(query) - if block_given? + # @param [Numeric] timeout + # @return [Concurrent::Promise] + def broadcast(query, timeout: TIMEOUT) + Promise.execute do + condition = ConditionVariable.new extra = TD::Utils.generate_extra(query) + result = nil + mutex = Mutex.new handler = ->(update) do return unless update['@extra'] == extra - yield update - @update_manager.remove_handler(handler) + mutex.synchronize do + result = update + @update_manager.remove_handler(handler) + condition.signal + end end @update_manager.add_handler(handler) query['@extra'] = extra + mutex.synchronize do + TD::Api.client_send(@td_client, query) + condition.wait(mutex, timeout) + raise TD::TimeoutError if result.nil? + result + end end - TD::Api.client_send(@td_client, query) end # Sends asynchronous request to the TDLib client and returns received update synchronously # @param [Hash] query # @return [Hash] - def broadcast_and_receive(query, timeout: TIMEOUT) - condition = ConditionVariable.new - extra = TD::Utils.generate_extra(query) - result = nil - mutex = Mutex.new - handler = ->(update) do - return unless update['@extra'] == extra - mutex.synchronize do - result = update - @update_manager.remove_handler(handler) - condition.signal - end - end - @update_manager.add_handler(handler) - query['@extra'] = extra - mutex.synchronize do - TD::Api.client_send(@td_client, query) - condition.wait(mutex, timeout) - raise TD::TimeoutError if result.nil? - result - end + def fetch(query, timeout: TIMEOUT) + broadcast(query, timeout: timeout).value end + alias broadcast_and_receive fetch + # Synchronously executes TDLib request # Only a few requests can be executed synchronously # @param [Hash] query diff --git a/spec/integration/tdlib_spec.rb b/spec/integration/tdlib_spec.rb index 850b770..b6b271f 100644 --- a/spec/integration/tdlib_spec.rb +++ b/spec/integration/tdlib_spec.rb @@ -35,16 +35,9 @@ subject { client.on_ready { client.broadcast(payload) } } it { expect { subject }.not_to raise_error(Exception) } - end - - context 'when block given' do - subject { client.on_ready { client.broadcast(payload) { |update| @result = update } } } - - it 'runs block on update' do - subject - sleep 1 - expect(@result).to include('@type', 'entities') - end + it { is_expected.to satisfy { |result| result.state == :pending } } + it { is_expected.to satisfy { |result| sleep 1; result.state == :fulfilled } } + it { is_expected.to satisfy { |result| sleep 1; result.value['@type'] == 'textEntities' } } end end From 8190a721afd43c4ed93f60c591b553a3cfd9681e Mon Sep 17 00:00:00 2001 From: Vladislav Yashin Date: Sun, 27 May 2018 10:48:20 +0300 Subject: [PATCH 2/3] Add concurrent-ruby to gemspec --- tdlib-ruby.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/tdlib-ruby.gemspec b/tdlib-ruby.gemspec index d11c4cb..c52a728 100644 --- a/tdlib-ruby.gemspec +++ b/tdlib-ruby.gemspec @@ -30,6 +30,7 @@ Gem::Specification.new do |gem| gem.require_paths = ['lib'] gem.add_runtime_dependency 'dry-configurable', '~> 0.7' + gem.add_runtime_dependency 'concurrent-ruby', '~> 1.0' gem.add_development_dependency 'bundler', '~> 1.10' gem.add_development_dependency 'rake', '12.3.1' From ebae800205f2a969844f6f83736b03fadcdf1529 Mon Sep 17 00:00:00 2001 From: Vladislav Yashin Date: Sun, 27 May 2018 11:19:34 +0300 Subject: [PATCH 3/3] Bump version [skip ci] --- ChangeLog.md | 5 +++++ README.md | 8 ++++++++ lib/tdlib/version.rb | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index f7a8eb4..65507a2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,8 @@ +### 1.0.0 / 2018-05-27 + +* Return promises from TD::Client#broadcast +* Add #fetch as alias to #broadcast_and_receive + ### 0.9.4 / 2018-05-16 * Fix recursive locking in nested handlers diff --git a/README.md b/README.md index c173eaf..7e5e81f 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,14 @@ end p @me ``` +## TD::Client#broadcast + +From version 1.0 TD::Client##broadcast returns [Concurrent::Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html) object. + +```ruby + me = client.broadcast('@type' => 'getMe').then { |result| puts result }.rescue { |error| puts error }.value +``` + ## Configuration ```ruby diff --git a/lib/tdlib/version.rb b/lib/tdlib/version.rb index 8890c82..83db62e 100644 --- a/lib/tdlib/version.rb +++ b/lib/tdlib/version.rb @@ -1,4 +1,4 @@ module TD # tdlib-ruby version - VERSION = "0.9.4" + VERSION = "1.0.0" end