From 6e077827e7f139db6d66ae5f64e10e11b8424674 Mon Sep 17 00:00:00 2001 From: dblock Date: Sat, 25 Aug 2018 17:25:26 +0200 Subject: [PATCH 01/10] Added support for socketry/async. Closes #210. --- .rubocop_todo.yml | 14 +++- .travis.yml | 2 + CHANGELOG.md | 1 + README.md | 19 ++++-- UPGRADING.md | 6 ++ examples/hi_real_time_async_async/Gemfile | 6 ++ examples/hi_real_time_async_async/Procfile | 2 + examples/hi_real_time_async_async/hi.rb | 35 ++++++++++ lib/slack/real_time/concurrency.rb | 1 + lib/slack/real_time/concurrency/async.rb | 76 ++++++++++++++++++++++ lib/slack/real_time/config.rb | 6 +- spec/integration/integration_spec.rb | 9 +++ 12 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 examples/hi_real_time_async_async/Gemfile create mode 100644 examples/hi_real_time_async_async/Procfile create mode 100644 examples/hi_real_time_async_async/hi.rb create mode 100644 lib/slack/real_time/concurrency/async.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8dcf55fa..b2c174c0 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,11 +1,17 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2018-08-20 08:24:54 -0400 using RuboCop version 0.58.2. +# on 2018-08-25 18:15:23 +0200 using RuboCop version 0.58.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. +# Offense count: 1 +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Exclude: + - 'lib/slack/real_time/concurrency/async.rb' + # Offense count: 4 Lint/HandleExceptions: Exclude: @@ -13,6 +19,12 @@ Lint/HandleExceptions: - 'spec/slack/real_time/concurrency/celluloid_spec.rb' - 'spec/slack/real_time/concurrency/eventmachine_spec.rb' +# Offense count: 2 +Lint/UselessAssignment: + Exclude: + - 'lib/slack/real_time/concurrency/async.rb' + - 'lib/slack/real_time/config.rb' + # Offense count: 1 # Configuration parameters: EnforcedStyleForLeadingUnderscores. # SupportedStylesForLeadingUnderscores: disallowed, required, optional diff --git a/.travis.yml b/.travis.yml index 8615f1af..618fb5bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,8 @@ matrix: env: CONCURRENCY=celluloid-io - rvm: 2.4.1 env: CONCURRENCY=faye-websocket + - rvm: 2.5 + env: CONCURRENCY=async-websocket allow_failures: - rvm: ruby-head - rvm: jruby-head diff --git a/CHANGELOG.md b/CHANGELOG.md index 40190c47..b95b9ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 0.12.1 (Next) +* [#219](https://github.com/slack-ruby/slack-ruby-client/pull/219): Added support for `async-websocket`. - [@dblock](https://github.com/dblock). * Your contribution here. ### 0.12.0 (8/20/2018) diff --git a/README.md b/README.md index cce4132c..49184f8b 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,10 @@ Add to Gemfile. gem 'slack-ruby-client' ``` -If you're going to be using the RealTime client, add either `eventmachine` and `faye-websocket` or `celluloid-io`. See below for more information about concurrency. +If you're going to be using the RealTime client, add either `async-websocket`, `eventmachine` and `faye-websocket` or `celluloid-io`. See below for more information about concurrency. We recommend you use `async-websocket`. ``` -gem 'eventmachine' -gem 'faye-websocket' +gem 'async-websocket' ``` Run `bundle install`. @@ -374,11 +373,11 @@ See [#134](https://github.com/slack-ruby/slack-ruby-client/issues/134) for a dis #### Concurrency -`Slack::RealTime::Client` needs help from a concurrency library and supports [Faye::WebSocket](https://github.com/faye/faye-websocket-ruby) with [Eventmachine](https://github.com/eventmachine/eventmachine) and [Celluloid](https://github.com/celluloid/celluloid). It will auto-detect one or the other depending on the gems in your Gemfile, but you can also set concurrency explicitly. +`Slack::RealTime::Client` needs help from a concurrency library and supports [Async](https://github.com/socketry/async), [Faye::WebSocket](https://github.com/faye/faye-websocket-ruby) with [Eventmachine](https://github.com/eventmachine/eventmachine) and [Celluloid](https://github.com/celluloid/celluloid). It will auto-detect one or the other depending on the gems in your Gemfile, but you can also set concurrency explicitly. ```ruby Slack::RealTime.configure do |config| - config.concurrency = Slack::RealTime::Concurrency::Eventmachine + config.concurrency = Slack::RealTime::Concurrency::Async end ``` @@ -390,6 +389,16 @@ client = Slack::RealTime::Client.new client.start_async ``` +##### Async + +This is the recommended library. Add `async-websocket` to your Gemfile. + +``` +gem 'async-websocket' +``` + +See a fully working example in [examples/hi_real_time_async_async](examples/hi_real_time_async_async/hi.rb). + ##### Faye::Websocket with Eventmachine Add the following to your Gemfile. diff --git a/UPGRADING.md b/UPGRADING.md index 8fa79dbe..7b73e8fd 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,6 +1,12 @@ Upgrading Slack-Ruby-Client =========================== +### Upgrading to >= 0.12.2 + +#### Recommended Async Library + +The RealTime client now supports [async-websocket](https://github.com/socketry/async-websocket), which is now the recommended library following numerous disconnect issues in [#208](https://github.com/slack-ruby/slack-ruby-client/issues/208). + ### Upgrading to >= 0.9.0 #### Changes in How the RTM Client Connects diff --git a/examples/hi_real_time_async_async/Gemfile b/examples/hi_real_time_async_async/Gemfile new file mode 100644 index 00000000..4be70966 --- /dev/null +++ b/examples/hi_real_time_async_async/Gemfile @@ -0,0 +1,6 @@ +source 'http://rubygems.org' + +gem 'slack-ruby-client', path: '../..' + +gem 'async-websocket' +gem 'foreman' diff --git a/examples/hi_real_time_async_async/Procfile b/examples/hi_real_time_async_async/Procfile new file mode 100644 index 00000000..8f831a3a --- /dev/null +++ b/examples/hi_real_time_async_async/Procfile @@ -0,0 +1,2 @@ +console: bundle exec ruby hi.rb + diff --git a/examples/hi_real_time_async_async/hi.rb b/examples/hi_real_time_async_async/hi.rb new file mode 100644 index 00000000..9d7147fb --- /dev/null +++ b/examples/hi_real_time_async_async/hi.rb @@ -0,0 +1,35 @@ +require 'slack-ruby-client' +require 'async' + +raise 'Missing ENV[SLACK_API_TOKENS]!' unless ENV.key?('SLACK_API_TOKENS') + +Async::Reactor.run do + $stdout.sync = true + logger = Logger.new($stdout) + logger.level = Logger::DEBUG + + ENV['SLACK_API_TOKENS'].split.each do |token| + logger.info "Starting #{token[0..12]} ..." + + client = Slack::RealTime::Client.new(token: token) + + client.on :hello do + logger.info "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." + end + + client.on :message do |data| + logger.info data + + client.typing channel: data.channel + + case data.text + when /hi/ then + client.message channel: data.channel, text: "Hi <@#{data.user}>!" + else + client.message channel: data.channel, text: "Sorry <@#{data.user}>, what?" + end + end + + client.start_async + end +end diff --git a/lib/slack/real_time/concurrency.rb b/lib/slack/real_time/concurrency.rb index 6fe1026e..42852977 100644 --- a/lib/slack/real_time/concurrency.rb +++ b/lib/slack/real_time/concurrency.rb @@ -1,6 +1,7 @@ module Slack module RealTime module Concurrency + autoload :Async, 'slack/real_time/concurrency/async' autoload :Eventmachine, 'slack/real_time/concurrency/eventmachine' autoload :Celluloid, 'slack/real_time/concurrency/celluloid' end diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb new file mode 100644 index 00000000..3eeda10e --- /dev/null +++ b/lib/slack/real_time/concurrency/async.rb @@ -0,0 +1,76 @@ +require 'async/websocket' + +module Slack + module RealTime + module Concurrency + module Async + class Client < ::Async::WebSocket::Client + extend ::Forwardable + def_delegators :driver, :on + + def text(message) + driver.text(message) + end + + def binary(data) + socket.write(data) + end + end + + class Socket < Slack::RealTime::Socket + attr_reader :client + + def start_async(client) + @client = client + client.run_loop + end + + def connect! + super + run_loop + end + + def close + driver.close + super + end + + def run_loop + @socket = build_socket + @connected = @socket.connect + while event = driver.next_event + + end + end + + protected + + def build_ssl_context + # TODO: context.set_params verify_mode: OpenSSL::SSL::VERIFY_PEER + { ssl_context: OpenSSL::SSL::SSLContext.new(:TLSv1_2_client) } + end + + def build_tcp_options + { + reuse_port: false + } + end + + def build_socket + socket = ::Async::IO::Endpoint.tcp(addr, port, build_tcp_options) + socket = ::Async::IO::SSLEndpoint.new(socket, build_ssl_context) if secure? + socket + end + + def build_driver + Client.new(build_socket.connect, url) + end + + def connect + @driver = build_driver + end + end + end + end + end +end diff --git a/lib/slack/real_time/config.rb b/lib/slack/real_time/config.rb index 5f753e10..5e566b44 100644 --- a/lib/slack/real_time/config.rb +++ b/lib/slack/real_time/config.rb @@ -36,15 +36,15 @@ def concurrency private def detect_concurrency - %i[Eventmachine Celluloid].each do |concurrency| + %i[Async Eventmachine Celluloid].each do |concurrency| begin return Slack::RealTime::Concurrency.const_get(concurrency) - rescue LoadError, NameError + rescue LoadError, NameError => e false # could not be loaded, missing dependencies end end - raise NoConcurrencyError, 'Missing concurrency. Add faye-websocket or celluloid-io to your Gemfile.' + raise NoConcurrencyError, 'Missing concurrency. Add async-websocket, faye-websocket or celluloid-io to your Gemfile.' end end diff --git a/spec/integration/integration_spec.rb b/spec/integration/integration_spec.rb index ae25537a..fac169f4 100644 --- a/spec/integration/integration_spec.rb +++ b/spec/integration/integration_spec.rb @@ -76,6 +76,15 @@ def stop_server wait_for_server end + if ENV['CONCURRENCY'] == 'async-websocket' + around do |example| + require 'async/reactor' + ::Async::Reactor.run do + example.run + end + end + end + context 'client connected' do before do start_server From 58c298009e0681d16c070dda27bbec9e71154ced Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 27 Aug 2018 18:28:52 +0900 Subject: [PATCH 02/10] Fix async implementation. --- lib/slack/real_time/concurrency/async.rb | 46 ++++++++++++------------ spec/integration/integration_spec.rb | 9 ----- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb index 3eeda10e..b01fb997 100644 --- a/lib/slack/real_time/concurrency/async.rb +++ b/lib/slack/real_time/concurrency/async.rb @@ -6,14 +6,14 @@ module Concurrency module Async class Client < ::Async::WebSocket::Client extend ::Forwardable - def_delegators :driver, :on + def_delegators :@driver, :on def text(message) - driver.text(message) + @driver.text(message) end def binary(data) - socket.write(data) + @driver.binary(data) end end @@ -21,25 +21,30 @@ class Socket < Slack::RealTime::Socket attr_reader :client def start_async(client) - @client = client - client.run_loop + Thread.new do + $stderr.puts "start_async: @driver = #{@driver}" + ::Async::Reactor.run do + client.run_loop + end + end end def connect! - super - run_loop + ::Async::Reactor.run do + super + + run_loop + end end def close - driver.close + @driver.close super end def run_loop - @socket = build_socket - @connected = @socket.connect - while event = driver.next_event - + while @driver and event = @driver.next_event + # $stderr.puts event.inspect end end @@ -56,18 +61,15 @@ def build_tcp_options } end - def build_socket - socket = ::Async::IO::Endpoint.tcp(addr, port, build_tcp_options) - socket = ::Async::IO::SSLEndpoint.new(socket, build_ssl_context) if secure? - socket + def build_endpoint + endpoint = ::Async::IO::Endpoint.tcp(addr, port, build_tcp_options) + endpoint = ::Async::IO::SSLEndpoint.new(endpoint, build_ssl_context) if secure? + + return endpoint end - - def build_driver - Client.new(build_socket.connect, url) - end - + def connect - @driver = build_driver + @driver = Client.new(build_endpoint.connect, url) end end end diff --git a/spec/integration/integration_spec.rb b/spec/integration/integration_spec.rb index fac169f4..ae25537a 100644 --- a/spec/integration/integration_spec.rb +++ b/spec/integration/integration_spec.rb @@ -76,15 +76,6 @@ def stop_server wait_for_server end - if ENV['CONCURRENCY'] == 'async-websocket' - around do |example| - require 'async/reactor' - ::Async::Reactor.run do - example.run - end - end - end - context 'client connected' do before do start_server From 78b64edaed08b5faf3d7a53a25fce276ae5c2a8a Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 27 Aug 2018 13:22:58 +0200 Subject: [PATCH 03/10] Fixed RTM example for async. --- .rubocop_todo.yml | 8 +---- examples/hi_real_time_async_async/hi.rb | 44 +++++++++++++----------- lib/slack/real_time/concurrency/async.rb | 15 +++----- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b2c174c0..a73f6302 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,17 +1,11 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2018-08-25 18:15:23 +0200 using RuboCop version 0.58.2. +# on 2018-08-27 13:21:41 +0200 using RuboCop version 0.58.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -# Configuration parameters: AllowSafeAssignment. -Lint/AssignmentInCondition: - Exclude: - - 'lib/slack/real_time/concurrency/async.rb' - # Offense count: 4 Lint/HandleExceptions: Exclude: diff --git a/examples/hi_real_time_async_async/hi.rb b/examples/hi_real_time_async_async/hi.rb index 9d7147fb..afa2a8ef 100644 --- a/examples/hi_real_time_async_async/hi.rb +++ b/examples/hi_real_time_async_async/hi.rb @@ -3,33 +3,35 @@ raise 'Missing ENV[SLACK_API_TOKENS]!' unless ENV.key?('SLACK_API_TOKENS') -Async::Reactor.run do - $stdout.sync = true - logger = Logger.new($stdout) - logger.level = Logger::DEBUG +$stdout.sync = true +logger = Logger.new($stdout) +logger.level = Logger::DEBUG - ENV['SLACK_API_TOKENS'].split.each do |token| - logger.info "Starting #{token[0..12]} ..." +threads = [] - client = Slack::RealTime::Client.new(token: token) +ENV['SLACK_API_TOKENS'].split.each do |token| + logger.info "Starting #{token[0..12]} ..." - client.on :hello do - logger.info "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." - end + client = Slack::RealTime::Client.new(token: token) - client.on :message do |data| - logger.info data + client.on :hello do + logger.info "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." + end - client.typing channel: data.channel + client.on :message do |data| + logger.info data - case data.text - when /hi/ then - client.message channel: data.channel, text: "Hi <@#{data.user}>!" - else - client.message channel: data.channel, text: "Sorry <@#{data.user}>, what?" - end - end + client.typing channel: data.channel - client.start_async + case data.text + when /hi/ then + client.message channel: data.channel, text: "Hi <@#{data.user}>!" + else + client.message channel: data.channel, text: "Sorry <@#{data.user}>, what?" + end end + + threads << client.start_async end + +threads.each(&:join) diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb index b01fb997..2f71c7fd 100644 --- a/lib/slack/real_time/concurrency/async.rb +++ b/lib/slack/real_time/concurrency/async.rb @@ -22,7 +22,6 @@ class Socket < Slack::RealTime::Socket def start_async(client) Thread.new do - $stderr.puts "start_async: @driver = #{@driver}" ::Async::Reactor.run do client.run_loop end @@ -30,11 +29,8 @@ def start_async(client) end def connect! - ::Async::Reactor.run do - super - - run_loop - end + super + run_loop end def close @@ -43,7 +39,7 @@ def close end def run_loop - while @driver and event = @driver.next_event + while @driver && @driver.next_event # $stderr.puts event.inspect end end @@ -64,10 +60,9 @@ def build_tcp_options def build_endpoint endpoint = ::Async::IO::Endpoint.tcp(addr, port, build_tcp_options) endpoint = ::Async::IO::SSLEndpoint.new(endpoint, build_ssl_context) if secure? - - return endpoint + endpoint end - + def connect @driver = Client.new(build_endpoint.connect, url) end From 93ceecab29fee48f23f4abe178ba44d0aeb1ccd4 Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 27 Aug 2018 13:31:55 +0200 Subject: [PATCH 04/10] Set SSL verify_mode to OpenSSL::SSL::VERIFY_PEER. --- .rubocop_todo.yml | 5 ++--- lib/slack/real_time/concurrency/async.rb | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a73f6302..a1ed6d15 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2018-08-27 13:21:41 +0200 using RuboCop version 0.58.2. +# on 2018-08-27 13:29:57 +0200 using RuboCop version 0.58.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -13,10 +13,9 @@ Lint/HandleExceptions: - 'spec/slack/real_time/concurrency/celluloid_spec.rb' - 'spec/slack/real_time/concurrency/eventmachine_spec.rb' -# Offense count: 2 +# Offense count: 1 Lint/UselessAssignment: Exclude: - - 'lib/slack/real_time/concurrency/async.rb' - 'lib/slack/real_time/config.rb' # Offense count: 1 diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb index 2f71c7fd..feee5a24 100644 --- a/lib/slack/real_time/concurrency/async.rb +++ b/lib/slack/real_time/concurrency/async.rb @@ -47,8 +47,9 @@ def run_loop protected def build_ssl_context - # TODO: context.set_params verify_mode: OpenSSL::SSL::VERIFY_PEER - { ssl_context: OpenSSL::SSL::SSLContext.new(:TLSv1_2_client) } + OpenSSL::SSL::SSLContext.new(:TLSv1_2_client).tap do |ctx| + ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER) + end end def build_tcp_options @@ -59,7 +60,7 @@ def build_tcp_options def build_endpoint endpoint = ::Async::IO::Endpoint.tcp(addr, port, build_tcp_options) - endpoint = ::Async::IO::SSLEndpoint.new(endpoint, build_ssl_context) if secure? + endpoint = ::Async::IO::SSLEndpoint.new(endpoint, ssl_context: build_ssl_context) if secure? endpoint end From a160ce34f0c9cd49f340a39c227faa2acdf6b1af Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 27 Aug 2018 13:34:12 +0200 Subject: [PATCH 05/10] Getting a of help from @ioquatix, added to CHANGELOG. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b95b9ab8..5e4cdebc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### 0.12.1 (Next) -* [#219](https://github.com/slack-ruby/slack-ruby-client/pull/219): Added support for `async-websocket`. - [@dblock](https://github.com/dblock). +* [#219](https://github.com/slack-ruby/slack-ruby-client/pull/219): Added support for `async-websocket` - [@dblock](https://github.com/dblock), [@ioquatix](https://github.com/ioquatix). * Your contribution here. ### 0.12.0 (8/20/2018) From 0fe8670efd3ddf138d6a2dd0ea1c57b44f90553f Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 27 Aug 2018 13:36:11 +0200 Subject: [PATCH 06/10] Removed TCP option, already set by default. --- lib/slack/real_time/concurrency/async.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb index feee5a24..766716fe 100644 --- a/lib/slack/real_time/concurrency/async.rb +++ b/lib/slack/real_time/concurrency/async.rb @@ -52,14 +52,8 @@ def build_ssl_context end end - def build_tcp_options - { - reuse_port: false - } - end - def build_endpoint - endpoint = ::Async::IO::Endpoint.tcp(addr, port, build_tcp_options) + endpoint = ::Async::IO::Endpoint.tcp(addr, port) endpoint = ::Async::IO::SSLEndpoint.new(endpoint, ssl_context: build_ssl_context) if secure? endpoint end From a8867bbf2ca6cb0662dc3e90dff45af7da53da9e Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 27 Aug 2018 13:43:38 +0200 Subject: [PATCH 07/10] Fix RuboCop, useless assignment. --- .rubocop_todo.yml | 5 ----- lib/slack/real_time/config.rb | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a1ed6d15..98935ead 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -13,11 +13,6 @@ Lint/HandleExceptions: - 'spec/slack/real_time/concurrency/celluloid_spec.rb' - 'spec/slack/real_time/concurrency/eventmachine_spec.rb' -# Offense count: 1 -Lint/UselessAssignment: - Exclude: - - 'lib/slack/real_time/config.rb' - # Offense count: 1 # Configuration parameters: EnforcedStyleForLeadingUnderscores. # SupportedStylesForLeadingUnderscores: disallowed, required, optional diff --git a/lib/slack/real_time/config.rb b/lib/slack/real_time/config.rb index 5e566b44..3e2d864c 100644 --- a/lib/slack/real_time/config.rb +++ b/lib/slack/real_time/config.rb @@ -39,7 +39,7 @@ def detect_concurrency %i[Async Eventmachine Celluloid].each do |concurrency| begin return Slack::RealTime::Concurrency.const_get(concurrency) - rescue LoadError, NameError => e + rescue LoadError, NameError false # could not be loaded, missing dependencies end end From d3140e90f2826162eacaef677505d171266f0173 Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 27 Aug 2018 13:52:16 +0200 Subject: [PATCH 08/10] Use def_delegators for text and binary. --- lib/slack/real_time/concurrency/async.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb index 766716fe..640361ed 100644 --- a/lib/slack/real_time/concurrency/async.rb +++ b/lib/slack/real_time/concurrency/async.rb @@ -6,15 +6,7 @@ module Concurrency module Async class Client < ::Async::WebSocket::Client extend ::Forwardable - def_delegators :@driver, :on - - def text(message) - @driver.text(message) - end - - def binary(data) - @driver.binary(data) - end + def_delegators :@driver, :on, :text, :binary end class Socket < Slack::RealTime::Socket From b1b681a362cf93fe8a1c8f175ec12ad22fb66dfa Mon Sep 17 00:00:00 2001 From: dblock Date: Tue, 28 Aug 2018 19:49:20 +0200 Subject: [PATCH 09/10] Attempt at fixing #198, potential race condition. --- spec/integration/integration_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/integration/integration_spec.rb b/spec/integration/integration_spec.rb index ae25537a..9be48158 100644 --- a/spec/integration/integration_spec.rb +++ b/spec/integration/integration_spec.rb @@ -74,6 +74,7 @@ def stop_server after do wait_for_server + connection.join end context 'client connected' do From 115942ec6781fa9fc3a9934440ba4ceac6b9b08f Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 3 Sep 2018 08:33:46 +0200 Subject: [PATCH 10/10] Close socket, terminate reactor, closes #222. --- lib/slack/real_time/concurrency/async.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/slack/real_time/concurrency/async.rb b/lib/slack/real_time/concurrency/async.rb index 640361ed..94649002 100644 --- a/lib/slack/real_time/concurrency/async.rb +++ b/lib/slack/real_time/concurrency/async.rb @@ -6,7 +6,7 @@ module Concurrency module Async class Client < ::Async::WebSocket::Client extend ::Forwardable - def_delegators :@driver, :on, :text, :binary + def_delegators :@driver, :on, :text, :binary, :emit end class Socket < Slack::RealTime::Socket @@ -26,11 +26,13 @@ def connect! end def close - @driver.close + @closing = true + @driver.close if @driver super end def run_loop + @closing = false while @driver && @driver.next_event # $stderr.puts event.inspect end @@ -50,8 +52,13 @@ def build_endpoint endpoint end + def connect_socket + build_endpoint.connect + end + def connect - @driver = Client.new(build_endpoint.connect, url) + @socket = connect_socket + @driver = Client.new(@socket, url) end end end