Navigation Menu

Skip to content

Commit

Permalink
Merge pull request #219 from dblock/async
Browse files Browse the repository at this point in the history
Added support for async-websocket.
  • Loading branch information
dblock committed Sep 7, 2018
2 parents b4daa51 + 115942e commit adf9672
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
@@ -1,6 +1,6 @@
# 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-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
Expand Down
2 changes: 2 additions & 0 deletions .travis.yml
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions 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), [@ioquatix](https://github.com/ioquatix).
* Your contribution here.

### 0.12.0 (8/20/2018)
Expand Down
19 changes: 14 additions & 5 deletions README.md
Expand Up @@ -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`.
Expand Down Expand Up @@ -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
```

Expand All @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions 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
Expand Down
6 changes: 6 additions & 0 deletions 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'
2 changes: 2 additions & 0 deletions examples/hi_real_time_async_async/Procfile
@@ -0,0 +1,2 @@
console: bundle exec ruby hi.rb

37 changes: 37 additions & 0 deletions examples/hi_real_time_async_async/hi.rb
@@ -0,0 +1,37 @@
require 'slack-ruby-client'
require 'async'

raise 'Missing ENV[SLACK_API_TOKENS]!' unless ENV.key?('SLACK_API_TOKENS')

$stdout.sync = true
logger = Logger.new($stdout)
logger.level = Logger::DEBUG

threads = []

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

threads << client.start_async
end

threads.each(&:join)
1 change: 1 addition & 0 deletions 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
Expand Down
67 changes: 67 additions & 0 deletions lib/slack/real_time/concurrency/async.rb
@@ -0,0 +1,67 @@
require 'async/websocket'

module Slack
module RealTime
module Concurrency
module Async
class Client < ::Async::WebSocket::Client
extend ::Forwardable
def_delegators :@driver, :on, :text, :binary, :emit
end

class Socket < Slack::RealTime::Socket
attr_reader :client

def start_async(client)
Thread.new do
::Async::Reactor.run do
client.run_loop
end
end
end

def connect!
super
run_loop
end

def close
@closing = true
@driver.close if @driver
super
end

def run_loop
@closing = false
while @driver && @driver.next_event
# $stderr.puts event.inspect
end
end

protected

def build_ssl_context
OpenSSL::SSL::SSLContext.new(:TLSv1_2_client).tap do |ctx|
ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
end
end

def build_endpoint
endpoint = ::Async::IO::Endpoint.tcp(addr, port)
endpoint = ::Async::IO::SSLEndpoint.new(endpoint, ssl_context: build_ssl_context) if secure?
endpoint
end

def connect_socket
build_endpoint.connect
end

def connect
@socket = connect_socket
@driver = Client.new(@socket, url)
end
end
end
end
end
end
4 changes: 2 additions & 2 deletions lib/slack/real_time/config.rb
Expand Up @@ -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
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

Expand Down
1 change: 1 addition & 0 deletions spec/integration/integration_spec.rb
Expand Up @@ -74,6 +74,7 @@ def stop_server

after do
wait_for_server
connection.join
end

context 'client connected' do
Expand Down

0 comments on commit adf9672

Please sign in to comment.