slack-ruby-client 0.13.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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