slack-ruby-client 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -1
  3. data/.rubocop_todo.yml +23 -6
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +11 -0
  6. data/Gemfile +2 -0
  7. data/README.md +89 -1
  8. data/RELEASING.md +3 -1
  9. data/UPGRADING.md +26 -0
  10. data/bin/commands.rb +20 -0
  11. data/bin/commands/api.rb +14 -0
  12. data/bin/commands/auth.rb +12 -0
  13. data/bin/commands/channels.rb +140 -0
  14. data/bin/commands/chat.rb +47 -0
  15. data/bin/commands/emoji.rb +12 -0
  16. data/bin/commands/files.rb +61 -0
  17. data/bin/commands/groups.rb +158 -0
  18. data/bin/commands/im.rb +53 -0
  19. data/bin/commands/mpim.rb +53 -0
  20. data/bin/commands/oauth.rb +16 -0
  21. data/bin/commands/pins.rb +37 -0
  22. data/bin/commands/reactions.rb +53 -0
  23. data/bin/commands/rtm.rb +15 -0
  24. data/bin/commands/search.rb +40 -0
  25. data/bin/commands/stars.rb +37 -0
  26. data/bin/commands/team.rb +32 -0
  27. data/bin/commands/usergroups.rb +73 -0
  28. data/bin/commands/users.rb +48 -0
  29. data/bin/slack +50 -0
  30. data/examples/hi_real_time/Gemfile +2 -0
  31. data/examples/hi_real_time_and_web/Gemfile +2 -0
  32. data/examples/hi_real_time_async/Gemfile +5 -0
  33. data/examples/hi_real_time_async/hi.rb +29 -0
  34. data/lib/slack-ruby-client.rb +2 -2
  35. data/lib/slack/real_time/client.rb +72 -30
  36. data/lib/slack/real_time/concurrency.rb +8 -0
  37. data/lib/slack/real_time/concurrency/celluloid.rb +92 -0
  38. data/lib/slack/real_time/concurrency/eventmachine.rb +39 -0
  39. data/lib/slack/real_time/config.rb +23 -1
  40. data/lib/slack/real_time/socket.rb +50 -12
  41. data/lib/slack/version.rb +1 -1
  42. data/lib/slack/web/api/endpoints.rb +2 -0
  43. data/lib/slack/web/api/endpoints/groups.rb +1 -1
  44. data/lib/slack/web/api/endpoints/team.rb +1 -1
  45. data/lib/slack/web/api/endpoints/usergroups.rb +113 -0
  46. data/lib/slack/web/api/error.rb +6 -0
  47. data/lib/slack/web/api/schema/group.json +14 -0
  48. data/lib/slack/web/api/tasks/generate.rake +19 -3
  49. data/lib/slack/web/api/templates/command.erb +34 -0
  50. data/lib/slack/web/api/templates/commands.erb +5 -0
  51. data/lib/slack/web/config.rb +2 -0
  52. data/lib/slack/web/faraday/connection.rb +3 -2
  53. data/lib/slack/web/faraday/response/raise_error.rb +2 -1
  54. data/slack-ruby-client.gemspec +4 -2
  55. data/spec/fixtures/slack/web/429_error.yml +83 -0
  56. data/spec/fixtures/slack/web/rtm_start.yml +1 -1
  57. data/spec/fixtures/slack/web/users_list.yml +72 -0
  58. data/spec/integration/integration_spec.rb +88 -0
  59. data/spec/slack/real_time/client_spec.rb +8 -5
  60. data/spec/slack/real_time/concurrency/celluloid_spec.rb +58 -0
  61. data/spec/slack/real_time/concurrency/eventmachine_spec.rb +49 -0
  62. data/spec/slack/slack_spec.rb +52 -0
  63. data/spec/slack/web/api/endpoints/auth_spec.rb +6 -1
  64. data/spec/slack/web/api/endpoints/users_spec.rb +13 -0
  65. data/spec/slack/web/api/error_spec.rb +14 -0
  66. data/spec/slack/web/client_spec.rb +16 -0
  67. data/spec/support/real_time/concurrency/mock.rb +31 -0
  68. data/spec/support/real_time/connected_client.rb +5 -2
  69. metadata +55 -8
  70. data/spec/slack/real_time/socket_spec.rb +0 -46
@@ -0,0 +1,15 @@
1
+ # This file was auto-generated by lib/slack/web/api/tasks/generate.rake
2
+
3
+ desc 'Rtm methods.'
4
+ command 'rtm' do |g|
5
+ g.desc 'This method starts a Real Time Messaging API session. Refer to the'
6
+ g.long_desc %( This method starts a Real Time Messaging API session. Refer to the RTM API documentation for full details on how to use the RTM API. )
7
+ g.command 'start' do |c|
8
+ c.flag 'simple_latest', desc: 'Return timestamp only for latest message object of each channel (improves performance).'
9
+ c.flag 'no_unreads', desc: 'Skip unread counts for each channel (improves performance).'
10
+ c.flag 'mpim_aware', desc: 'Returns MPIMs to the client in the API response.'
11
+ c.action do |_global_options, options, _args|
12
+ puts JSON.dump($client.rtm_start(options))
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,40 @@
1
+ # This file was auto-generated by lib/slack/web/api/tasks/generate.rake
2
+
3
+ desc "Search your team's files and messages."
4
+ command 'search' do |g|
5
+ g.desc 'This method allows to to search both messages and files in a single call.'
6
+ g.long_desc %( This method allows to to search both messages and files in a single call. )
7
+ g.command 'all' do |c|
8
+ c.flag 'query', desc: 'Search query. May contains booleans, etc.'
9
+ c.flag 'sort', desc: 'Return matches sorted by either score or timestamp.'
10
+ c.flag 'sort_dir', desc: 'Change sort direction to ascending (asc) or descending (desc).'
11
+ c.flag 'highlight', desc: 'Pass a value of 1 to enable query highlight markers (see below).'
12
+ c.action do |_global_options, options, _args|
13
+ puts JSON.dump($client.search_all(options))
14
+ end
15
+ end
16
+
17
+ g.desc 'This method returns files matching a search query.'
18
+ g.long_desc %( This method returns files matching a search query. )
19
+ g.command 'files' do |c|
20
+ c.flag 'query', desc: 'Search query. May contain booleans, etc.'
21
+ c.flag 'sort', desc: 'Return matches sorted by either score or timestamp.'
22
+ c.flag 'sort_dir', desc: 'Change sort direction to ascending (asc) or descending (desc).'
23
+ c.flag 'highlight', desc: 'Pass a value of 1 to enable query highlight markers (see below).'
24
+ c.action do |_global_options, options, _args|
25
+ puts JSON.dump($client.search_files(options))
26
+ end
27
+ end
28
+
29
+ g.desc 'This method returns messages matching a search query.'
30
+ g.long_desc %( This method returns messages matching a search query. )
31
+ g.command 'messages' do |c|
32
+ c.flag 'query', desc: 'Search query. May contains booleans, etc.'
33
+ c.flag 'sort', desc: 'Return matches sorted by either score or timestamp.'
34
+ c.flag 'sort_dir', desc: 'Change sort direction to ascending (asc) or descending (desc).'
35
+ c.flag 'highlight', desc: 'Pass a value of 1 to enable query highlight markers (see below).'
36
+ c.action do |_global_options, options, _args|
37
+ puts JSON.dump($client.search_messages(options))
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ # This file was auto-generated by lib/slack/web/api/tasks/generate.rake
2
+
3
+ desc 'Stars methods.'
4
+ command 'stars' do |g|
5
+ g.desc 'This method adds a star to an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user.'
6
+ g.long_desc %( This method adds a star to an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user. One of file, file_comment, channel, or the combination of channel and timestamp must be specified. )
7
+ g.command 'add' do |c|
8
+ c.flag 'file', desc: 'File to add star to.'
9
+ c.flag 'file_comment', desc: 'File comment to add star to.'
10
+ c.flag 'channel', desc: 'Channel to add star to, or channel where the message to add star to was posted (used with timestamp).'
11
+ c.flag 'timestamp', desc: 'Timestamp of the message to add star to.'
12
+ c.action do |_global_options, options, _args|
13
+ puts JSON.dump($client.stars_add(options))
14
+ end
15
+ end
16
+
17
+ g.desc 'This method lists the items starred by a user.'
18
+ g.long_desc %( This method lists the items starred by a user. )
19
+ g.command 'list' do |c|
20
+ c.flag 'user', desc: 'Show stars by this user. Defaults to the authed user.'
21
+ c.action do |_global_options, options, _args|
22
+ puts JSON.dump($client.stars_list(options))
23
+ end
24
+ end
25
+
26
+ g.desc 'This method removes a star from an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user.'
27
+ g.long_desc %( This method removes a star from an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user. One of file, file_comment, channel, or the combination of channel and timestamp must be specified. )
28
+ g.command 'remove' do |c|
29
+ c.flag 'file', desc: 'File to remove star from.'
30
+ c.flag 'file_comment', desc: 'File comment to remove star from.'
31
+ c.flag 'channel', desc: 'Channel to remove star from, or channel where the message to remove star from was posted (used with timestamp).'
32
+ c.flag 'timestamp', desc: 'Timestamp of the message to remove star from.'
33
+ c.action do |_global_options, options, _args|
34
+ puts JSON.dump($client.stars_remove(options))
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ # This file was auto-generated by lib/slack/web/api/tasks/generate.rake
2
+
3
+ desc 'Team methods.'
4
+ command 'team' do |g|
5
+ g.desc 'This method is used to get the access logs for users on a team.'
6
+ g.long_desc %( This method is used to get the access logs for users on a team. )
7
+ g.command 'accessLogs' do |c|
8
+ c.action do |_global_options, options, _args|
9
+ puts JSON.dump($client.team_accessLogs(options))
10
+ end
11
+ end
12
+
13
+ g.desc 'This method provides information about your team.'
14
+ g.long_desc %( This method provides information about your team. )
15
+ g.command 'info' do |c|
16
+ c.action do |_global_options, options, _args|
17
+ puts JSON.dump($client.team_info(options))
18
+ end
19
+ end
20
+
21
+ g.desc 'This method lists the integration activity logs for a team, including when integrations are added, modified and removed. This method can only be called by Admins.'
22
+ g.long_desc %( This method lists the integration activity logs for a team, including when integrations are added, modified and removed. This method can only be called by Admins. )
23
+ g.command 'integrationLogs' do |c|
24
+ c.flag 'service_id', desc: 'Filter logs to this service. Defaults to all logs.'
25
+ c.flag 'app_id', desc: 'Filter logs to this API application. Defaults to all logs.'
26
+ c.flag 'user', desc: "Filter logs generated by this user's actions. Defaults to all logs."
27
+ c.flag 'change_type', desc: 'Filter logs with this change type. Defaults to all logs.'
28
+ c.action do |_global_options, options, _args|
29
+ puts JSON.dump($client.team_integrationLogs(options))
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,73 @@
1
+ # This file was auto-generated by lib/slack/web/api/tasks/generate.rake
2
+
3
+ desc "Get info on your team's user groups."
4
+ command 'usergroups' do |g|
5
+ g.desc 'This method is used to create a user group.'
6
+ g.long_desc %( This method is used to create a user group. )
7
+ g.command 'create' do |c|
8
+ c.flag 'name', desc: 'A name for the user group. Must be unique among user groups.'
9
+ c.flag 'handle', desc: 'A mention handle. Must be unique among channels, users and user groups.'
10
+ c.flag 'description', desc: 'A short description of the user group.'
11
+ c.flag 'channels', desc: 'A comma separated string of encoded channel IDs for which the user group uses as a default.'
12
+ c.flag 'include_count', desc: 'Include the number of users in each user group.'
13
+ c.action do |_global_options, options, _args|
14
+ puts JSON.dump($client.usergroups_create(options))
15
+ end
16
+ end
17
+
18
+ g.desc 'This method disables an existing user group.'
19
+ g.long_desc %( This method disables an existing user group. )
20
+ g.command 'disable' do |c|
21
+ c.flag 'usergroup', desc: 'The encoded ID of the user group to disable.'
22
+ c.flag 'include_count', desc: 'Include the number of users in the user group.'
23
+ c.action do |_global_options, options, _args|
24
+ puts JSON.dump($client.usergroups_disable(options))
25
+ end
26
+ end
27
+
28
+ g.desc 'This method enables a user group which was previously disabled.'
29
+ g.long_desc %( This method enables a user group which was previously disabled. )
30
+ g.command 'enable' do |c|
31
+ c.flag 'usergroup', desc: 'The encoded ID of the user group to enable.'
32
+ c.flag 'include_count', desc: 'Include the number of users in the user group.'
33
+ c.action do |_global_options, options, _args|
34
+ puts JSON.dump($client.usergroups_enable(options))
35
+ end
36
+ end
37
+
38
+ g.desc 'This method returns a list of all user groups in the team. This can optionally include disabled user groups.'
39
+ g.long_desc %( This method returns a list of all user groups in the team. This can optionally include disabled user groups. )
40
+ g.command 'list' do |c|
41
+ c.flag 'include_disabled', desc: 'Include disabled user groups.'
42
+ c.flag 'include_count', desc: 'Include the number of users in each user group.'
43
+ c.flag 'include_users', desc: 'Include the list of users for each user group.'
44
+ c.action do |_global_options, options, _args|
45
+ puts JSON.dump($client.usergroups_list(options))
46
+ end
47
+ end
48
+
49
+ g.desc 'This method updates the properties of an existing user group.'
50
+ g.long_desc %( This method updates the properties of an existing user group. )
51
+ g.command 'update' do |c|
52
+ c.flag 'usergroup', desc: 'The encoded ID of the user group to update.'
53
+ c.flag 'name', desc: 'A name for the user group. Must be unique among user groups.'
54
+ c.flag 'handle', desc: 'A mention handle. Must be unique among channels, users and user groups.'
55
+ c.flag 'description', desc: 'A short description of the user group.'
56
+ c.flag 'channels', desc: 'A comma separated string of encoded channel IDs for which the user group uses as a default.'
57
+ c.flag 'include_count', desc: 'Include the number of users in the user group.'
58
+ c.action do |_global_options, options, _args|
59
+ puts JSON.dump($client.usergroups_update(options))
60
+ end
61
+ end
62
+
63
+ g.desc 'This method updates the list of users that belong to a user group. This method replaces all users in a user group with the list of users provided in the users parameter.'
64
+ g.long_desc %( This method updates the list of users that belong to a user group. This method replaces all users in a user group with the list of users provided in the users parameter. )
65
+ g.command 'users' do |c|
66
+ c.flag 'usergroup', desc: 'The encoded ID of the user group to update.'
67
+ c.flag 'users', desc: 'A comma separated string of encoded user IDs that represent the entire list of users for the user group.'
68
+ c.flag 'include_count', desc: 'Include the number of users in the user group.'
69
+ c.action do |_global_options, options, _args|
70
+ puts JSON.dump($client.usergroups_users(options))
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,48 @@
1
+ # This file was auto-generated by lib/slack/web/api/tasks/generate.rake
2
+
3
+ desc 'Get info on members of your Slack team.'
4
+ command 'users' do |g|
5
+ g.desc "This method lets you find out information about a user's presence."
6
+ g.long_desc %( This method lets you find out information about a user's presence. Consult the presence documentation for more details. )
7
+ g.command 'getPresence' do |c|
8
+ c.flag 'user', desc: 'User to get presence info on. Defaults to the authed user.'
9
+ c.action do |_global_options, options, _args|
10
+ puts JSON.dump($client.users_getPresence(options))
11
+ end
12
+ end
13
+
14
+ g.desc 'This method returns information about a team member.'
15
+ g.long_desc %( This method returns information about a team member. )
16
+ g.command 'info' do |c|
17
+ c.flag 'user', desc: 'User to get info on.'
18
+ c.action do |_global_options, options, _args|
19
+ puts JSON.dump($client.users_info(options))
20
+ end
21
+ end
22
+
23
+ g.desc 'This method returns a list of all users in the team. This includes deleted/deactivated users.'
24
+ g.long_desc %( This method returns a list of all users in the team. This includes deleted/deactivated users. )
25
+ g.command 'list' do |c|
26
+ c.flag 'presence', desc: 'Whether to include presence data in the output.'
27
+ c.action do |_global_options, options, _args|
28
+ puts JSON.dump($client.users_list(options))
29
+ end
30
+ end
31
+
32
+ g.desc 'This method lets the slack messaging server know that the authenticated user'
33
+ g.long_desc %( This method lets the slack messaging server know that the authenticated user is currently active. Consult the presence documentation for more details. )
34
+ g.command 'setActive' do |c|
35
+ c.action do |_global_options, options, _args|
36
+ puts JSON.dump($client.users_setActive(options))
37
+ end
38
+ end
39
+
40
+ g.desc "This method lets you set the calling user's manual presence."
41
+ g.long_desc %( This method lets you set the calling user's manual presence. Consult the presence documentation for more details. )
42
+ g.command 'setPresence' do |c|
43
+ c.flag 'presence', desc: 'Either auto or away.'
44
+ c.action do |_global_options, options, _args|
45
+ puts JSON.dump($client.users_setPresence(options))
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gli'
4
+ require 'slack-ruby-client'
5
+
6
+ include GLI::App
7
+
8
+ program_desc 'Slack client.'
9
+
10
+ default_command :help
11
+
12
+ switch [:d, :debug], desc: 'Enable debug-level logging.', default_value: false
13
+ flag [:t, 'slack-api-token'], desc: 'Slack API token.', default_value: ENV['SLACK_API_TOKEN']
14
+ flag ['vcr-cassette-name'], desc: 'Offline VCR cassette.'
15
+
16
+ pre do |global_options, _command, options, _args|
17
+ # global Slack configuration
18
+ Slack.config.token = global_options['slack-api-token']
19
+ help_now! 'Set Slack API token via --slack-api-token or SLACK_API_TOKEN.' unless Slack.config.token && Slack.config.token.length > 0
20
+
21
+ if global_options['debug']
22
+ require 'logger'
23
+ logger = Logger.new(STDOUT)
24
+ logger.level = Logger::DEBUG
25
+ Slack::Web::Client.config.logger = logger
26
+ end
27
+
28
+ $client = Slack::Web::Client.new
29
+
30
+ # Offline VCR cassette
31
+ if global_options['vcr-cassette-name']
32
+ require 'vcr'
33
+ VCR.configure do |config|
34
+ config.cassette_library_dir = 'spec/fixtures/slack'
35
+ config.hook_into :webmock
36
+ config.default_cassette_options = { record: :new_episodes }
37
+ end
38
+ VCR.insert_cassette global_options['vcr-cassette-name']
39
+ end
40
+
41
+ # remove any nil values from options
42
+ options.select! { |_k, v| v }
43
+
44
+ true
45
+ end
46
+
47
+ $LOAD_PATH.push File.expand_path('..', __FILE__)
48
+ require 'commands'
49
+
50
+ exit run(ARGV)
@@ -1,3 +1,5 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  gem 'slack-ruby-client', path: '../..'
4
+
5
+ gem 'celluloid-io'
@@ -1,3 +1,5 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  gem 'slack-ruby-client', path: '../..'
4
+
5
+ gem 'faye-websocket'
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'slack-ruby-client', path: '../..'
4
+
5
+ gem 'faye-websocket'
@@ -0,0 +1,29 @@
1
+ require 'slack-ruby-client'
2
+
3
+ Slack.configure do |config|
4
+ config.token = ENV['SLACK_API_TOKEN']
5
+ fail 'Missing ENV[SLACK_API_TOKEN]!' unless config.token
6
+ end
7
+
8
+ client = Slack::RealTime::Client.new
9
+
10
+ client.on :hello do
11
+ puts "Successfully connected, welcome '#{client.self['name']}' to the '#{client.team['name']}' team at https://#{client.team['domain']}.slack.com."
12
+ end
13
+
14
+ client.on :message do |data|
15
+ puts data
16
+
17
+ client.typing channel: data['channel']
18
+
19
+ case data['text']
20
+ when 'bot hi' then
21
+ client.message channel: data['channel'], text: "Hi <@#{data['user']}>!"
22
+ when /^bot/ then
23
+ client.message channel: data['channel'], text: "Sorry <@#{data['user']}>, what?"
24
+ end
25
+ end
26
+
27
+ EM.run do
28
+ client.start_async
29
+ end
@@ -5,6 +5,7 @@ require 'slack/config'
5
5
  require 'faraday'
6
6
  require 'faraday_middleware'
7
7
  require 'json'
8
+ require 'logger'
8
9
  require 'slack/web/config'
9
10
  require 'slack/web/api/error'
10
11
  require 'slack/web/faraday/response/raise_error'
@@ -14,8 +15,7 @@ require 'slack/web/api/endpoints'
14
15
  require 'slack/web/client'
15
16
 
16
17
  # RealTime API
17
- require 'faye/websocket'
18
- require 'eventmachine'
18
+ require 'slack/real_time/concurrency'
19
19
  require 'slack/real_time/socket'
20
20
  require 'slack/real_time/api/message_id'
21
21
  require 'slack/real_time/api/ping'
@@ -13,7 +13,7 @@ module Slack
13
13
  attr_accessor(*Config::ATTRIBUTES)
14
14
 
15
15
  def initialize(options = {})
16
- @callbacks = {}
16
+ @callbacks = Hash.new { |h, k| h[k] = [] }
17
17
  Slack::RealTime::Config::ATTRIBUTES.each do |key|
18
18
  send("#{key}=", options[key] || Slack::RealTime.config.send(key))
19
19
  end
@@ -29,34 +29,22 @@ module Slack
29
29
 
30
30
  def on(type, &block)
31
31
  type = type.to_s
32
- @callbacks[type] ||= []
33
- @callbacks[type] << block
32
+ callbacks[type] << block
34
33
  end
35
34
 
36
- def start!
37
- fail ClientAlreadyStartedError if started?
38
- EM.run do
39
- @options = web_client.rtm_start
40
-
41
- socket_options = {}
42
- socket_options[:ping] = websocket_ping if websocket_ping
43
- socket_options[:proxy] = websocket_proxy if websocket_proxy
44
- @socket = Slack::RealTime::Socket.new(@options['url'], socket_options)
45
-
46
- @socket.connect! do |ws|
47
- ws.on :open do |event|
48
- open(event)
49
- end
50
-
51
- ws.on :message do |event|
52
- dispatch(event)
53
- end
54
-
55
- ws.on :close do |event|
56
- close(event)
57
- end
58
- end
59
- end
35
+ # Start RealTime client and block until it disconnects.
36
+ # @yieldparam [Websocket::Driver] driver
37
+ def start!(&block)
38
+ socket = build_socket
39
+ socket.start_sync { run_loop(socket, &block) }
40
+ end
41
+
42
+ # Start RealTime client and return immediately.
43
+ # The RealTime::Client will run in the background.
44
+ # @yieldparam [Websocket::Driver] driver
45
+ def start_async(&block)
46
+ socket = build_socket
47
+ socket.start_async { run_loop(socket, &block) }
60
48
  end
61
49
 
62
50
  def stop!
@@ -70,7 +58,7 @@ module Slack
70
58
 
71
59
  class << self
72
60
  def configure
73
- block_given? ? yield(Config) : Config
61
+ block_given? ? yield(config) : config
74
62
  end
75
63
 
76
64
  def config
@@ -80,6 +68,48 @@ module Slack
80
68
 
81
69
  protected
82
70
 
71
+ # @return [Slack::RealTime::Socket]
72
+ def build_socket
73
+ fail ClientAlreadyStartedError if started?
74
+ @options = web_client.rtm_start
75
+
76
+ socket_class.new(@options.fetch('url'), socket_options)
77
+ end
78
+
79
+ def socket_options
80
+ socket_options = {}
81
+ socket_options[:ping] = websocket_ping if websocket_ping
82
+ socket_options[:proxy] = websocket_proxy if websocket_proxy
83
+ socket_options
84
+ end
85
+
86
+ def run_loop(socket)
87
+ @socket = socket
88
+
89
+ @socket.connect! do |driver|
90
+ yield driver if block_given?
91
+
92
+ driver.on :open do |event|
93
+ open(event)
94
+ callback(event, :open)
95
+ end
96
+
97
+ driver.on :message do |event|
98
+ dispatch(event)
99
+ end
100
+
101
+ driver.on :close do |event|
102
+ callback(event, :close)
103
+ close(event)
104
+ end
105
+ end
106
+ end
107
+
108
+ attr_reader :callbacks
109
+ def socket_class
110
+ concurrency::Socket
111
+ end
112
+
83
113
  def send_json(data)
84
114
  fail ClientNotStartedError unless started?
85
115
  @socket.send_data(data.to_json)
@@ -89,8 +119,20 @@ module Slack
89
119
  end
90
120
 
91
121
  def close(_event)
122
+ socket = @socket
92
123
  @socket = nil
93
- EM.stop
124
+
125
+ [socket, socket_class].each do |s|
126
+ s.close if s.respond_to?(:close)
127
+ end
128
+ end
129
+
130
+ def callback(event, type)
131
+ callbacks = self.callbacks[type.to_s]
132
+ return false unless callbacks
133
+ callbacks.each do |c|
134
+ c.call(event)
135
+ end
94
136
  end
95
137
 
96
138
  def dispatch(event)
@@ -98,7 +140,7 @@ module Slack
98
140
  data = JSON.parse(event.data)
99
141
  type = data['type']
100
142
  return false unless type
101
- callbacks = @callbacks[type.to_s]
143
+ callbacks = self.callbacks[type.to_s]
102
144
  return false unless callbacks
103
145
  callbacks.each do |c|
104
146
  c.call(data)