slack-ruby-client 0.7.9 → 0.16.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.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +32 -1
- data/.rubocop_todo.yml +98 -49
- data/.travis.yml +10 -14
- data/CHANGELOG.md +172 -24
- data/CONTRIBUTING.md +17 -6
- data/Dangerfile +2 -0
- data/Gemfile +10 -4
- data/LICENSE.md +1 -1
- data/README.md +276 -54
- data/RELEASING.md +19 -11
- data/Rakefile +2 -1
- data/UPGRADING.md +84 -2
- data/bin/commands.rb +43 -1
- data/bin/commands/admin_analytics.rb +15 -0
- data/bin/commands/admin_apps.rb +40 -0
- data/bin/commands/admin_apps_approved.rb +17 -0
- data/bin/commands/admin_apps_requests.rb +16 -0
- data/bin/commands/admin_apps_restricted.rb +17 -0
- data/bin/commands/admin_barriers.rb +47 -0
- data/bin/commands/admin_conversations.rb +169 -0
- data/bin/commands/admin_conversations_ekm.rb +17 -0
- data/bin/commands/admin_conversations_restrictAccess.rb +37 -0
- data/bin/commands/admin_conversations_whitelist.rb +37 -0
- data/bin/commands/admin_emoji.rb +54 -0
- data/bin/commands/admin_inviteRequests.rb +36 -0
- data/bin/commands/admin_inviteRequests_approved.rb +16 -0
- data/bin/commands/admin_inviteRequests_denied.rb +16 -0
- data/bin/commands/admin_teams.rb +27 -0
- data/bin/commands/admin_teams_admins.rb +16 -0
- data/bin/commands/admin_teams_owners.rb +16 -0
- data/bin/commands/admin_teams_settings.rb +64 -0
- data/bin/commands/admin_usergroups.rb +48 -0
- data/bin/commands/admin_users.rb +97 -0
- data/bin/commands/admin_users_session.rb +38 -0
- data/bin/commands/api.rb +3 -3
- data/bin/commands/apps.rb +15 -0
- data/bin/commands/apps_connections.rb +13 -0
- data/bin/commands/apps_event_authorizations.rb +16 -0
- data/bin/commands/apps_permissions.rb +23 -0
- data/bin/commands/apps_permissions_resources.rb +15 -0
- data/bin/commands/apps_permissions_scopes.rb +13 -0
- data/bin/commands/apps_permissions_users.rb +26 -0
- data/bin/commands/auth.rb +5 -4
- data/bin/commands/auth_teams.rb +16 -0
- data/bin/commands/bots.rb +4 -2
- data/bin/commands/calls.rb +52 -0
- data/bin/commands/calls_participants.rb +25 -0
- data/bin/commands/channels.rb +64 -43
- data/bin/commands/chat.rb +114 -24
- data/bin/commands/chat_scheduledMessages.rb +19 -0
- data/bin/commands/conversations.rb +196 -0
- data/bin/commands/dialog.rb +15 -0
- data/bin/commands/dnd.rb +9 -8
- data/bin/commands/emoji.rb +3 -2
- data/bin/commands/files.rb +45 -30
- data/bin/commands/files_comments.rb +3 -24
- data/bin/commands/files_remote.rb +78 -0
- data/bin/commands/groups.rb +53 -53
- data/bin/commands/im.rb +17 -13
- data/bin/commands/migration.rb +16 -0
- data/bin/commands/mpim.rb +16 -13
- data/bin/commands/oauth.rb +17 -2
- data/bin/commands/oauth_v2.rb +17 -0
- data/bin/commands/pins.rb +7 -10
- data/bin/commands/reactions.rb +17 -15
- data/bin/commands/reminders.rb +11 -10
- data/bin/commands/rtm.rb +19 -4
- data/bin/commands/search.rb +15 -11
- data/bin/commands/stars.rb +11 -8
- data/bin/commands/team.rb +15 -10
- data/bin/commands/team_profile.rb +3 -2
- data/bin/commands/usergroups.rb +22 -16
- data/bin/commands/usergroups_users.rb +7 -4
- data/bin/commands/users.rb +65 -37
- data/bin/commands/users_admin.rb +29 -0
- data/bin/commands/users_prefs.rb +13 -0
- data/bin/commands/users_profile.rb +8 -7
- data/bin/commands/views.rb +48 -0
- data/bin/commands/workflows.rb +38 -0
- data/bin/slack +3 -4
- data/examples/hi_real_time_and_web/Gemfile +1 -0
- data/examples/hi_real_time_and_web/hi.rb +8 -4
- data/examples/{hi_real_time_async_eventmachine → hi_real_time_async_async}/Gemfile +2 -1
- data/examples/{hi_real_time_async_celluloid → hi_real_time_async_async}/Procfile +0 -0
- data/examples/{hi_real_time_async_celluloid → hi_real_time_async_async}/hi.rb +13 -8
- data/examples/hi_web/Gemfile +1 -0
- data/examples/hi_web/hi.rb +2 -1
- data/examples/new_ticket/Gemfile +1 -0
- data/examples/new_ticket/new_ticket.rb +2 -1
- data/lib/slack-ruby-client.rb +40 -26
- data/lib/slack.rb +1 -0
- data/lib/slack/config.rb +1 -0
- data/lib/slack/events/config.rb +32 -0
- data/lib/slack/events/request.rb +70 -0
- data/lib/slack/logger.rb +6 -5
- data/lib/slack/messages/formatting.rb +4 -4
- data/lib/slack/messages/message.rb +2 -6
- data/lib/slack/real_time/api/message.rb +3 -1
- data/lib/slack/real_time/api/message_id.rb +1 -0
- data/lib/slack/real_time/api/ping.rb +5 -2
- data/lib/slack/real_time/api/templates/event_handler.erb +1 -1
- data/lib/slack/real_time/api/typing.rb +3 -1
- data/lib/slack/real_time/client.rb +113 -32
- data/lib/slack/real_time/concurrency.rb +2 -2
- data/lib/slack/real_time/concurrency/async.rb +140 -0
- data/lib/slack/real_time/config.rb +20 -12
- data/lib/slack/real_time/models.rb +8 -7
- data/lib/slack/real_time/models/base.rb +2 -6
- data/lib/slack/real_time/models/bot.rb +1 -0
- data/lib/slack/real_time/models/channel.rb +1 -0
- data/lib/slack/real_time/models/group.rb +1 -0
- data/lib/slack/real_time/models/im.rb +1 -0
- data/lib/slack/real_time/models/team.rb +1 -0
- data/lib/slack/real_time/models/user.rb +1 -0
- data/lib/slack/real_time/socket.rb +46 -17
- data/lib/slack/real_time/stores.rb +4 -3
- data/lib/slack/real_time/stores/base.rb +5 -3
- data/lib/slack/real_time/stores/starter.rb +113 -72
- data/lib/slack/real_time/stores/store.rb +131 -88
- data/lib/slack/version.rb +2 -1
- data/lib/slack/web/api/endpoints.rb +110 -26
- data/lib/slack/web/api/endpoints/admin_analytics.rb +26 -0
- data/lib/slack/web/api/endpoints/admin_apps.rb +62 -0
- data/lib/slack/web/api/endpoints/admin_apps_approved.rb +35 -0
- data/lib/slack/web/api/endpoints/admin_apps_requests.rb +33 -0
- data/lib/slack/web/api/endpoints/admin_apps_restricted.rb +35 -0
- data/lib/slack/web/api/endpoints/admin_barriers.rb +82 -0
- data/lib/slack/web/api/endpoints/admin_conversations.rb +260 -0
- data/lib/slack/web/api/endpoints/admin_conversations_ekm.rb +35 -0
- data/lib/slack/web/api/endpoints/admin_conversations_restrictAccess.rb +61 -0
- data/lib/slack/web/api/endpoints/admin_conversations_whitelist.rb +64 -0
- data/lib/slack/web/api/endpoints/admin_emoji.rb +88 -0
- data/lib/slack/web/api/endpoints/admin_inviteRequests.rb +61 -0
- data/lib/slack/web/api/endpoints/admin_inviteRequests_approved.rb +33 -0
- data/lib/slack/web/api/endpoints/admin_inviteRequests_denied.rb +33 -0
- data/lib/slack/web/api/endpoints/admin_teams.rb +50 -0
- data/lib/slack/web/api/endpoints/admin_teams_admins.rb +34 -0
- data/lib/slack/web/api/endpoints/admin_teams_owners.rb +34 -0
- data/lib/slack/web/api/endpoints/admin_teams_settings.rb +99 -0
- data/lib/slack/web/api/endpoints/admin_usergroups.rb +77 -0
- data/lib/slack/web/api/endpoints/admin_users.rb +161 -0
- data/lib/slack/web/api/endpoints/admin_users_session.rb +66 -0
- data/lib/slack/web/api/endpoints/api.rb +3 -4
- data/lib/slack/web/api/endpoints/apps.rb +27 -0
- data/lib/slack/web/api/endpoints/apps_connections.rb +21 -0
- data/lib/slack/web/api/endpoints/apps_event_authorizations.rb +34 -0
- data/lib/slack/web/api/endpoints/apps_permissions.rb +36 -0
- data/lib/slack/web/api/endpoints/apps_permissions_resources.rb +31 -0
- data/lib/slack/web/api/endpoints/apps_permissions_scopes.rb +21 -0
- data/lib/slack/web/api/endpoints/apps_permissions_users.rb +50 -0
- data/lib/slack/web/api/endpoints/auth.rb +5 -4
- data/lib/slack/web/api/endpoints/auth_teams.rb +33 -0
- data/lib/slack/web/api/endpoints/bots.rb +5 -2
- data/lib/slack/web/api/endpoints/calls.rb +83 -0
- data/lib/slack/web/api/endpoints/calls_participants.rb +42 -0
- data/lib/slack/web/api/endpoints/channels.rb +105 -49
- data/lib/slack/web/api/endpoints/chat.rb +221 -40
- data/lib/slack/web/api/endpoints/chat_scheduledMessages.rb +40 -0
- data/lib/slack/web/api/endpoints/conversations.rb +332 -0
- data/lib/slack/web/api/endpoints/dialog.rb +33 -0
- data/lib/slack/web/api/endpoints/dnd.rb +11 -9
- data/lib/slack/web/api/endpoints/emoji.rb +3 -2
- data/lib/slack/web/api/endpoints/files.rb +75 -38
- data/lib/slack/web/api/endpoints/files_comments.rb +3 -38
- data/lib/slack/web/api/endpoints/files_remote.rb +127 -0
- data/lib/slack/web/api/endpoints/groups.rb +76 -53
- data/lib/slack/web/api/endpoints/im.rb +38 -21
- data/lib/slack/web/api/endpoints/migration.rb +28 -0
- data/lib/slack/web/api/endpoints/mpim.rb +37 -22
- data/lib/slack/web/api/endpoints/oauth.rb +25 -4
- data/lib/slack/web/api/endpoints/oauth_v2.rb +30 -0
- data/lib/slack/web/api/endpoints/pins.rb +10 -19
- data/lib/slack/web/api/endpoints/presence.rb +1 -1
- data/lib/slack/web/api/endpoints/reactions.rb +37 -28
- data/lib/slack/web/api/endpoints/reminders.rb +11 -10
- data/lib/slack/web/api/endpoints/rtm.rb +28 -7
- data/lib/slack/web/api/endpoints/search.rb +21 -14
- data/lib/slack/web/api/endpoints/stars.rb +24 -15
- data/lib/slack/web/api/endpoints/team.rb +21 -13
- data/lib/slack/web/api/endpoints/team_profile.rb +3 -2
- data/lib/slack/web/api/endpoints/usergroups.rb +33 -22
- data/lib/slack/web/api/endpoints/usergroups_users.rb +9 -4
- data/lib/slack/web/api/endpoints/users.rb +78 -29
- data/lib/slack/web/api/endpoints/users_admin.rb +49 -0
- data/lib/slack/web/api/endpoints/users_prefs.rb +21 -0
- data/lib/slack/web/api/endpoints/users_profile.rb +11 -10
- data/lib/slack/web/api/endpoints/views.rb +97 -0
- data/lib/slack/web/api/endpoints/workflows.rb +61 -0
- data/lib/slack/web/api/error.rb +2 -8
- data/lib/slack/web/api/errors.rb +850 -0
- data/lib/slack/web/api/errors/internal_error.rb +14 -0
- data/lib/slack/web/api/errors/slack_error.rb +29 -0
- data/lib/slack/web/api/errors/too_many_requests_error.rb +24 -0
- data/lib/slack/web/api/mixins.rb +6 -4
- data/lib/slack/web/api/mixins/channels.id.rb +6 -7
- data/lib/slack/web/api/mixins/conversations.id.rb +25 -0
- data/lib/slack/web/api/mixins/groups.id.rb +6 -7
- data/lib/slack/web/api/mixins/ids.id.rb +24 -0
- data/lib/slack/web/api/mixins/users.id.rb +6 -7
- data/lib/slack/web/api/mixins/users.search.rb +39 -36
- data/lib/slack/web/api/patches/chat.1.patch +72 -0
- data/lib/slack/web/api/patches/dialog.1.open-json-support.patch +17 -0
- data/lib/slack/web/api/patches/views.1.view-json.patch +40 -0
- data/lib/slack/web/api/patches/views.1.views-published.patch +16 -0
- data/lib/slack/web/api/templates/command.erb +5 -3
- data/lib/slack/web/api/templates/commands.erb +2 -1
- data/lib/slack/web/api/templates/endpoints.erb +5 -3
- data/lib/slack/web/api/templates/errors.erb +20 -0
- data/lib/slack/web/api/templates/method.erb +26 -4
- data/lib/slack/web/api/templates/method_spec.erb +3 -2
- data/lib/slack/web/client.rb +2 -1
- data/lib/slack/web/config.rb +21 -10
- data/lib/slack/web/faraday/connection.rb +25 -16
- data/lib/slack/web/faraday/request.rb +2 -0
- data/lib/slack/web/faraday/response/raise_error.rb +23 -1
- data/lib/slack/web/faraday/response/wrap_error.rb +18 -0
- data/lib/slack/web/pagination/cursor.rb +52 -0
- data/lib/slack_ruby_client.rb +1 -0
- data/lib/tasks/git.rake +2 -1
- data/lib/tasks/real_time.rake +16 -6
- data/lib/tasks/update.rake +1 -0
- data/lib/tasks/web.rake +38 -10
- data/screenshots/create-app.png +0 -0
- data/slack-ruby-client.gemspec +9 -6
- data/spec/fixtures/slack/web/429_error.yml +2 -0
- data/spec/fixtures/slack/web/503_error.yml +14 -0
- data/spec/fixtures/slack/web/channels_info.yml +108 -15
- data/spec/fixtures/slack/web/conversations_setTopic.yml +69 -0
- data/spec/fixtures/slack/web/conversations_setTopic_one_page.yml +142 -0
- data/spec/fixtures/slack/web/conversations_setTopic_paginated.yml +208 -0
- data/spec/fixtures/slack/web/paginated_users_list.yml +181 -0
- data/spec/fixtures/slack/web/rtm_connect.yml +70 -0
- data/spec/fixtures/slack/web/rtm_start.yml +1 -1
- data/spec/fixtures/slack/web/views_open_error.yml +76 -0
- data/spec/integration/integration_spec.rb +116 -48
- data/spec/slack/config_spec.rb +2 -0
- data/spec/slack/events/config_spec.rb +33 -0
- data/spec/slack/events/request_spec.rb +183 -0
- data/spec/slack/messages/formatting_spec.rb +25 -14
- data/spec/slack/real_time/api/message_spec.rb +6 -1
- data/spec/slack/real_time/api/ping_spec.rb +2 -0
- data/spec/slack/real_time/api/typing_spec.rb +5 -1
- data/spec/slack/real_time/client_spec.rb +462 -134
- data/spec/slack/real_time/concurrency/it_behaves_like_a_realtime_socket.rb +3 -1
- data/spec/slack/real_time/event_handlers/bot_spec.rb +6 -3
- data/spec/slack/real_time/event_handlers/channel_spec.rb +9 -6
- data/spec/slack/real_time/event_handlers/event_handlers_spec.rb +3 -2
- data/spec/slack/real_time/event_handlers/group_spec.rb +5 -4
- data/spec/slack/real_time/event_handlers/im_spec.rb +4 -3
- data/spec/slack/real_time/event_handlers/team_spec.rb +8 -4
- data/spec/slack/real_time/event_handlers/user_spec.rb +5 -2
- data/spec/slack/real_time/rtm_connect_spec.rb +14 -0
- data/spec/slack/real_time/rtm_start_spec.rb +1 -0
- data/spec/slack/real_time/store_spec.rb +2 -1
- data/spec/slack/slack_spec.rb +39 -7
- data/spec/slack/version_spec.rb +2 -1
- data/spec/slack/web/api/endpoints/admin_analytics_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/admin_apps_approved_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/admin_apps_requests_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/admin_apps_restricted_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/admin_apps_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/admin_barriers_spec.rb +38 -0
- data/spec/slack/web/api/endpoints/admin_conversations_ekm_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/admin_conversations_restrictAccess_spec.rb +32 -0
- data/spec/slack/web/api/endpoints/admin_conversations_spec.rb +98 -0
- data/spec/slack/web/api/endpoints/admin_conversations_whitelist_spec.rb +32 -0
- data/spec/slack/web/api/endpoints/admin_emoji_spec.rb +37 -0
- data/spec/slack/web/api/endpoints/admin_inviteRequests_approved_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/admin_inviteRequests_denied_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/admin_inviteRequests_spec.rb +18 -0
- data/spec/slack/web/api/endpoints/admin_teams_admins_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/admin_teams_owners_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/admin_teams_settings_spec.rb +53 -0
- data/spec/slack/web/api/endpoints/admin_teams_spec.rb +16 -0
- data/spec/slack/web/api/endpoints/admin_usergroups_spec.rb +37 -0
- data/spec/slack/web/api/endpoints/admin_users_session_spec.rb +21 -0
- data/spec/slack/web/api/endpoints/admin_users_spec.rb +67 -0
- data/spec/slack/web/api/endpoints/api_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/apps_connections_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/apps_event_authorizations_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/apps_permissions_resources_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/apps_permissions_scopes_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/apps_permissions_spec.rb +16 -0
- data/spec/slack/web/api/endpoints/apps_permissions_users_spec.rb +19 -0
- data/spec/slack/web/api/endpoints/apps_spec.rb +16 -0
- data/spec/slack/web/api/endpoints/auth_teams_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/bots_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/calls_participants_spec.rb +24 -0
- data/spec/slack/web/api/endpoints/calls_spec.rb +31 -0
- data/spec/slack/web/api/endpoints/chat_scheduledMessages_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/conversations_spec.rb +109 -0
- data/spec/slack/web/api/endpoints/custom_specs/auth_spec.rb +13 -4
- data/spec/slack/web/api/endpoints/custom_specs/channels_spec.rb +5 -3
- data/spec/slack/web/api/endpoints/custom_specs/chat_spec.rb +140 -24
- data/spec/slack/web/api/endpoints/custom_specs/dialog_spec.rb +36 -0
- data/spec/slack/web/api/endpoints/custom_specs/groups_spec.rb +2 -0
- data/spec/slack/web/api/endpoints/custom_specs/users_spec.rb +21 -6
- data/spec/slack/web/api/endpoints/custom_specs/views_spec.rb +95 -0
- data/spec/slack/web/api/endpoints/dnd_spec.rb +6 -0
- data/spec/slack/web/api/endpoints/emoji_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/files_comments_spec.rb +3 -21
- data/spec/slack/web/api/endpoints/files_remote_spec.rb +24 -0
- data/spec/slack/web/api/endpoints/files_spec.rb +17 -5
- data/spec/slack/web/api/endpoints/im_spec.rb +5 -4
- data/spec/slack/web/api/endpoints/migration_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/mpim_spec.rb +5 -4
- data/spec/slack/web/api/endpoints/oauth_spec.rb +5 -4
- data/spec/slack/web/api/endpoints/oauth_v2_spec.rb +13 -0
- data/spec/slack/web/api/endpoints/pins_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/reactions_spec.rb +8 -1
- data/spec/slack/web/api/endpoints/reminders_spec.rb +3 -2
- data/spec/slack/web/api/endpoints/rtm_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/search_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/stars_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/team_profile_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/team_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/usergroups_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/usergroups_users_spec.rb +3 -2
- data/spec/slack/web/api/endpoints/users_admin_spec.rb +18 -0
- data/spec/slack/web/api/endpoints/users_prefs_spec.rb +8 -0
- data/spec/slack/web/api/endpoints/users_profile_spec.rb +1 -0
- data/spec/slack/web/api/endpoints/views_spec.rb +29 -0
- data/spec/slack/web/api/endpoints/workflows_spec.rb +26 -0
- data/spec/slack/web/api/error_spec.rb +5 -3
- data/spec/slack/web/api/errors/slack_error_spec.rb +38 -0
- data/spec/slack/web/api/mixins/channels_spec.rb +24 -12
- data/spec/slack/web/api/mixins/conversations_list_spec.rb +21 -0
- data/spec/slack/web/api/mixins/conversations_spec.rb +43 -0
- data/spec/slack/web/api/mixins/groups_spec.rb +24 -12
- data/spec/slack/web/api/mixins/users_spec.rb +30 -17
- data/spec/slack/web/api/pagination/cursor_spec.rb +100 -0
- data/spec/slack/web/client_spec.rb +215 -14
- data/spec/slack/web/faraday/response/raise_error_spec.rb +85 -0
- data/spec/spec_helper.rb +8 -1
- data/spec/support/queue_with_timeout.rb +6 -5
- data/spec/support/real_time/concurrency/mock.rb +2 -2
- data/spec/support/real_time/connected_client.rb +13 -2
- data/spec/support/real_time/event.rb +1 -0
- data/spec/support/token.rb +1 -0
- data/spec/support/vcr.rb +6 -1
- metadata +280 -55
- data/examples/hi_real_time/Gemfile +0 -5
- data/examples/hi_real_time/hi.gif +0 -0
- data/examples/hi_real_time/hi.rb +0 -37
- data/examples/hi_real_time_async_celluloid/Gemfile +0 -6
- data/examples/hi_real_time_async_eventmachine/Procfile +0 -2
- data/examples/hi_real_time_async_eventmachine/hi.rb +0 -36
- data/lib/slack/real_time/concurrency/celluloid.rb +0 -113
- data/lib/slack/real_time/concurrency/eventmachine.rb +0 -60
- data/lib/slack/web/api/patches/chat.1.text-attachments-required.patch +0 -13
- data/lib/slack/web/api/patches/chat.2.attachments-json.patch +0 -17
- data/lib/slack/web/api/patches/chat.3.update-attachments-support.patch +0 -20
- data/screenshots/register-bot.png +0 -0
- data/spec/slack/real_time/concurrency/celluloid_spec.rb +0 -31
- data/spec/slack/real_time/concurrency/eventmachine_spec.rb +0 -47
data/lib/slack/logger.rb
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'logger'
|
|
2
3
|
|
|
3
4
|
module Slack
|
|
4
5
|
class Logger < ::Logger
|
|
5
6
|
def self.default
|
|
6
|
-
@
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
return @default if @default
|
|
8
|
+
|
|
9
|
+
logger = new STDOUT
|
|
10
|
+
logger.level = Logger::WARN
|
|
11
|
+
@default = logger
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
14
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
module Slack
|
|
3
3
|
module Messages
|
|
4
4
|
module Formatting
|
|
@@ -10,9 +10,9 @@ module Slack
|
|
|
10
10
|
def unescape(message)
|
|
11
11
|
CGI.unescapeHTML(message.gsub(/[“”]/, '"')
|
|
12
12
|
.gsub(/[‘’]/, "'")
|
|
13
|
-
.gsub(/<(?<sign>[?@#!]?)(?<dt>.*?)>/) do
|
|
14
|
-
sign =
|
|
15
|
-
dt =
|
|
13
|
+
.gsub(/<(?<sign>[?@#!]?)(?<dt>.*?)>/) do
|
|
14
|
+
sign = Regexp.last_match[:sign]
|
|
15
|
+
dt = Regexp.last_match[:dt]
|
|
16
16
|
rhs = dt.split('|', 2).last
|
|
17
17
|
case sign
|
|
18
18
|
when '@', '!'
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Slack
|
|
2
3
|
module Messages
|
|
3
4
|
class Message < Hashie::Mash
|
|
4
|
-
def presence
|
|
5
|
-
super['presence']
|
|
6
|
-
end
|
|
7
|
-
|
|
8
5
|
def to_s
|
|
9
6
|
keys.sort_by(&:to_s).map do |key|
|
|
10
7
|
"#{key}=#{self[key]}"
|
|
@@ -14,8 +11,7 @@ module Slack
|
|
|
14
11
|
private
|
|
15
12
|
|
|
16
13
|
# see https://github.com/intridea/hashie/issues/394
|
|
17
|
-
def log_built_in_message(*)
|
|
18
|
-
end
|
|
14
|
+
def log_built_in_message(*); end
|
|
19
15
|
end
|
|
20
16
|
end
|
|
21
17
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Slack
|
|
2
3
|
module RealTime
|
|
3
4
|
module Api
|
|
@@ -6,7 +7,8 @@ module Slack
|
|
|
6
7
|
# Sends a message to a channel.
|
|
7
8
|
#
|
|
8
9
|
# @option options [channel] :channel
|
|
9
|
-
# Channel to send message to. Can be a public channel, private group or IM channel.
|
|
10
|
+
# Channel to send message to. Can be a public channel, private group or IM channel.
|
|
11
|
+
# Can be an encoded ID, or a name.
|
|
10
12
|
# @option options [Object] :text
|
|
11
13
|
# Text of the message to send. See below for an explanation of formatting.
|
|
12
14
|
def message(options = {})
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Slack
|
|
2
3
|
module RealTime
|
|
3
4
|
module Api
|
|
4
5
|
module Ping
|
|
5
6
|
#
|
|
6
|
-
# Clients should try to quickly detect disconnections, even in idle periods, so that users
|
|
7
|
-
#
|
|
7
|
+
# Clients should try to quickly detect disconnections, even in idle periods, so that users
|
|
8
|
+
# can easily tell the
|
|
9
|
+
# difference between being disconnected and everyone being quiet. Not all web browsers
|
|
10
|
+
# support the WebSocket
|
|
8
11
|
# ping spec, so the RTM protocol also supports ping/pong messages.
|
|
9
12
|
#
|
|
10
13
|
def ping(options = {})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Slack
|
|
2
3
|
module RealTime
|
|
3
4
|
module Api
|
|
@@ -6,7 +7,8 @@ module Slack
|
|
|
6
7
|
# Send a typing indicator to indicate that the user is currently writing a message.
|
|
7
8
|
#
|
|
8
9
|
# @option options [channel] :channel
|
|
9
|
-
# Channel to send message to. Can be a public channel, private group or IM channel.
|
|
10
|
+
# Channel to send message to. Can be a public channel, private group or IM channel.
|
|
11
|
+
# Can be an encoded ID, or a name.
|
|
10
12
|
def typing(options = {})
|
|
11
13
|
throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil?
|
|
12
14
|
send_json({ type: 'typing', id: next_id }.merge(options))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Slack
|
|
2
3
|
module RealTime
|
|
3
4
|
class Client
|
|
@@ -20,7 +21,6 @@ module Slack
|
|
|
20
21
|
attr_accessor :url
|
|
21
22
|
attr_accessor(*Config::ATTRIBUTES)
|
|
22
23
|
|
|
23
|
-
protected :logger, :logger=
|
|
24
24
|
protected :store_class, :store_class=
|
|
25
25
|
|
|
26
26
|
def initialize(options = {})
|
|
@@ -33,9 +33,9 @@ module Slack
|
|
|
33
33
|
@web_client = Slack::Web::Client.new(token: token, logger: logger)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
[
|
|
36
|
+
%i[users self channels team teams groups ims bots].each do |store_method|
|
|
37
37
|
define_method store_method do
|
|
38
|
-
store
|
|
38
|
+
store&.send(store_method)
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -47,7 +47,7 @@ module Slack
|
|
|
47
47
|
# Start RealTime client and block until it disconnects.
|
|
48
48
|
def start!(&block)
|
|
49
49
|
@callback = block if block_given?
|
|
50
|
-
|
|
50
|
+
build_socket
|
|
51
51
|
@socket.start_sync(self)
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -55,17 +55,18 @@ module Slack
|
|
|
55
55
|
# The RealTime::Client will run in the background.
|
|
56
56
|
def start_async(&block)
|
|
57
57
|
@callback = block if block_given?
|
|
58
|
-
|
|
58
|
+
build_socket
|
|
59
59
|
@socket.start_async(self)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def stop!
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
raise ClientNotStartedError unless started?
|
|
64
|
+
|
|
65
|
+
@socket&.disconnect!
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
def started?
|
|
68
|
-
@socket
|
|
69
|
+
@socket&.connected?
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
class << self
|
|
@@ -80,38 +81,115 @@ module Slack
|
|
|
80
81
|
|
|
81
82
|
def run_loop
|
|
82
83
|
@socket.connect! do |driver|
|
|
83
|
-
@callback.call(driver) if @callback
|
|
84
|
-
|
|
85
84
|
driver.on :open do |event|
|
|
86
|
-
logger.debug("#{self
|
|
87
|
-
|
|
85
|
+
logger.debug("#{self}##{__method__}") { event.class.name }
|
|
86
|
+
open_event(event)
|
|
88
87
|
callback(event, :open)
|
|
89
88
|
end
|
|
90
89
|
|
|
91
90
|
driver.on :message do |event|
|
|
92
|
-
logger.debug("#{self
|
|
91
|
+
logger.debug("#{self}##{__method__}") { "#{event.class}, #{event.data}" }
|
|
93
92
|
dispatch(event)
|
|
94
93
|
end
|
|
95
94
|
|
|
96
95
|
driver.on :close do |event|
|
|
97
|
-
logger.debug("#{self
|
|
96
|
+
logger.debug("#{self}##{__method__}") { event.class.name }
|
|
98
97
|
callback(event, :close)
|
|
99
98
|
close(event)
|
|
100
99
|
callback(event, :closed)
|
|
101
100
|
end
|
|
101
|
+
|
|
102
|
+
# This must be called last to ensure any events are registered before invoking user code.
|
|
103
|
+
@callback&.call(driver)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Ensure the server is running, and ping the remote server if no other messages were sent.
|
|
108
|
+
def keep_alive?
|
|
109
|
+
# We can't ping the remote server if we aren't connected.
|
|
110
|
+
return false if @socket.nil? || !@socket.connected?
|
|
111
|
+
|
|
112
|
+
time_since_last_message = @socket.time_since_last_message
|
|
113
|
+
|
|
114
|
+
# If the server responded within the specified time, we are okay:
|
|
115
|
+
return true if time_since_last_message < websocket_ping
|
|
116
|
+
|
|
117
|
+
# If the server has not responded for a while:
|
|
118
|
+
return false if time_since_last_message > (websocket_ping * 2)
|
|
119
|
+
|
|
120
|
+
# Kick off the next ping message:
|
|
121
|
+
ping
|
|
122
|
+
|
|
123
|
+
true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Check if the remote server is responsive, and if not, restart the connection.
|
|
127
|
+
def run_ping!
|
|
128
|
+
return if keep_alive?
|
|
129
|
+
|
|
130
|
+
logger.warn(to_s) { 'is offline' }
|
|
131
|
+
|
|
132
|
+
restart_async
|
|
133
|
+
rescue Slack::Web::Api::Errors::SlackError => e
|
|
134
|
+
# stop pinging if bot was uninstalled
|
|
135
|
+
case e.message
|
|
136
|
+
when 'account_inactive', 'invalid_auth' then
|
|
137
|
+
logger.warn(to_s) { e.message }
|
|
138
|
+
raise e
|
|
139
|
+
end
|
|
140
|
+
logger.debug("#{self}##{__method__}") { e }
|
|
141
|
+
rescue StandardError => e
|
|
142
|
+
# disregard all ping worker failures, keep pinging
|
|
143
|
+
logger.debug("#{self}##{__method__}") { e }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def run_ping?
|
|
147
|
+
!websocket_ping.nil? && websocket_ping.positive?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def websocket_ping_timer
|
|
151
|
+
websocket_ping / 2
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def to_s
|
|
155
|
+
if store&.team
|
|
156
|
+
"id=#{store.team.id}, name=#{store.team.name}, domain=#{store.team.domain}"
|
|
157
|
+
else
|
|
158
|
+
super
|
|
102
159
|
end
|
|
103
160
|
end
|
|
104
161
|
|
|
105
162
|
protected
|
|
106
163
|
|
|
164
|
+
def restart_async
|
|
165
|
+
logger.debug("#{self}##{__method__}")
|
|
166
|
+
@socket.close
|
|
167
|
+
start = web_client.send(rtm_start_method, start_options)
|
|
168
|
+
data = Slack::Messages::Message.new(start)
|
|
169
|
+
@url = data.url
|
|
170
|
+
@store = @store_class.new(data) if @store_class
|
|
171
|
+
@socket.restart_async(self, @url)
|
|
172
|
+
end
|
|
173
|
+
|
|
107
174
|
# @return [Slack::RealTime::Socket]
|
|
108
175
|
def build_socket
|
|
109
|
-
|
|
110
|
-
|
|
176
|
+
raise ClientAlreadyStartedError if started?
|
|
177
|
+
|
|
178
|
+
start = web_client.send(rtm_start_method, start_options)
|
|
111
179
|
data = Slack::Messages::Message.new(start)
|
|
112
180
|
@url = data.url
|
|
113
181
|
@store = @store_class.new(data) if @store_class
|
|
114
|
-
socket_class.new(@url, socket_options)
|
|
182
|
+
@socket = socket_class.new(@url, socket_options)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def rtm_start_method
|
|
186
|
+
if start_method
|
|
187
|
+
start_method
|
|
188
|
+
elsif @store_class && @store_class <= Slack::RealTime::Stores::Store
|
|
189
|
+
:rtm_start
|
|
190
|
+
else
|
|
191
|
+
:rtm_connect
|
|
192
|
+
end
|
|
115
193
|
end
|
|
116
194
|
|
|
117
195
|
def socket_options
|
|
@@ -128,19 +206,16 @@ module Slack
|
|
|
128
206
|
end
|
|
129
207
|
|
|
130
208
|
def send_json(data)
|
|
131
|
-
|
|
132
|
-
|
|
209
|
+
raise ClientNotStartedError unless started?
|
|
210
|
+
|
|
211
|
+
logger.debug("#{self}##{__method__}") { data }
|
|
133
212
|
@socket.send_data(data.to_json)
|
|
134
213
|
end
|
|
135
214
|
|
|
136
|
-
def
|
|
137
|
-
end
|
|
215
|
+
def open_event(_event); end
|
|
138
216
|
|
|
139
217
|
def close(_event)
|
|
140
|
-
socket
|
|
141
|
-
@socket = nil
|
|
142
|
-
|
|
143
|
-
[socket, socket_class].each do |s|
|
|
218
|
+
[@socket, socket_class].each do |s|
|
|
144
219
|
s.close if s.respond_to?(:close)
|
|
145
220
|
end
|
|
146
221
|
end
|
|
@@ -148,48 +223,54 @@ module Slack
|
|
|
148
223
|
def callback(event, type)
|
|
149
224
|
callbacks = self.callbacks[type.to_s]
|
|
150
225
|
return false unless callbacks
|
|
226
|
+
|
|
151
227
|
callbacks.each do |c|
|
|
152
228
|
c.call(event)
|
|
153
229
|
end
|
|
154
230
|
true
|
|
155
231
|
rescue StandardError => e
|
|
156
|
-
logger.error e
|
|
232
|
+
logger.error("#{self}##{__method__}") { e }
|
|
157
233
|
false
|
|
158
234
|
end
|
|
159
235
|
|
|
160
236
|
def dispatch(event)
|
|
161
237
|
return false unless event.data
|
|
238
|
+
|
|
162
239
|
data = Slack::Messages::Message.new(JSON.parse(event.data))
|
|
163
240
|
type = data.type
|
|
164
241
|
return false unless type
|
|
242
|
+
|
|
165
243
|
type = type.to_s
|
|
166
|
-
logger.debug("#{self
|
|
244
|
+
logger.debug("#{self}##{__method__}") { data.to_s }
|
|
167
245
|
run_handlers(type, data) if @store
|
|
168
246
|
run_callbacks(type, data)
|
|
169
247
|
rescue StandardError => e
|
|
170
|
-
logger.error e
|
|
248
|
+
logger.error("#{self}##{__method__}") { e }
|
|
171
249
|
false
|
|
172
250
|
end
|
|
173
251
|
|
|
174
252
|
def run_handlers(type, data)
|
|
253
|
+
return unless store.class.events
|
|
254
|
+
|
|
175
255
|
handlers = store.class.events[type.to_s]
|
|
176
|
-
handlers
|
|
256
|
+
handlers&.each do |handler|
|
|
177
257
|
store.instance_exec(data, &handler)
|
|
178
|
-
end
|
|
258
|
+
end
|
|
179
259
|
rescue StandardError => e
|
|
180
|
-
logger.error e
|
|
260
|
+
logger.error("#{self}##{__method__}") { e }
|
|
181
261
|
false
|
|
182
262
|
end
|
|
183
263
|
|
|
184
264
|
def run_callbacks(type, data)
|
|
185
265
|
callbacks = self.callbacks[type]
|
|
186
266
|
return false unless callbacks
|
|
267
|
+
|
|
187
268
|
callbacks.each do |c|
|
|
188
269
|
c.call(data)
|
|
189
270
|
end
|
|
190
271
|
true
|
|
191
272
|
rescue StandardError => e
|
|
192
|
-
logger.error e
|
|
273
|
+
logger.error("#{self}##{__method__}") { e }
|
|
193
274
|
false
|
|
194
275
|
end
|
|
195
276
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Slack
|
|
2
3
|
module RealTime
|
|
3
4
|
module Concurrency
|
|
4
|
-
autoload :
|
|
5
|
-
autoload :Celluloid, 'slack/real_time/concurrency/celluloid'
|
|
5
|
+
autoload :Async, 'slack/real_time/concurrency/async'
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
8
|
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'async/websocket'
|
|
3
|
+
require 'async/notification'
|
|
4
|
+
require 'async/clock'
|
|
5
|
+
|
|
6
|
+
module Slack
|
|
7
|
+
module RealTime
|
|
8
|
+
module Concurrency
|
|
9
|
+
module Async
|
|
10
|
+
class Client < ::Async::WebSocket::Client
|
|
11
|
+
extend ::Forwardable
|
|
12
|
+
def_delegators :@driver, :on, :text, :binary, :emit
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Socket < Slack::RealTime::Socket
|
|
16
|
+
attr_reader :client
|
|
17
|
+
|
|
18
|
+
def start_sync(client)
|
|
19
|
+
start_reactor(client).wait
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start_async(client)
|
|
23
|
+
Thread.new do
|
|
24
|
+
start_reactor(client)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def start_reactor(client)
|
|
29
|
+
Async do |task|
|
|
30
|
+
@restart = ::Async::Notification.new
|
|
31
|
+
|
|
32
|
+
if client.run_ping?
|
|
33
|
+
@ping_task = task.async do |subtask|
|
|
34
|
+
subtask.annotate "#{client} keep-alive"
|
|
35
|
+
|
|
36
|
+
# The timer task will naturally exit after the driver is set to nil.
|
|
37
|
+
while @restart
|
|
38
|
+
subtask.sleep client.websocket_ping_timer
|
|
39
|
+
client.run_ping! if @restart
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
while @restart
|
|
45
|
+
@client_task&.stop
|
|
46
|
+
|
|
47
|
+
@client_task = task.async do |subtask|
|
|
48
|
+
begin
|
|
49
|
+
subtask.annotate "#{client} run-loop"
|
|
50
|
+
client.run_loop
|
|
51
|
+
rescue ::Async::Wrapper::Cancelled => e
|
|
52
|
+
# Will get restarted by ping worker.
|
|
53
|
+
rescue StandardError => e
|
|
54
|
+
client.logger.error(subtask.to_s) { e.message }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
@restart.wait
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@ping_task&.stop
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def restart_async(_client, new_url)
|
|
66
|
+
@url = new_url
|
|
67
|
+
@last_message_at = current_time
|
|
68
|
+
|
|
69
|
+
@restart&.signal
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def current_time
|
|
73
|
+
::Async::Clock.now
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def connect!
|
|
77
|
+
super
|
|
78
|
+
run_loop
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Kill the restart/ping loop.
|
|
82
|
+
def disconnect!
|
|
83
|
+
super
|
|
84
|
+
ensure
|
|
85
|
+
if (restart = @restart)
|
|
86
|
+
@restart = nil
|
|
87
|
+
restart.signal
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Close the socket.
|
|
92
|
+
def close
|
|
93
|
+
super
|
|
94
|
+
ensure
|
|
95
|
+
if @socket
|
|
96
|
+
@socket.close
|
|
97
|
+
@socket = nil
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def run_loop
|
|
102
|
+
while @driver&.next_event
|
|
103
|
+
# $stderr.puts event.inspect
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
protected
|
|
108
|
+
|
|
109
|
+
def build_ssl_context
|
|
110
|
+
OpenSSL::SSL::SSLContext.new(:TLSv1_2_client).tap do |ctx|
|
|
111
|
+
ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def build_endpoint
|
|
116
|
+
endpoint = ::Async::IO::Endpoint.tcp(addr, port)
|
|
117
|
+
endpoint = ::Async::IO::SSLEndpoint.new(endpoint, ssl_context: build_ssl_context) if secure?
|
|
118
|
+
endpoint
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def connect_socket
|
|
122
|
+
build_endpoint.connect
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def connect
|
|
126
|
+
@socket = connect_socket
|
|
127
|
+
@driver = Client.new(@socket, url)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if Gem::Version.new(Async::WebSocket::VERSION) >= Gem::Version.new('0.9.0')
|
|
136
|
+
raise(
|
|
137
|
+
"Incompatible version of async-websocket, #{Async::WebSocket::VERSION}, " \
|
|
138
|
+
"use \"gem 'async-websocket', '~> 0.8.0'\"."
|
|
139
|
+
)
|
|
140
|
+
end
|