Class: SlackSocketModeBot::SimpleWebSocket
- Inherits:
-
Object
- Object
- SlackSocketModeBot::SimpleWebSocket
- Defined in:
- lib/slack_socket_mode_bot/simple_web_socket.rb
Constant Summary collapse
- CLOSE_TIMEOUT =
Seconds to wait for the server's TCP close before dropping the socket ourselves.
10
Instance Method Summary collapse
- #close(code: 1000, reason: "") ⇒ Object
- #closing? ⇒ Boolean
-
#initialize(url) ⇒ SimpleWebSocket
constructor
A new instance of SimpleWebSocket.
- #send(data, type: :text, code: nil) ⇒ Object
- #step(read_ios, write_ios) ⇒ Object
Constructor Details
#initialize(url) ⇒ SimpleWebSocket
Returns a new instance of SimpleWebSocket.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/slack_socket_mode_bot/simple_web_socket.rb', line 5 def initialize(url) uri = URI.parse(url) unless uri.scheme == "https" || uri.scheme == "wss" raise "unexpected scheme (not secure?): #{ uri.scheme }" end ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = "SSLv23" ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.cert_store = OpenSSL::X509::Store.new ctx.cert_store.set_default_paths count = 0 begin io = TCPSocket.new(uri.host, uri.port || 443) @io = OpenSSL::SSL::SSLSocket.new(io, ctx) @io.connect rescue Socket::ResolutionError sleep 1 count += 1 retry if count < 3 raise end @version = nil @close_deadline = nil # nil while open; a Time once closing @fib = Fiber.new do begin handshake = WebSocket::Handshake::Client.new(url: url) @write_buff = handshake.to_s.dup handshake << Fiber.yield until handshake.finished? @version = handshake.version yield :open frame = WebSocket::Frame::Incoming::Client.new frame << handshake.leftovers while true while msg = frame.next case msg.type when :close was_closing = closing? close yield :close unless was_closing when :ping send(msg.data, type: :pong) when :pong when :text yield :message, msg.data, :text when :binary yield :message, msg.data, :binary end end frame << Fiber.yield end rescue EOFError ensure yield :close unless closing? end end @fib.resume end |
Instance Method Details
#close(code: 1000, reason: "") ⇒ Object
79 80 81 82 83 |
# File 'lib/slack_socket_mode_bot/simple_web_socket.rb', line 79 def close(code: 1000, reason: "") return if closing? || @io.closed? send(reason, type: :close, code: code) @close_deadline = Time.now + CLOSE_TIMEOUT end |
#closing? ⇒ Boolean
71 |
# File 'lib/slack_socket_mode_bot/simple_web_socket.rb', line 71 def closing? = !@close_deadline.nil? |
#send(data, type: :text, code: nil) ⇒ Object
73 74 75 76 77 |
# File 'lib/slack_socket_mode_bot/simple_web_socket.rb', line 73 def send(data, type: :text, code: nil) raise "not opened yet" unless @version frame = WebSocket::Frame::Outgoing::Client.new(version: @version, data: data, type: type, code: code) @write_buff << frame.to_s end |
#step(read_ios, write_ios) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/slack_socket_mode_bot/simple_web_socket.rb', line 85 def step(read_ios, write_ios) if @close_deadline && Time.now >= @close_deadline @io.close unless @io.closed? return false end wait_readable = wait_writable = false while true read_buff = @io.read_nonblock(4096, exception: false) case read_buff when :wait_readable then wait_readable = true; break when :wait_writable then wait_writable = true; break when nil raise Errno::EPIPE else @fib.resume(read_buff) end end unless @write_buff.empty? len = @io.write_nonblock(@write_buff, exception: false) case len when :wait_readable then wait_readable = true when :wait_writable then wait_writable = true else @write_buff.clear end end read_ios << @io if wait_readable write_ios << @io if wait_writable return true rescue Errno::EPIPE, Errno::ECONNRESET begin @fib.raise(EOFError) rescue FiberError end @io.close unless @io.closed? false end |