slack-ruby-client 0.13.1 → 2.0.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 (402) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/integration_test.yml +26 -0
  4. data/.github/workflows/lint.yml +14 -0
  5. data/.github/workflows/pr_lint.yml +21 -0
  6. data/.github/workflows/test.yml +36 -0
  7. data/.gitignore +5 -3
  8. data/.rubocop.yml +34 -5
  9. data/.rubocop_todo.yml +180 -46
  10. data/.ruby-version +1 -0
  11. data/CHANGELOG.md +119 -2
  12. data/CONTRIBUTING.md +23 -11
  13. data/Dangerfile +2 -0
  14. data/Gemfile +22 -5
  15. data/Gemfile.danger +6 -0
  16. data/LICENSE.md +1 -1
  17. data/README.md +236 -101
  18. data/RELEASING.md +2 -2
  19. data/Rakefile +2 -1
  20. data/UPGRADING.md +100 -2
  21. data/bin/commands/admin_analytics.rb +16 -0
  22. data/bin/commands/admin_apps.rb +51 -0
  23. data/bin/commands/admin_apps_approved.rb +17 -0
  24. data/bin/commands/admin_apps_requests.rb +28 -0
  25. data/bin/commands/admin_apps_restricted.rb +17 -0
  26. data/bin/commands/admin_audit_anomaly_allow.rb +23 -0
  27. data/bin/commands/admin_auth_policy.rb +39 -0
  28. data/bin/commands/admin_barriers.rb +47 -0
  29. data/bin/commands/admin_conversations.rb +171 -0
  30. data/bin/commands/admin_conversations_ekm.rb +17 -0
  31. data/bin/commands/admin_conversations_restrictAccess.rb +37 -0
  32. data/bin/commands/admin_emoji.rb +54 -0
  33. data/bin/commands/admin_inviteRequests.rb +36 -0
  34. data/bin/commands/admin_inviteRequests_approved.rb +16 -0
  35. data/bin/commands/admin_inviteRequests_denied.rb +16 -0
  36. data/bin/commands/admin_teams.rb +27 -0
  37. data/bin/commands/admin_teams_admins.rb +16 -0
  38. data/bin/commands/admin_teams_owners.rb +16 -0
  39. data/bin/commands/admin_teams_settings.rb +64 -0
  40. data/bin/commands/admin_usergroups.rb +48 -0
  41. data/bin/commands/admin_users.rb +98 -0
  42. data/bin/commands/admin_users_session.rb +78 -0
  43. data/bin/commands/admin_users_unsupportedVersions.rb +15 -0
  44. data/bin/commands/api.rb +1 -1
  45. data/bin/commands/apps.rb +15 -0
  46. data/bin/commands/apps_connections.rb +13 -0
  47. data/bin/commands/apps_event_authorizations.rb +16 -0
  48. data/bin/commands/apps_manifest.rb +52 -0
  49. data/bin/commands/auth.rb +1 -0
  50. data/bin/commands/auth_teams.rb +16 -0
  51. data/bin/commands/bookmarks.rb +53 -0
  52. data/bin/commands/bots.rb +2 -0
  53. data/bin/commands/calls.rb +52 -0
  54. data/bin/commands/calls_participants.rb +25 -0
  55. data/bin/commands/chat.rb +61 -14
  56. data/bin/commands/chat_scheduledMessages.rb +19 -0
  57. data/bin/commands/conversations.rb +82 -10
  58. data/bin/commands/dialog.rb +1 -0
  59. data/bin/commands/dnd.rb +6 -3
  60. data/bin/commands/emoji.rb +1 -0
  61. data/bin/commands/files.rb +34 -18
  62. data/bin/commands/files_comments.rb +1 -21
  63. data/bin/commands/files_remote.rb +78 -0
  64. data/bin/commands/migration.rb +2 -0
  65. data/bin/commands/oauth.rb +2 -14
  66. data/bin/commands/oauth_v2.rb +29 -0
  67. data/bin/commands/openid_connect.rb +27 -0
  68. data/bin/commands/pins.rb +3 -6
  69. data/bin/commands/reactions.rb +3 -3
  70. data/bin/commands/reminders.rb +7 -0
  71. data/bin/commands/rtm.rb +1 -15
  72. data/bin/commands/search.rb +6 -1
  73. data/bin/commands/stars.rb +8 -6
  74. data/bin/commands/team.rb +6 -0
  75. data/bin/commands/team_billing.rb +13 -0
  76. data/bin/commands/team_preferences.rb +13 -0
  77. data/bin/commands/team_profile.rb +1 -0
  78. data/bin/commands/tooling_tokens.rb +14 -0
  79. data/bin/commands/usergroups.rb +7 -1
  80. data/bin/commands/usergroups_users.rb +3 -0
  81. data/bin/commands/users.rb +6 -4
  82. data/bin/commands/users_admin.rb +1 -0
  83. data/bin/commands/users_prefs.rb +1 -0
  84. data/bin/commands/users_profile.rb +6 -5
  85. data/bin/commands/views.rb +50 -0
  86. data/bin/commands/workflows.rb +38 -0
  87. data/bin/commands.rb +41 -8
  88. data/bin/slack +3 -4
  89. data/examples/hi_real_time_and_web/Gemfile +1 -0
  90. data/examples/hi_real_time_and_web/hi.rb +7 -3
  91. data/examples/hi_real_time_async_async/Gemfile +1 -0
  92. data/examples/hi_real_time_async_async/hi.rb +6 -2
  93. data/examples/hi_web/Gemfile +1 -0
  94. data/examples/hi_web/hi.rb +1 -0
  95. data/examples/new_ticket/Gemfile +1 -0
  96. data/examples/new_ticket/new_ticket.rb +1 -0
  97. data/lib/slack/config.rb +2 -2
  98. data/lib/slack/events/config.rb +32 -0
  99. data/lib/slack/events/request.rb +72 -0
  100. data/lib/slack/logger.rb +6 -5
  101. data/lib/slack/messages/formatting.rb +1 -0
  102. data/lib/slack/messages/message.rb +1 -4
  103. data/lib/slack/real_time/api/message.rb +6 -3
  104. data/lib/slack/real_time/api/message_id.rb +1 -0
  105. data/lib/slack/real_time/api/ping.rb +5 -2
  106. data/lib/slack/real_time/api/templates/event_handler.erb +5 -1
  107. data/lib/slack/real_time/api/typing.rb +5 -2
  108. data/lib/slack/real_time/client.rb +105 -54
  109. data/lib/slack/real_time/concurrency/async.rb +77 -6
  110. data/lib/slack/real_time/concurrency.rb +1 -2
  111. data/lib/slack/real_time/config.rb +9 -13
  112. data/lib/slack/real_time/models/base.rb +1 -4
  113. data/lib/slack/real_time/models/bot.rb +1 -0
  114. data/lib/slack/real_time/models/channel.rb +5 -0
  115. data/lib/slack/real_time/models/im.rb +1 -0
  116. data/lib/slack/real_time/models/{group.rb → mpim.rb} +2 -1
  117. data/lib/slack/real_time/models/team.rb +1 -0
  118. data/lib/slack/real_time/models/user.rb +1 -0
  119. data/lib/slack/real_time/models.rb +3 -1
  120. data/lib/slack/real_time/socket.rb +45 -17
  121. data/lib/slack/real_time/stores/base.rb +28 -14
  122. data/lib/slack/real_time/stores/starter.rb +325 -297
  123. data/lib/slack/real_time/stores/store.rb +271 -196
  124. data/lib/slack/real_time/stores.rb +2 -7
  125. data/lib/slack/version.rb +2 -1
  126. data/lib/slack/web/api/endpoints/admin_analytics.rb +28 -0
  127. data/lib/slack/web/api/endpoints/admin_apps.rb +78 -0
  128. data/lib/slack/web/api/endpoints/admin_apps_approved.rb +35 -0
  129. data/lib/slack/web/api/endpoints/admin_apps_requests.rb +51 -0
  130. data/lib/slack/web/api/endpoints/admin_apps_restricted.rb +35 -0
  131. data/lib/slack/web/api/endpoints/admin_audit_anomaly_allow.rb +34 -0
  132. data/lib/slack/web/api/endpoints/admin_auth_policy.rb +72 -0
  133. data/lib/slack/web/api/endpoints/admin_barriers.rb +82 -0
  134. data/lib/slack/web/api/endpoints/admin_conversations.rb +264 -0
  135. data/lib/slack/web/api/endpoints/admin_conversations_ekm.rb +35 -0
  136. data/lib/slack/web/api/endpoints/admin_conversations_restrictAccess.rb +61 -0
  137. data/lib/slack/web/api/endpoints/admin_emoji.rb +88 -0
  138. data/lib/slack/web/api/endpoints/admin_inviteRequests.rb +61 -0
  139. data/lib/slack/web/api/endpoints/admin_inviteRequests_approved.rb +33 -0
  140. data/lib/slack/web/api/endpoints/admin_inviteRequests_denied.rb +33 -0
  141. data/lib/slack/web/api/endpoints/admin_teams.rb +50 -0
  142. data/lib/slack/web/api/endpoints/admin_teams_admins.rb +34 -0
  143. data/lib/slack/web/api/endpoints/admin_teams_owners.rb +34 -0
  144. data/lib/slack/web/api/endpoints/admin_teams_settings.rb +99 -0
  145. data/lib/slack/web/api/endpoints/admin_usergroups.rb +77 -0
  146. data/lib/slack/web/api/endpoints/admin_users.rb +163 -0
  147. data/lib/slack/web/api/endpoints/admin_users_session.rb +122 -0
  148. data/lib/slack/web/api/endpoints/admin_users_unsupportedVersions.rb +25 -0
  149. data/lib/slack/web/api/endpoints/api.rb +2 -3
  150. data/lib/slack/web/api/endpoints/apps.rb +27 -0
  151. data/lib/slack/web/api/endpoints/apps_connections.rb +21 -0
  152. data/lib/slack/web/api/endpoints/apps_event_authorizations.rb +34 -0
  153. data/lib/slack/web/api/endpoints/apps_manifest.rb +77 -0
  154. data/lib/slack/web/api/endpoints/auth.rb +2 -1
  155. data/lib/slack/web/api/endpoints/auth_teams.rb +33 -0
  156. data/lib/slack/web/api/endpoints/bookmarks.rb +88 -0
  157. data/lib/slack/web/api/endpoints/bots.rb +4 -1
  158. data/lib/slack/web/api/endpoints/calls.rb +83 -0
  159. data/lib/slack/web/api/endpoints/calls_participants.rb +42 -0
  160. data/lib/slack/web/api/endpoints/chat.rb +168 -65
  161. data/lib/slack/web/api/endpoints/chat_scheduledMessages.rb +40 -0
  162. data/lib/slack/web/api/endpoints/conversations.rb +182 -67
  163. data/lib/slack/web/api/endpoints/dialog.rb +5 -4
  164. data/lib/slack/web/api/endpoints/dnd.rb +9 -4
  165. data/lib/slack/web/api/endpoints/emoji.rb +1 -0
  166. data/lib/slack/web/api/endpoints/files.rb +69 -37
  167. data/lib/slack/web/api/endpoints/files_comments.rb +4 -36
  168. data/lib/slack/web/api/endpoints/files_remote.rb +127 -0
  169. data/lib/slack/web/api/endpoints/migration.rb +6 -3
  170. data/lib/slack/web/api/endpoints/oauth.rb +7 -31
  171. data/lib/slack/web/api/endpoints/oauth_v2.rb +48 -0
  172. data/lib/slack/web/api/endpoints/openid_connect.rb +42 -0
  173. data/lib/slack/web/api/endpoints/pins.rb +11 -18
  174. data/lib/slack/web/api/endpoints/reactions.rb +22 -21
  175. data/lib/slack/web/api/endpoints/reminders.rb +23 -10
  176. data/lib/slack/web/api/endpoints/rtm.rb +3 -25
  177. data/lib/slack/web/api/endpoints/search.rb +31 -16
  178. data/lib/slack/web/api/endpoints/stars.rb +14 -11
  179. data/lib/slack/web/api/endpoints/team.rb +15 -4
  180. data/lib/slack/web/api/endpoints/team_billing.rb +21 -0
  181. data/lib/slack/web/api/endpoints/team_preferences.rb +21 -0
  182. data/lib/slack/web/api/endpoints/team_profile.rb +2 -1
  183. data/lib/slack/web/api/endpoints/tooling_tokens.rb +24 -0
  184. data/lib/slack/web/api/endpoints/usergroups.rb +31 -20
  185. data/lib/slack/web/api/endpoints/usergroups_users.rb +13 -8
  186. data/lib/slack/web/api/endpoints/users.rb +24 -23
  187. data/lib/slack/web/api/endpoints/users_admin.rb +3 -2
  188. data/lib/slack/web/api/endpoints/users_prefs.rb +1 -0
  189. data/lib/slack/web/api/endpoints/users_profile.rb +8 -7
  190. data/lib/slack/web/api/endpoints/views.rb +102 -0
  191. data/lib/slack/web/api/endpoints/workflows.rb +61 -0
  192. data/lib/slack/web/api/endpoints.rb +82 -18
  193. data/lib/slack/web/api/error.rb +1 -0
  194. data/lib/slack/web/api/errors/server_error.rb +37 -0
  195. data/lib/slack/web/api/errors/slack_error.rb +14 -1
  196. data/lib/slack/web/api/errors/too_many_requests_error.rb +2 -4
  197. data/lib/slack/web/api/errors.rb +1116 -0
  198. data/lib/slack/web/api/mixins/{channels.id.rb → conversations.id.rb} +5 -6
  199. data/lib/slack/web/api/mixins/ids.id.rb +3 -2
  200. data/lib/slack/web/api/mixins/users.id.rb +3 -4
  201. data/lib/slack/web/api/mixins/users.search.rb +3 -1
  202. data/lib/slack/web/api/mixins.rb +2 -2
  203. data/lib/slack/web/api/patches/chat.attachments-blocks.patch +69 -0
  204. data/lib/slack/web/api/patches/{dialog.1.open-json-support.patch → dialog.encoded-json.patch} +4 -4
  205. data/lib/slack/web/api/patches/views.view-json.patch +55 -0
  206. data/lib/slack/web/api/templates/command.erb +1 -0
  207. data/lib/slack/web/api/templates/commands.erb +1 -0
  208. data/lib/slack/web/api/templates/endpoints.erb +2 -2
  209. data/lib/slack/web/api/templates/errors.erb +20 -0
  210. data/lib/slack/web/api/templates/method.erb +6 -2
  211. data/lib/slack/web/api/templates/method_spec.erb +2 -1
  212. data/lib/slack/web/client.rb +2 -1
  213. data/lib/slack/web/config.rb +5 -2
  214. data/lib/slack/web/faraday/connection.rb +24 -20
  215. data/lib/slack/web/faraday/request.rb +5 -1
  216. data/lib/slack/web/faraday/response/raise_error.rb +14 -7
  217. data/lib/slack/web/faraday/response/wrap_error.rb +24 -0
  218. data/lib/slack/web/pagination/cursor.rb +7 -7
  219. data/lib/slack-ruby-client.rb +12 -5
  220. data/lib/slack.rb +1 -0
  221. data/lib/slack_ruby_client.rb +1 -0
  222. data/lib/tasks/git.rake +1 -0
  223. data/lib/tasks/real_time.rake +51 -21
  224. data/lib/tasks/update.rake +1 -0
  225. data/lib/tasks/web.rake +48 -12
  226. data/screenshots/create-app.png +0 -0
  227. data/slack-ruby-client.gemspec +7 -12
  228. data/spec/fixtures/slack/web/429_error.yml +50 -54
  229. data/spec/fixtures/slack/web/auth_test_error.yml +51 -18
  230. data/spec/fixtures/slack/web/auth_test_success.yml +50 -26
  231. data/spec/fixtures/slack/web/conversations_info.yml +167 -0
  232. data/spec/fixtures/slack/web/conversations_setTopic.yml +84 -0
  233. data/spec/fixtures/slack/web/conversations_setTopic_one_page.yml +172 -0
  234. data/spec/fixtures/slack/web/conversations_setTopic_paginated.yml +253 -0
  235. data/spec/fixtures/slack/web/paginated_users_list.yml +501 -69
  236. data/spec/fixtures/slack/web/rtm_connect.yml +347 -26
  237. data/spec/fixtures/slack/web/users_info.yml +153 -69
  238. data/spec/fixtures/slack/web/users_list.yml +102 -41
  239. data/spec/fixtures/slack/web/views_open_error.yml +83 -0
  240. data/spec/integration/integration_spec.rb +115 -47
  241. data/spec/slack/config_spec.rb +2 -0
  242. data/spec/slack/events/config_spec.rb +35 -0
  243. data/spec/slack/events/request_spec.rb +188 -0
  244. data/spec/slack/messages/formatting_spec.rb +35 -13
  245. data/spec/slack/real_time/api/message_spec.rb +7 -2
  246. data/spec/slack/real_time/api/ping_spec.rb +3 -1
  247. data/spec/slack/real_time/api/typing_spec.rb +6 -2
  248. data/spec/slack/real_time/client_spec.rb +300 -142
  249. data/spec/slack/real_time/concurrency/it_behaves_like_a_realtime_socket.rb +2 -0
  250. data/spec/slack/real_time/concurrency/with_concurrency_spec.rb +10 -0
  251. data/spec/slack/real_time/concurrency/without_concurrency_spec.rb +10 -0
  252. data/spec/slack/real_time/event_handlers/bot_spec.rb +20 -17
  253. data/spec/slack/real_time/event_handlers/event_handlers_spec.rb +3 -2
  254. data/spec/slack/real_time/event_handlers/im_spec.rb +31 -27
  255. data/spec/slack/real_time/event_handlers/{group_spec.rb → private_channel_spec.rb} +36 -27
  256. data/spec/slack/real_time/event_handlers/{channel_spec.rb → public_channel_spec.rb} +31 -24
  257. data/spec/slack/real_time/event_handlers/team_spec.rb +8 -7
  258. data/spec/slack/real_time/event_handlers/user_spec.rb +7 -5
  259. data/spec/slack/real_time/rtm_connect_spec.rb +2 -1
  260. data/spec/slack/real_time/stores/store_spec.rb +50 -0
  261. data/spec/slack/slack_spec.rb +41 -6
  262. data/spec/slack/version_spec.rb +2 -1
  263. data/spec/slack/web/api/endpoints/admin_analytics_spec.rb +13 -0
  264. data/spec/slack/web/api/endpoints/admin_apps_approved_spec.rb +8 -0
  265. data/spec/slack/web/api/endpoints/admin_apps_requests_spec.rb +13 -0
  266. data/spec/slack/web/api/endpoints/admin_apps_restricted_spec.rb +8 -0
  267. data/spec/slack/web/api/endpoints/admin_apps_spec.rb +18 -0
  268. data/spec/slack/web/api/endpoints/admin_audit_anomaly_allow_spec.rb +8 -0
  269. data/spec/slack/web/api/endpoints/admin_auth_policy_spec.rb +35 -0
  270. data/spec/slack/web/api/endpoints/admin_barriers_spec.rb +38 -0
  271. data/spec/slack/web/api/endpoints/admin_conversations_ekm_spec.rb +8 -0
  272. data/spec/slack/web/api/endpoints/admin_conversations_restrictAccess_spec.rb +32 -0
  273. data/spec/slack/web/api/endpoints/admin_conversations_spec.rb +98 -0
  274. data/spec/slack/web/api/endpoints/admin_emoji_spec.rb +37 -0
  275. data/spec/slack/web/api/endpoints/admin_inviteRequests_approved_spec.rb +8 -0
  276. data/spec/slack/web/api/endpoints/admin_inviteRequests_denied_spec.rb +8 -0
  277. data/spec/slack/web/api/endpoints/admin_inviteRequests_spec.rb +18 -0
  278. data/spec/slack/web/api/endpoints/admin_teams_admins_spec.rb +13 -0
  279. data/spec/slack/web/api/endpoints/admin_teams_owners_spec.rb +13 -0
  280. data/spec/slack/web/api/endpoints/admin_teams_settings_spec.rb +53 -0
  281. data/spec/slack/web/api/endpoints/admin_teams_spec.rb +16 -0
  282. data/spec/slack/web/api/endpoints/admin_usergroups_spec.rb +37 -0
  283. data/spec/slack/web/api/endpoints/admin_users_session_spec.rb +41 -0
  284. data/spec/slack/web/api/endpoints/admin_users_spec.rb +67 -0
  285. data/spec/slack/web/api/endpoints/admin_users_unsupportedVersions_spec.rb +8 -0
  286. data/spec/slack/web/api/endpoints/api_spec.rb +1 -0
  287. data/spec/slack/web/api/endpoints/apps_connections_spec.rb +8 -0
  288. data/spec/slack/web/api/endpoints/apps_event_authorizations_spec.rb +13 -0
  289. data/spec/slack/web/api/endpoints/apps_manifest_spec.rb +36 -0
  290. data/spec/slack/web/api/endpoints/apps_spec.rb +16 -0
  291. data/spec/slack/web/api/endpoints/{apps_permissions_resources_spec.rb → auth_teams_spec.rb} +2 -1
  292. data/spec/slack/web/api/endpoints/bookmarks_spec.rb +40 -0
  293. data/spec/slack/web/api/endpoints/bots_spec.rb +1 -0
  294. data/spec/slack/web/api/endpoints/calls_participants_spec.rb +24 -0
  295. data/spec/slack/web/api/endpoints/calls_spec.rb +31 -0
  296. data/spec/slack/web/api/endpoints/chat_scheduledMessages_spec.rb +8 -0
  297. data/spec/slack/web/api/endpoints/custom_specs/auth_spec.rb +9 -7
  298. data/spec/slack/web/api/endpoints/custom_specs/chat_spec.rb +144 -40
  299. data/spec/slack/web/api/endpoints/custom_specs/conversations_spec.rb +13 -0
  300. data/spec/slack/web/api/endpoints/custom_specs/dialog_spec.rb +18 -6
  301. data/spec/slack/web/api/endpoints/custom_specs/users_spec.rb +8 -3
  302. data/spec/slack/web/api/endpoints/custom_specs/views_spec.rb +112 -0
  303. data/spec/slack/web/api/endpoints/dnd_spec.rb +4 -3
  304. data/spec/slack/web/api/endpoints/emoji_spec.rb +1 -0
  305. data/spec/slack/web/api/endpoints/files_comments_spec.rb +3 -21
  306. data/spec/slack/web/api/endpoints/files_remote_spec.rb +24 -0
  307. data/spec/slack/web/api/endpoints/files_spec.rb +18 -4
  308. data/spec/slack/web/api/endpoints/migration_spec.rb +1 -0
  309. data/spec/slack/web/api/endpoints/oauth_spec.rb +1 -22
  310. data/spec/slack/web/api/endpoints/oauth_v2_spec.rb +16 -0
  311. data/spec/slack/web/api/endpoints/openid_connect_spec.rb +8 -0
  312. data/spec/slack/web/api/endpoints/pins_spec.rb +1 -0
  313. data/spec/slack/web/api/endpoints/reactions_spec.rb +8 -1
  314. data/spec/slack/web/api/endpoints/reminders_spec.rb +3 -2
  315. data/spec/slack/web/api/endpoints/rtm_spec.rb +1 -0
  316. data/spec/slack/web/api/endpoints/search_spec.rb +1 -0
  317. data/spec/slack/web/api/endpoints/stars_spec.rb +1 -0
  318. data/spec/slack/web/api/endpoints/{apps_permissions_scopes_spec.rb → team_billing_spec.rb} +2 -1
  319. data/spec/slack/web/api/endpoints/team_preferences_spec.rb +8 -0
  320. data/spec/slack/web/api/endpoints/team_profile_spec.rb +1 -0
  321. data/spec/slack/web/api/endpoints/team_spec.rb +1 -0
  322. data/spec/slack/web/api/endpoints/tooling_tokens_spec.rb +13 -0
  323. data/spec/slack/web/api/endpoints/usergroups_spec.rb +1 -0
  324. data/spec/slack/web/api/endpoints/usergroups_users_spec.rb +3 -2
  325. data/spec/slack/web/api/endpoints/users_admin_spec.rb +1 -0
  326. data/spec/slack/web/api/endpoints/users_prefs_spec.rb +1 -0
  327. data/spec/slack/web/api/endpoints/users_profile_spec.rb +1 -0
  328. data/spec/slack/web/api/endpoints/workflows_spec.rb +26 -0
  329. data/spec/slack/web/api/error_spec.rb +7 -7
  330. data/spec/slack/web/api/errors/slack_error_spec.rb +26 -7
  331. data/spec/slack/web/api/mixins/conversations_list_spec.rb +21 -0
  332. data/spec/slack/web/api/mixins/conversations_spec.rb +45 -0
  333. data/spec/slack/web/api/mixins/users_spec.rb +19 -8
  334. data/spec/slack/web/api/pagination/cursor_spec.rb +47 -15
  335. data/spec/slack/web/client_spec.rb +199 -22
  336. data/spec/slack/web/faraday/request_spec.rb +80 -0
  337. data/spec/slack/web/faraday/response/raise_error_spec.rb +48 -12
  338. data/spec/spec_helper.rb +9 -2
  339. data/spec/support/queue_with_timeout.rb +5 -4
  340. data/spec/support/real_time/concurrency/mock.rb +1 -0
  341. data/spec/support/real_time/connected_client.rb +6 -6
  342. data/spec/support/real_time/event.rb +1 -0
  343. data/spec/support/real_time/loaded_client.rb +120 -0
  344. data/spec/support/token.rb +1 -0
  345. data/spec/support/vcr.rb +37 -1
  346. metadata +174 -262
  347. data/.travis.yml +0 -32
  348. data/bin/commands/apps_permissions.rb +0 -22
  349. data/bin/commands/apps_permissions_resources.rb +0 -14
  350. data/bin/commands/apps_permissions_scopes.rb +0 -12
  351. data/bin/commands/apps_permissions_users.rb +0 -25
  352. data/bin/commands/channels.rb +0 -175
  353. data/bin/commands/groups.rb +0 -174
  354. data/bin/commands/im.rb +0 -67
  355. data/bin/commands/mpim.rb +0 -65
  356. data/examples/hi_real_time/Gemfile +0 -5
  357. data/examples/hi_real_time/hi.gif +0 -0
  358. data/examples/hi_real_time/hi.rb +0 -37
  359. data/examples/hi_real_time_async_celluloid/Gemfile +0 -6
  360. data/examples/hi_real_time_async_celluloid/Procfile +0 -2
  361. data/examples/hi_real_time_async_celluloid/hi.rb +0 -35
  362. data/examples/hi_real_time_async_eventmachine/Gemfile +0 -6
  363. data/examples/hi_real_time_async_eventmachine/Procfile +0 -2
  364. data/examples/hi_real_time_async_eventmachine/hi.rb +0 -35
  365. data/lib/slack/real_time/concurrency/celluloid.rb +0 -118
  366. data/lib/slack/real_time/concurrency/eventmachine.rb +0 -66
  367. data/lib/slack/web/api/endpoints/apps_permissions.rb +0 -35
  368. data/lib/slack/web/api/endpoints/apps_permissions_resources.rb +0 -30
  369. data/lib/slack/web/api/endpoints/apps_permissions_scopes.rb +0 -20
  370. data/lib/slack/web/api/endpoints/apps_permissions_users.rb +0 -49
  371. data/lib/slack/web/api/endpoints/channels.rb +0 -266
  372. data/lib/slack/web/api/endpoints/groups.rb +0 -265
  373. data/lib/slack/web/api/endpoints/im.rb +0 -113
  374. data/lib/slack/web/api/endpoints/mpim.rb +0 -108
  375. data/lib/slack/web/api/endpoints/presence.rb +0 -23
  376. data/lib/slack/web/api/mixins/channels.id.json +0 -20
  377. data/lib/slack/web/api/mixins/groups.id.json +0 -20
  378. data/lib/slack/web/api/mixins/groups.id.rb +0 -26
  379. data/lib/slack/web/api/patches/chat.1.text-attachments-required.patch +0 -13
  380. data/lib/slack/web/api/patches/chat.2.attachments-json.patch +0 -17
  381. data/lib/slack/web/api/patches/chat.3.update-attachments-support.patch +0 -21
  382. data/lib/slack/web/api/patches/chat.4.postEphemeral-attachments-support.patch +0 -17
  383. data/lib/slack/web/api/patches/chat.5.postEphemeral-text-or-attachments.patch +0 -13
  384. data/screenshots/register-bot.png +0 -0
  385. data/spec/fixtures/slack/web/503_error.yml +0 -14
  386. data/spec/fixtures/slack/web/channels_info.yml +0 -46
  387. data/spec/fixtures/slack/web/groups_info.yml +0 -43
  388. data/spec/fixtures/slack/web/rtm_start.yml +0 -104
  389. data/spec/slack/real_time/concurrency/celluloid_spec.rb +0 -106
  390. data/spec/slack/real_time/concurrency/eventmachine_spec.rb +0 -47
  391. data/spec/slack/real_time/rtm_start_spec.rb +0 -13
  392. data/spec/slack/real_time/store_spec.rb +0 -11
  393. data/spec/slack/web/api/endpoints/apps_permissions_spec.rb +0 -15
  394. data/spec/slack/web/api/endpoints/apps_permissions_users_spec.rb +0 -18
  395. data/spec/slack/web/api/endpoints/conversations_spec.rb +0 -100
  396. data/spec/slack/web/api/endpoints/custom_specs/channels_spec.rb +0 -11
  397. data/spec/slack/web/api/endpoints/custom_specs/groups_spec.rb +0 -11
  398. data/spec/slack/web/api/endpoints/im_spec.rb +0 -38
  399. data/spec/slack/web/api/endpoints/mpim_spec.rb +0 -38
  400. data/spec/slack/web/api/errors/service_unavailable_spec.rb +0 -14
  401. data/spec/slack/web/api/mixins/channels_spec.rb +0 -33
  402. data/spec/slack/web/api/mixins/groups_spec.rb +0 -33
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  class Client
4
5
  class ClientNotStartedError < StandardError; end
6
+
5
7
  class ClientAlreadyStartedError < StandardError; end
6
8
 
7
9
  include Api::MessageId
@@ -9,19 +11,9 @@ module Slack
9
11
  include Api::Message
10
12
  include Api::Typing
11
13
 
12
- @events = {}
13
-
14
- class << self
15
- attr_accessor :events
16
- end
17
-
18
- attr_accessor :web_client
19
- attr_accessor :store
20
- attr_accessor :url
21
- attr_accessor(*Config::ATTRIBUTES)
14
+ attr_accessor :web_client, :store, :url, *Config::ATTRIBUTES
22
15
 
23
- protected :logger, :logger=
24
- protected :store_class, :store_class=
16
+ protected :store_class, :store_class=, :store_options, :store_options=
25
17
 
26
18
  def initialize(options = {})
27
19
  @callbacks = Hash.new { |h, k| h[k] = [] }
@@ -33,9 +25,9 @@ module Slack
33
25
  @web_client = Slack::Web::Client.new(token: token, logger: logger)
34
26
  end
35
27
 
36
- %i[users self channels team teams groups ims bots].each do |store_method|
28
+ [:self, :team, *Stores::Base::CACHES].each do |store_method|
37
29
  define_method store_method do
38
- store.send(store_method) if store
30
+ store&.send(store_method)
39
31
  end
40
32
  end
41
33
 
@@ -46,26 +38,27 @@ module Slack
46
38
 
47
39
  # Start RealTime client and block until it disconnects.
48
40
  def start!(&block)
49
- @callback = block if block_given?
50
- @socket = build_socket
41
+ @callback = block if block
42
+ build_socket
51
43
  @socket.start_sync(self)
52
44
  end
53
45
 
54
46
  # Start RealTime client and return immediately.
55
47
  # The RealTime::Client will run in the background.
56
48
  def start_async(&block)
57
- @callback = block if block_given?
58
- @socket = build_socket
49
+ @callback = block if block
50
+ build_socket
59
51
  @socket.start_async(self)
60
52
  end
61
53
 
62
54
  def stop!
63
55
  raise ClientNotStartedError unless started?
64
- @socket.disconnect! if @socket
56
+
57
+ @socket&.disconnect!
65
58
  end
66
59
 
67
60
  def started?
68
- @socket && @socket.connected?
61
+ @socket&.connected?
69
62
  end
70
63
 
71
64
  class << self
@@ -80,48 +73,105 @@ module Slack
80
73
 
81
74
  def run_loop
82
75
  @socket.connect! do |driver|
83
- @callback.call(driver) if @callback
84
-
85
76
  driver.on :open do |event|
86
- logger.debug("#{self.class}##{__method__}") { event.class.name }
87
- open(event)
77
+ logger.debug("#{self}##{__method__}") { event.class.name }
78
+ open_event(event)
88
79
  callback(event, :open)
89
80
  end
90
81
 
91
82
  driver.on :message do |event|
92
- logger.debug("#{self.class}##{__method__}") { "#{event.class}, #{event.data}" }
83
+ logger.debug("#{self}##{__method__}") { "#{event.class}, #{event.data}" }
93
84
  dispatch(event)
94
85
  end
95
86
 
96
87
  driver.on :close do |event|
97
- logger.debug("#{self.class}##{__method__}") { event.class.name }
88
+ logger.debug("#{self}##{__method__}") { event.class.name }
98
89
  callback(event, :close)
99
90
  close(event)
100
91
  callback(event, :closed)
101
92
  end
93
+
94
+ # This must be called last to ensure any events are registered before invoking user code.
95
+ @callback&.call(driver)
96
+ end
97
+ end
98
+
99
+ # Ensure the server is running, and ping the remote server if no other messages were sent.
100
+ def keep_alive?
101
+ # We can't ping the remote server if we aren't connected.
102
+ return false if @socket.nil? || !@socket.connected?
103
+
104
+ time_since_last_message = @socket.time_since_last_message
105
+
106
+ # If the server responded within the specified time, we are okay:
107
+ return true if time_since_last_message < websocket_ping
108
+
109
+ # If the server has not responded for a while:
110
+ return false if time_since_last_message > (websocket_ping * 2)
111
+
112
+ # Kick off the next ping message:
113
+ ping
114
+
115
+ true
116
+ end
117
+
118
+ # Check if the remote server is responsive, and if not, restart the connection.
119
+ def run_ping!
120
+ return if keep_alive?
121
+
122
+ logger.warn(to_s) { 'is offline' }
123
+
124
+ restart_async
125
+ rescue Slack::Web::Api::Errors::SlackError => e
126
+ # stop pinging if bot was uninstalled
127
+ case e.message
128
+ when 'account_inactive', 'invalid_auth'
129
+ logger.warn(to_s) { e.message }
130
+ raise e
131
+ end
132
+ logger.debug("#{self}##{__method__}") { e }
133
+ rescue StandardError => e
134
+ # disregard all ping worker failures, keep pinging
135
+ logger.debug("#{self}##{__method__}") { e }
136
+ end
137
+
138
+ def run_ping?
139
+ !websocket_ping.nil? && websocket_ping.positive?
140
+ end
141
+
142
+ def websocket_ping_timer
143
+ websocket_ping / 2
144
+ end
145
+
146
+ def to_s
147
+ if store&.team
148
+ "id=#{store.team.id}, name=#{store.team.name}, domain=#{store.team.domain}"
149
+ else
150
+ super
102
151
  end
103
152
  end
104
153
 
105
154
  protected
106
155
 
156
+ def restart_async
157
+ logger.debug("#{self}##{__method__}")
158
+ @socket.close
159
+ start = web_client.rtm_connect(start_options)
160
+ data = Slack::Messages::Message.new(start)
161
+ @url = data.url
162
+ @store = store_class.new(data, store_options.to_h) if store_class
163
+ @socket.restart_async(self, @url)
164
+ end
165
+
107
166
  # @return [Slack::RealTime::Socket]
108
167
  def build_socket
109
168
  raise ClientAlreadyStartedError if started?
110
- start = web_client.send(rtm_start_method, start_options)
169
+
170
+ start = web_client.rtm_connect(start_options)
111
171
  data = Slack::Messages::Message.new(start)
112
172
  @url = data.url
113
- @store = @store_class.new(data) if @store_class
114
- socket_class.new(@url, socket_options)
115
- end
116
-
117
- def rtm_start_method
118
- if start_method
119
- start_method
120
- elsif @store_class && @store_class <= Slack::RealTime::Stores::Store
121
- :rtm_start
122
- else
123
- :rtm_connect
124
- end
173
+ @store = store_class.new(data, store_options.to_h) if store_class
174
+ @socket = socket_class.new(@url, socket_options)
125
175
  end
126
176
 
127
177
  def socket_options
@@ -133,23 +183,22 @@ module Slack
133
183
  end
134
184
 
135
185
  attr_reader :callbacks
186
+
136
187
  def socket_class
137
188
  concurrency::Socket
138
189
  end
139
190
 
140
191
  def send_json(data)
141
192
  raise ClientNotStartedError unless started?
142
- logger.debug("#{self.class}##{__method__}") { data }
193
+
194
+ logger.debug("#{self}##{__method__}") { data }
143
195
  @socket.send_data(data.to_json)
144
196
  end
145
197
 
146
- def open(_event); end
198
+ def open_event(_event); end
147
199
 
148
200
  def close(_event)
149
- socket = @socket
150
- @socket = nil
151
-
152
- [socket, socket_class].each do |s|
201
+ [@socket, socket_class].each do |s|
153
202
  s.close if s.respond_to?(:close)
154
203
  end
155
204
  end
@@ -157,50 +206,52 @@ module Slack
157
206
  def callback(event, type)
158
207
  callbacks = self.callbacks[type.to_s]
159
208
  return false unless callbacks
209
+
160
210
  callbacks.each do |c|
161
211
  c.call(event)
162
212
  end
163
213
  true
164
214
  rescue StandardError => e
165
- logger.error e
215
+ logger.error("#{self}##{__method__}") { e }
166
216
  false
167
217
  end
168
218
 
169
219
  def dispatch(event)
170
220
  return false unless event.data
221
+
171
222
  data = Slack::Messages::Message.new(JSON.parse(event.data))
172
223
  type = data.type
173
224
  return false unless type
225
+
174
226
  type = type.to_s
175
- logger.debug("#{self.class}##{__method__}") { data.to_s }
227
+ logger.debug("#{self}##{__method__}") { data.to_s }
176
228
  run_handlers(type, data) if @store
177
229
  run_callbacks(type, data)
178
230
  rescue StandardError => e
179
- logger.error e
231
+ logger.error("#{self}##{__method__}") { e }
180
232
  false
181
233
  end
182
234
 
183
235
  def run_handlers(type, data)
184
236
  handlers = store.class.events[type.to_s]
185
- if handlers
186
- handlers.each do |handler|
187
- store.instance_exec(data, &handler)
188
- end
237
+ handlers.each do |handler|
238
+ store.instance_exec(data, self, &handler)
189
239
  end
190
240
  rescue StandardError => e
191
- logger.error e
241
+ logger.error("#{self}##{__method__}") { e }
192
242
  false
193
243
  end
194
244
 
195
245
  def run_callbacks(type, data)
196
246
  callbacks = self.callbacks[type]
197
247
  return false unless callbacks
248
+
198
249
  callbacks.each do |c|
199
250
  c.call(data)
200
251
  end
201
252
  true
202
253
  rescue StandardError => e
203
- logger.error e
254
+ logger.error("#{self}##{__method__}") { e }
204
255
  false
205
256
  end
206
257
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  require 'async/websocket'
3
+ require 'async/notification'
4
+ require 'async/clock'
2
5
 
3
6
  module Slack
4
7
  module RealTime
@@ -12,28 +15,89 @@ module Slack
12
15
  class Socket < Slack::RealTime::Socket
13
16
  attr_reader :client
14
17
 
18
+ def start_sync(client)
19
+ start_reactor(client).wait
20
+ end
21
+
15
22
  def start_async(client)
16
23
  Thread.new do
17
- ::Async::Reactor.run do
18
- client.run_loop
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
+ subtask.annotate "#{client} run-loop"
49
+ client.run_loop
50
+ rescue ::Async::Wrapper::Cancelled => e
51
+ # Will get restarted by ping worker.
52
+ rescue StandardError => e
53
+ client.logger.error(subtask.to_s) { e.message }
54
+ end
55
+
56
+ @restart.wait
19
57
  end
58
+
59
+ @ping_task&.stop
20
60
  end
21
61
  end
22
62
 
63
+ def restart_async(_client, new_url)
64
+ @url = new_url
65
+ @last_message_at = current_time
66
+
67
+ @restart&.signal
68
+ end
69
+
70
+ def current_time
71
+ ::Async::Clock.now
72
+ end
73
+
23
74
  def connect!
24
75
  super
25
76
  run_loop
26
77
  end
27
78
 
79
+ # Kill the restart/ping loop.
80
+ def disconnect!
81
+ super
82
+ ensure
83
+ if (restart = @restart)
84
+ @restart = nil
85
+ restart.signal
86
+ end
87
+ end
88
+
89
+ # Close the socket.
28
90
  def close
29
- @closing = true
30
- @driver.close if @driver
31
91
  super
92
+ ensure
93
+ if @socket
94
+ @socket.close
95
+ @socket = nil
96
+ end
32
97
  end
33
98
 
34
99
  def run_loop
35
- @closing = false
36
- while @driver && @driver.next_event
100
+ while @driver&.next_event
37
101
  # $stderr.puts event.inspect
38
102
  end
39
103
  end
@@ -65,3 +129,10 @@ module Slack
65
129
  end
66
130
  end
67
131
  end
132
+
133
+ if Gem::Version.new(Async::WebSocket::VERSION) >= Gem::Version.new('0.9.0')
134
+ raise(
135
+ "Incompatible version of async-websocket, #{Async::WebSocket::VERSION}, " \
136
+ "use \"gem 'async-websocket', '~> 0.8.0'\"."
137
+ )
138
+ end
@@ -1,9 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Concurrency
4
5
  autoload :Async, 'slack/real_time/concurrency/async'
5
- autoload :Eventmachine, 'slack/real_time/concurrency/eventmachine'
6
- autoload :Celluloid, 'slack/real_time/concurrency/celluloid'
7
6
  end
8
7
  end
9
8
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Config
@@ -10,22 +11,23 @@ module Slack
10
11
  websocket_ping
11
12
  websocket_proxy
12
13
  concurrency
13
- start_method
14
14
  start_options
15
15
  store_class
16
+ store_options
16
17
  logger
17
18
  ].freeze
18
19
 
19
- attr_accessor(*Config::ATTRIBUTES)
20
+ attr_accessor(*Config::ATTRIBUTES - [:concurrency])
21
+ attr_writer :concurrency
20
22
 
21
23
  def reset
22
24
  self.websocket_ping = 30
23
25
  self.websocket_proxy = nil
24
26
  self.token = nil
25
27
  self.concurrency = method(:detect_concurrency)
26
- self.start_method = nil
27
28
  self.start_options = { request: { timeout: 180 } }
28
- self.store_class = Slack::RealTime::Store
29
+ self.store_class = Slack::RealTime::Stores::Starter
30
+ self.store_options = {}
29
31
  self.logger = nil
30
32
  end
31
33
 
@@ -36,15 +38,9 @@ module Slack
36
38
  private
37
39
 
38
40
  def detect_concurrency
39
- %i[Async Eventmachine Celluloid].each do |concurrency|
40
- begin
41
- return Slack::RealTime::Concurrency.const_get(concurrency)
42
- rescue LoadError, NameError
43
- false # could not be loaded, missing dependencies
44
- end
45
- end
46
-
47
- raise NoConcurrencyError, 'Missing concurrency. Add async-websocket, faye-websocket or celluloid-io to your Gemfile.'
41
+ Slack::RealTime::Concurrency.const_get(:Async)
42
+ rescue LoadError, NameError
43
+ raise NoConcurrencyError, 'Missing concurrency. Add async-websocket to your Gemfile.'
48
44
  end
49
45
  end
50
46
 
@@ -1,11 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Models
4
5
  class Base < Hashie::Mash
5
- def presence
6
- super['presence']
7
- end
8
-
9
6
  # see https://github.com/intridea/hashie/issues/394
10
7
  def log_built_in_message(*); end
11
8
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Models
@@ -1,7 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Slack
2
4
  module RealTime
3
5
  module Models
4
6
  class Channel < Base
7
+ def is_public? # rubocop:disable Naming/PredicateName
8
+ !is_private?
9
+ end
5
10
  end
6
11
  end
7
12
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Models
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Models
4
- class Group < Base
5
+ class Mpim < Base
5
6
  end
6
7
  end
7
8
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Models
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Models
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'models/base'
2
4
  require_relative 'models/user'
3
5
  require_relative 'models/bot'
4
6
  require_relative 'models/channel'
5
- require_relative 'models/group'
6
7
  require_relative 'models/team'
7
8
  require_relative 'models/im'
9
+ require_relative 'models/mpim'
@@ -1,25 +1,24 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  class Socket
4
- attr_accessor :url
5
- attr_accessor :options
5
+ attr_accessor :url, :options
6
6
  attr_reader :driver
7
- attr_reader :logger
8
- protected :logger
9
7
 
10
8
  def initialize(url, options = {})
11
9
  @url = url
12
- @options = options
10
+ @options = options.dup
13
11
  @driver = nil
14
- @logger = options.delete(:logger) || Slack::RealTime::Config.logger || Slack::Config.logger
12
+ @logger = @options.delete(:logger) || Slack::RealTime::Config.logger || Slack::Config.logger
13
+ @last_message_at = nil
15
14
  end
16
15
 
17
16
  def send_data(message)
18
17
  logger.debug("#{self.class}##{__method__}") { message }
19
18
  case message
20
- when Numeric then driver.text(message.to_s)
21
- when String then driver.text(message)
22
- when Array then driver.binary(message)
19
+ when Numeric then @driver.text(message.to_s)
20
+ when String then @driver.text(message)
21
+ when Array then @driver.binary(message)
23
22
  else false
24
23
  end
25
24
  end
@@ -28,24 +27,31 @@ module Slack
28
27
  return if connected?
29
28
 
30
29
  connect
31
- logger.debug("#{self.class}##{__method__}") { driver.class }
30
+ logger.debug("#{self.class}##{__method__}") { @driver.class }
31
+
32
+ @driver.on :message do
33
+ @last_message_at = current_time
34
+ end
32
35
 
33
- yield driver if block_given?
36
+ yield @driver if block_given?
34
37
  end
35
38
 
39
+ # Gracefully shut down the connection.
36
40
  def disconnect!
37
- driver.close
41
+ @driver.close
42
+ ensure
43
+ close
38
44
  end
39
45
 
40
46
  def connected?
41
- !driver.nil?
47
+ !@driver.nil?
42
48
  end
43
49
 
44
50
  def start_sync(client)
45
51
  thread = start_async(client)
46
- thread.join if thread
52
+ thread&.join
47
53
  rescue Interrupt
48
- thread.exit if thread
54
+ thread&.exit
49
55
  end
50
56
 
51
57
  # @return [#join]
@@ -53,12 +59,34 @@ module Slack
53
59
  raise NotImplementedError, "Expected #{self.class} to implement #{__method__}."
54
60
  end
55
61
 
62
+ def restart_async(_client, _url)
63
+ raise NotImplementedError, "Expected #{self.class} to implement #{__method__}."
64
+ end
65
+
66
+ def time_since_last_message
67
+ return 0 unless @last_message_at
68
+
69
+ current_time - @last_message_at
70
+ end
71
+
72
+ def current_time
73
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
74
+ end
75
+
56
76
  def close
77
+ # When you call `driver.emit(:close)`, it will typically end up calling `client.close`
78
+ # which will call `@socket.close` and end up back here. In order to break this infinite
79
+ # recursion, we check and set `@driver = nil` before invoking `client.close`.
80
+ return unless (driver = @driver)
81
+
57
82
  @driver = nil
83
+ driver.emit(:close)
58
84
  end
59
85
 
60
86
  protected
61
87
 
88
+ attr_reader :logger
89
+
62
90
  def addr
63
91
  URI(url).host
64
92
  end
@@ -69,9 +97,9 @@ module Slack
69
97
 
70
98
  def port
71
99
  case (uri = URI(url)).scheme
72
- when 'wss'.freeze, 'https'.freeze
100
+ when 'wss', 'https'
73
101
  URI::HTTPS::DEFAULT_PORT
74
- when 'ws', 'http'.freeze
102
+ when 'ws', 'http'
75
103
  URI::HTTP::DEFAULT_PORT
76
104
  else
77
105
  uri.port