slack-ruby-client 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)