slack-ruby-client-bhe 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +17 -0
- data/.gitignore +4 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +6 -0
- data/.rubocop_todo.yml +78 -0
- data/.travis.yml +26 -0
- data/CHANGELOG.md +79 -0
- data/CONTRIBUTING.md +157 -0
- data/Gemfile +5 -0
- data/LICENSE.md +22 -0
- data/README.md +385 -0
- data/RELEASING.md +69 -0
- data/Rakefile +19 -0
- data/UPGRADING.md +26 -0
- data/bin/commands.rb +21 -0
- data/bin/commands/api.rb +14 -0
- data/bin/commands/auth.rb +12 -0
- data/bin/commands/channels.rb +149 -0
- data/bin/commands/chat.rb +47 -0
- data/bin/commands/dnd.rb +47 -0
- data/bin/commands/emoji.rb +12 -0
- data/bin/commands/files.rb +72 -0
- data/bin/commands/groups.rb +167 -0
- data/bin/commands/im.rb +53 -0
- data/bin/commands/mpim.rb +53 -0
- data/bin/commands/oauth.rb +16 -0
- data/bin/commands/pins.rb +37 -0
- data/bin/commands/reactions.rb +53 -0
- data/bin/commands/rtm.rb +15 -0
- data/bin/commands/search.rb +40 -0
- data/bin/commands/stars.rb +37 -0
- data/bin/commands/team.rb +32 -0
- data/bin/commands/usergroups.rb +73 -0
- data/bin/commands/users.rb +57 -0
- data/bin/slack +50 -0
- data/examples/hi_real_time/Gemfile +5 -0
- data/examples/hi_real_time/hi.gif +0 -0
- data/examples/hi_real_time/hi.rb +32 -0
- data/examples/hi_real_time_and_web/Gemfile +5 -0
- data/examples/hi_real_time_and_web/hi.gif +0 -0
- data/examples/hi_real_time_and_web/hi.rb +24 -0
- data/examples/hi_real_time_async/Gemfile +5 -0
- data/examples/hi_real_time_async/hi.rb +29 -0
- data/examples/hi_web/Gemfile +3 -0
- data/examples/hi_web/hi.gif +0 -0
- data/examples/hi_web/hi.rb +12 -0
- data/examples/new_ticket/Gemfile +3 -0
- data/examples/new_ticket/new_ticket.rb +25 -0
- data/lib/slack-ruby-client.rb +29 -0
- data/lib/slack.rb +1 -0
- data/lib/slack/config.rb +21 -0
- data/lib/slack/messages/formatting.rb +30 -0
- data/lib/slack/real_time/api/message.rb +20 -0
- data/lib/slack/real_time/api/message_id.rb +14 -0
- data/lib/slack/real_time/api/ping.rb +16 -0
- data/lib/slack/real_time/api/typing.rb +17 -0
- data/lib/slack/real_time/client.rb +152 -0
- data/lib/slack/real_time/concurrency.rb +8 -0
- data/lib/slack/real_time/concurrency/celluloid.rb +93 -0
- data/lib/slack/real_time/concurrency/eventmachine.rb +39 -0
- data/lib/slack/real_time/config.rb +55 -0
- data/lib/slack/real_time/socket.rb +81 -0
- data/lib/slack/version.rb +3 -0
- data/lib/slack/web/api/endpoints.rb +53 -0
- data/lib/slack/web/api/endpoints/api.rb +24 -0
- data/lib/slack/web/api/endpoints/auth.rb +20 -0
- data/lib/slack/web/api/endpoints/channels.rb +220 -0
- data/lib/slack/web/api/endpoints/chat.rb +91 -0
- data/lib/slack/web/api/endpoints/dnd.rb +64 -0
- data/lib/slack/web/api/endpoints/emoji.rb +20 -0
- data/lib/slack/web/api/endpoints/files.rb +108 -0
- data/lib/slack/web/api/endpoints/groups.rb +247 -0
- data/lib/slack/web/api/endpoints/im.rb +85 -0
- data/lib/slack/web/api/endpoints/mpim.rb +84 -0
- data/lib/slack/web/api/endpoints/oauth.rb +32 -0
- data/lib/slack/web/api/endpoints/pins.rb +64 -0
- data/lib/slack/web/api/endpoints/presence.rb +23 -0
- data/lib/slack/web/api/endpoints/reactions.rb +89 -0
- data/lib/slack/web/api/endpoints/rtm.rb +27 -0
- data/lib/slack/web/api/endpoints/search.rb +65 -0
- data/lib/slack/web/api/endpoints/stars.rb +61 -0
- data/lib/slack/web/api/endpoints/team.rb +47 -0
- data/lib/slack/web/api/endpoints/usergroups.rb +113 -0
- data/lib/slack/web/api/endpoints/users.rb +73 -0
- data/lib/slack/web/api/error.rb +14 -0
- data/lib/slack/web/api/mixins.rb +3 -0
- data/lib/slack/web/api/mixins/channels.id.json +20 -0
- data/lib/slack/web/api/mixins/channels.id.rb +26 -0
- data/lib/slack/web/api/mixins/groups.id.json +20 -0
- data/lib/slack/web/api/mixins/groups.id.rb +26 -0
- data/lib/slack/web/api/mixins/users.id.json +20 -0
- data/lib/slack/web/api/mixins/users.id.rb +26 -0
- data/lib/slack/web/api/patches/chat.1.text-attachments-required.patch +13 -0
- data/lib/slack/web/api/patches/chat.2.attachments-json.patch +17 -0
- data/lib/slack/web/api/schema/group.json +14 -0
- data/lib/slack/web/api/schema/method.json +45 -0
- data/lib/slack/web/api/tasks/generate.rake +61 -0
- data/lib/slack/web/api/templates/command.erb +34 -0
- data/lib/slack/web/api/templates/commands.erb +5 -0
- data/lib/slack/web/api/templates/endpoints.erb +21 -0
- data/lib/slack/web/api/templates/method.erb +49 -0
- data/lib/slack/web/client.rb +28 -0
- data/lib/slack/web/config.rb +41 -0
- data/lib/slack/web/faraday/connection.rb +29 -0
- data/lib/slack/web/faraday/request.rb +39 -0
- data/lib/slack/web/faraday/response/raise_error.rb +15 -0
- data/lib/slack_ruby_client.rb +1 -0
- data/screenshots/register-bot.png +0 -0
- data/slack-ruby-client.gemspec +31 -0
- data/slack.png +0 -0
- data/spec/fixtures/slack/web/429_error.yml +83 -0
- data/spec/fixtures/slack/web/auth_test_error.yml +48 -0
- data/spec/fixtures/slack/web/auth_test_success.yml +57 -0
- data/spec/fixtures/slack/web/channels_info.yml +46 -0
- data/spec/fixtures/slack/web/groups_info.yml +43 -0
- data/spec/fixtures/slack/web/rtm_start.yml +73 -0
- data/spec/fixtures/slack/web/users_info.yml +130 -0
- data/spec/fixtures/slack/web/users_list.yml +72 -0
- data/spec/integration/integration_spec.rb +107 -0
- data/spec/slack/config_spec.rb +14 -0
- data/spec/slack/messages/formatting_spec.rb +43 -0
- data/spec/slack/real_time/api/message_spec.rb +15 -0
- data/spec/slack/real_time/api/ping_spec.rb +15 -0
- data/spec/slack/real_time/api/typing_spec.rb +15 -0
- data/spec/slack/real_time/client_spec.rb +198 -0
- data/spec/slack/real_time/concurrency/celluloid_spec.rb +58 -0
- data/spec/slack/real_time/concurrency/eventmachine_spec.rb +49 -0
- data/spec/slack/slack_spec.rb +58 -0
- data/spec/slack/version_spec.rb +7 -0
- data/spec/slack/web/api/endpoints/auth_spec.rb +20 -0
- data/spec/slack/web/api/endpoints/channels_spec.rb +11 -0
- data/spec/slack/web/api/endpoints/chat_spec.rb +33 -0
- data/spec/slack/web/api/endpoints/groups_spec.rb +11 -0
- data/spec/slack/web/api/endpoints/users_spec.rb +17 -0
- data/spec/slack/web/api/error_spec.rb +14 -0
- data/spec/slack/web/api/mixins/channels_spec.rb +31 -0
- data/spec/slack/web/api/mixins/groups_spec.rb +31 -0
- data/spec/slack/web/api/mixins/users_spec.rb +31 -0
- data/spec/slack/web/client_spec.rb +134 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/queue_with_timeout.rb +34 -0
- data/spec/support/real_time/concurrency/mock.rb +31 -0
- data/spec/support/real_time/connected_client.rb +16 -0
- data/spec/support/token.rb +10 -0
- data/spec/support/vcr.rb +8 -0
- metadata +392 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Slack
|
2
|
+
module RealTime
|
3
|
+
module Api
|
4
|
+
module Message
|
5
|
+
#
|
6
|
+
# Sends a message to a channel.
|
7
|
+
#
|
8
|
+
# @option options [channel] :channel
|
9
|
+
# Channel to send message to. Can be a public channel, private group or IM channel. Can be an encoded ID, or a name.
|
10
|
+
# @option options [Object] :text
|
11
|
+
# Text of the message to send. See below for an explanation of formatting.
|
12
|
+
def message(options = {})
|
13
|
+
throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil?
|
14
|
+
throw ArgumentError.new('Required arguments :text missing') if options[:text].nil?
|
15
|
+
send_json({ type: 'message', id: next_id }.merge(options))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Slack
|
2
|
+
module RealTime
|
3
|
+
module Api
|
4
|
+
module Ping
|
5
|
+
#
|
6
|
+
# Clients should try to quickly detect disconnections, even in idle periods, so that users can easily tell the
|
7
|
+
# difference between being disconnected and everyone being quiet. Not all web browsers support the WebSocket
|
8
|
+
# ping spec, so the RTM protocol also supports ping/pong messages.
|
9
|
+
#
|
10
|
+
def ping(options = {})
|
11
|
+
send_json({ type: 'ping', id: next_id }.merge(options))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Slack
|
2
|
+
module RealTime
|
3
|
+
module Api
|
4
|
+
module Typing
|
5
|
+
#
|
6
|
+
# Send a typing indicator to indicate that the user is currently writing a message.
|
7
|
+
#
|
8
|
+
# @option options [channel] :channel
|
9
|
+
# Channel to send message to. Can be a public channel, private group or IM channel. Can be an encoded ID, or a name.
|
10
|
+
def typing(options = {})
|
11
|
+
throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil?
|
12
|
+
send_json({ type: 'typing', id: next_id }.merge(options))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Slack
|
2
|
+
module RealTime
|
3
|
+
class Client
|
4
|
+
class ClientNotStartedError < StandardError; end
|
5
|
+
class ClientAlreadyStartedError < StandardError; end
|
6
|
+
|
7
|
+
include Api::MessageId
|
8
|
+
include Api::Ping
|
9
|
+
include Api::Message
|
10
|
+
include Api::Typing
|
11
|
+
|
12
|
+
attr_accessor :web_client
|
13
|
+
attr_accessor(*Config::ATTRIBUTES)
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@callbacks = Hash.new { |h, k| h[k] = [] }
|
17
|
+
Slack::RealTime::Config::ATTRIBUTES.each do |key|
|
18
|
+
send("#{key}=", options[key] || Slack::RealTime.config.send(key))
|
19
|
+
end
|
20
|
+
@token ||= Slack.config.token
|
21
|
+
@web_client = Slack::Web::Client.new(token: token)
|
22
|
+
end
|
23
|
+
|
24
|
+
[:url, :team, :self, :users, :channels, :groups, :ims, :bots].each do |attr|
|
25
|
+
define_method attr do
|
26
|
+
@options[attr.to_s] if @options
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def on(type, &block)
|
31
|
+
type = type.to_s
|
32
|
+
callbacks[type] << block
|
33
|
+
end
|
34
|
+
|
35
|
+
# Start RealTime client and block until it disconnects.
|
36
|
+
# @yieldparam [Websocket::Driver] driver
|
37
|
+
def start!(&block)
|
38
|
+
socket = build_socket
|
39
|
+
socket.start_sync { run_loop(socket, &block) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Start RealTime client and return immediately.
|
43
|
+
# The RealTime::Client will run in the background.
|
44
|
+
# @yieldparam [Websocket::Driver] driver
|
45
|
+
def start_async(&block)
|
46
|
+
socket = build_socket
|
47
|
+
socket.start_async { run_loop(socket, &block) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def stop!
|
51
|
+
fail ClientNotStartedError unless started?
|
52
|
+
@socket.disconnect! if @socket
|
53
|
+
end
|
54
|
+
|
55
|
+
def started?
|
56
|
+
@socket && @socket.connected?
|
57
|
+
end
|
58
|
+
|
59
|
+
class << self
|
60
|
+
def configure
|
61
|
+
block_given? ? yield(config) : config
|
62
|
+
end
|
63
|
+
|
64
|
+
def config
|
65
|
+
Config
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
# @return [Slack::RealTime::Socket]
|
72
|
+
def build_socket
|
73
|
+
fail ClientAlreadyStartedError if started?
|
74
|
+
@options = web_client.rtm_start
|
75
|
+
|
76
|
+
socket_class.new(@options.fetch('url'), socket_options)
|
77
|
+
end
|
78
|
+
|
79
|
+
def socket_options
|
80
|
+
socket_options = {}
|
81
|
+
socket_options[:ping] = websocket_ping if websocket_ping
|
82
|
+
socket_options[:proxy] = websocket_proxy if websocket_proxy
|
83
|
+
socket_options
|
84
|
+
end
|
85
|
+
|
86
|
+
def run_loop(socket)
|
87
|
+
@socket = socket
|
88
|
+
|
89
|
+
@socket.connect! do |driver|
|
90
|
+
yield driver if block_given?
|
91
|
+
|
92
|
+
driver.on :open do |event|
|
93
|
+
open(event)
|
94
|
+
callback(event, :open)
|
95
|
+
end
|
96
|
+
|
97
|
+
driver.on :message do |event|
|
98
|
+
dispatch(event)
|
99
|
+
end
|
100
|
+
|
101
|
+
driver.on :close do |event|
|
102
|
+
callback(event, :close)
|
103
|
+
close(event)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
attr_reader :callbacks
|
109
|
+
def socket_class
|
110
|
+
concurrency::Socket
|
111
|
+
end
|
112
|
+
|
113
|
+
def send_json(data)
|
114
|
+
fail ClientNotStartedError unless started?
|
115
|
+
@socket.send_data(data.to_json)
|
116
|
+
end
|
117
|
+
|
118
|
+
def open(_event)
|
119
|
+
end
|
120
|
+
|
121
|
+
def close(_event)
|
122
|
+
socket = @socket
|
123
|
+
@socket = nil
|
124
|
+
|
125
|
+
[socket, socket_class].each do |s|
|
126
|
+
s.close if s.respond_to?(:close)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def callback(event, type)
|
131
|
+
callbacks = self.callbacks[type.to_s]
|
132
|
+
return false unless callbacks
|
133
|
+
callbacks.each do |c|
|
134
|
+
c.call(event)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def dispatch(event)
|
139
|
+
return false unless event.data
|
140
|
+
data = JSON.parse(event.data)
|
141
|
+
type = data['type']
|
142
|
+
return false unless type
|
143
|
+
callbacks = self.callbacks[type.to_s]
|
144
|
+
return false unless callbacks
|
145
|
+
callbacks.each do |c|
|
146
|
+
c.call(data)
|
147
|
+
end
|
148
|
+
true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'websocket/driver'
|
2
|
+
require 'socket'
|
3
|
+
require 'forwardable'
|
4
|
+
require 'celluloid/current'
|
5
|
+
require 'celluloid/io'
|
6
|
+
|
7
|
+
module Slack
|
8
|
+
module RealTime
|
9
|
+
module Concurrency
|
10
|
+
module Celluloid
|
11
|
+
class Socket < Slack::RealTime::Socket
|
12
|
+
include ::Celluloid::IO
|
13
|
+
include ::Celluloid::Internals::Logger
|
14
|
+
|
15
|
+
BLOCK_SIZE = 4096
|
16
|
+
|
17
|
+
extend ::Forwardable
|
18
|
+
def_delegator :socket, :write
|
19
|
+
def_delegators :driver, :text, :binary, :close
|
20
|
+
|
21
|
+
attr_reader :socket
|
22
|
+
|
23
|
+
def initialize(*args)
|
24
|
+
super
|
25
|
+
@driver = build_driver
|
26
|
+
end
|
27
|
+
|
28
|
+
# @yieldparam [WebSocket::Driver] driver
|
29
|
+
def connect!
|
30
|
+
super
|
31
|
+
|
32
|
+
driver.start
|
33
|
+
future.run_loop
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_loop
|
37
|
+
loop { read } if socket
|
38
|
+
rescue EOFError
|
39
|
+
# connection closed
|
40
|
+
end
|
41
|
+
|
42
|
+
def read
|
43
|
+
buffer = socket.readpartial(BLOCK_SIZE)
|
44
|
+
driver.parse buffer
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_async
|
48
|
+
future = yield self if block_given?
|
49
|
+
|
50
|
+
Actor.new(future)
|
51
|
+
end
|
52
|
+
|
53
|
+
def connected?
|
54
|
+
!@connected.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
class Actor
|
60
|
+
attr_reader :future
|
61
|
+
|
62
|
+
def initialize(future)
|
63
|
+
@future = future
|
64
|
+
end
|
65
|
+
|
66
|
+
def join
|
67
|
+
@future.value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_socket
|
72
|
+
socket = TCPSocket.new(addr, port)
|
73
|
+
socket = SSLSocket.new(socket, build_ssl_context) if secure?
|
74
|
+
socket
|
75
|
+
end
|
76
|
+
|
77
|
+
def build_ssl_context
|
78
|
+
OpenSSL::SSL::SSLContext.new(:TLSv1_2_client)
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_driver
|
82
|
+
::WebSocket::Driver.client(self)
|
83
|
+
end
|
84
|
+
|
85
|
+
def connect
|
86
|
+
@socket = build_socket
|
87
|
+
@connected = @socket.connect
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'faye/websocket'
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
module Slack
|
5
|
+
module RealTime
|
6
|
+
module Concurrency
|
7
|
+
module Eventmachine
|
8
|
+
class Socket < Slack::RealTime::Socket
|
9
|
+
def start_async
|
10
|
+
thread = ensure_reactor_running
|
11
|
+
|
12
|
+
yield self if block_given?
|
13
|
+
|
14
|
+
thread
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_data(message)
|
18
|
+
driver.send(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# @return [Thread]
|
24
|
+
def ensure_reactor_running
|
25
|
+
return if EventMachine.reactor_running?
|
26
|
+
|
27
|
+
reactor = Thread.new { EventMachine.run }
|
28
|
+
Thread.pass until EventMachine.reactor_running?
|
29
|
+
reactor
|
30
|
+
end
|
31
|
+
|
32
|
+
def connect
|
33
|
+
@driver = ::Faye::WebSocket::Client.new(url, nil, options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Slack
|
2
|
+
module RealTime
|
3
|
+
module Config
|
4
|
+
class NoConcurrencyError < StandardError; end
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
ATTRIBUTES = [
|
9
|
+
:token,
|
10
|
+
:websocket_ping,
|
11
|
+
:websocket_proxy,
|
12
|
+
:concurrency
|
13
|
+
]
|
14
|
+
|
15
|
+
attr_accessor(*Config::ATTRIBUTES)
|
16
|
+
|
17
|
+
def reset
|
18
|
+
self.websocket_ping = 30
|
19
|
+
self.websocket_proxy = nil
|
20
|
+
self.token = nil
|
21
|
+
self.concurrency = method(:detect_concurrency)
|
22
|
+
end
|
23
|
+
|
24
|
+
def concurrency
|
25
|
+
(val = @concurrency).respond_to?(:call) ? val.call : val
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def detect_concurrency
|
31
|
+
[:Eventmachine, :Celluloid].each do |concurrency|
|
32
|
+
begin
|
33
|
+
return Slack::RealTime::Concurrency.const_get(concurrency)
|
34
|
+
rescue LoadError, NameError
|
35
|
+
false # could not be loaded, missing dependencies
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
fail NoConcurrencyError, 'Missing concurrency. Add faye-websocket or celluloid-io to your Gemfile.'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def configure
|
45
|
+
block_given? ? yield(Config) : Config
|
46
|
+
end
|
47
|
+
|
48
|
+
def config
|
49
|
+
Config
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Slack::RealTime::Config.reset
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Slack
|
2
|
+
module RealTime
|
3
|
+
class Socket
|
4
|
+
attr_accessor :url
|
5
|
+
attr_accessor :options
|
6
|
+
attr_reader :driver
|
7
|
+
|
8
|
+
def initialize(url, options = {})
|
9
|
+
@url = url
|
10
|
+
@options = options
|
11
|
+
@driver = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_data(message)
|
15
|
+
case message
|
16
|
+
when Numeric then driver.text(message.to_s)
|
17
|
+
when String then driver.text(message)
|
18
|
+
when Array then driver.binary(message)
|
19
|
+
else false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect!
|
24
|
+
return if connected?
|
25
|
+
|
26
|
+
connect
|
27
|
+
|
28
|
+
yield driver if block_given?
|
29
|
+
end
|
30
|
+
|
31
|
+
def disconnect!
|
32
|
+
driver.close
|
33
|
+
end
|
34
|
+
|
35
|
+
def connected?
|
36
|
+
!driver.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_sync(&block)
|
40
|
+
thread = start_async(&block)
|
41
|
+
thread.join if thread
|
42
|
+
rescue Interrupt
|
43
|
+
thread.exit if thread
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [#join]
|
47
|
+
def start_async
|
48
|
+
fail NotImplementedError, "Expected #{self.class} to implement #{__method__}."
|
49
|
+
end
|
50
|
+
|
51
|
+
def close(_event)
|
52
|
+
@driver = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def addr
|
58
|
+
URI(url).host
|
59
|
+
end
|
60
|
+
|
61
|
+
def secure?
|
62
|
+
port == URI::HTTPS::DEFAULT_PORT
|
63
|
+
end
|
64
|
+
|
65
|
+
def port
|
66
|
+
case (uri = URI(url)).scheme
|
67
|
+
when 'wss'.freeze, 'https'.freeze
|
68
|
+
URI::HTTPS::DEFAULT_PORT
|
69
|
+
when 'ws', 'http'.freeze
|
70
|
+
URI::HTTP::DEFAULT_PORT
|
71
|
+
else
|
72
|
+
uri.port
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def connect
|
77
|
+
fail NotImplementedError, "Expected #{self.class} to implement #{__method__}."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|