Class: Satori::RTM::WebSocket

Inherits:
Object
  • Object
show all
Includes:
Logger
Defined in:
lib/satori-rtm-sdk/websocket.rb

Overview

WebSocket implementation on top of standard TCP sockets.

Constant Summary

Constants included from Logger

Logger::ENV_FLAG

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logger

create_logger, default_level, included, logger, use_logger, use_std_logger

Constructor Details

#initialize(opts = {}) ⇒ WebSocket

Returns a new instance of WebSocket


19
20
21
22
# File 'lib/satori-rtm-sdk/websocket.rb', line 19

def initialize(opts = {})
  @opts = opts
  @state = :none
end

Instance Attribute Details

#socketObject (readonly)

Returns the value of attribute socket


17
18
19
# File 'lib/satori-rtm-sdk/websocket.rb', line 17

def socket
  @socket
end

Instance Method Details

#close(code = 1000, reason = nil) ⇒ Object


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/satori-rtm-sdk/websocket.rb', line 93

def close(code = 1000, reason = nil)
  if @state == :open
    send_frame_unsafe(reason, :close, code)
  elsif @state == :server_close_frame_received
    # server send close frame, replying back with default code
    send_frame_unsafe(reason, :close)
  end
rescue => ex
  # ignore
  logger.info("fail to close socket: #{ex.message}")
ensure
  should_trigger_on_close = opened?
  @state = :closed
  @socket.close if @socket
  fire :close, code, reason if should_trigger_on_close
end

#connect(url) ⇒ Object


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/satori-rtm-sdk/websocket.rb', line 24

def connect(url)
  uri = URI.parse(url)

  @socket = create_socket(uri)
  @socket = start_tls(@socket, uri.host) if uri.scheme == 'wss'

  @hs = ::WebSocket::Handshake::Client.new(url: url)
  @frame = incoming_frame.new(version: @hs.version)

  @state = :open
  do_ws_handshake
  fire :open
rescue => ex
  close 1006, ex.message
  raise ConnectionError, ex.message, ex.backtrace
end

#readObject


59
60
61
62
63
64
65
66
67
# File 'lib/satori-rtm-sdk/websocket.rb', line 59

def read
  while (rc = read_nonblock) == :would_block
    IO.select([@socket])
  end
  rc
rescue => ex
  close 1006, 'Socket is closed'
  raise ConnectionError, ex.message, ex.backtrace
end

#read_nonblockObject


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/satori-rtm-sdk/websocket.rb', line 41

def read_nonblock
  data = nil
  begin
    data = @socket.read_nonblock(1024)
  rescue IO::WaitReadable, IO::WaitWritable
    return :would_block
  end

  @frame << data
  while (frame = @frame.next)
    handle_incoming_frame(frame)
  end
  :ok
rescue => ex
  close 1006, 'Socket is closed'
  raise ConnectionError, ex.message, ex.backtrace
end

#read_with_timeout(timeout_in_secs) ⇒ Object


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/satori-rtm-sdk/websocket.rb', line 69

def read_with_timeout(timeout_in_secs)
  now = Time.now
  while (rc = read_nonblock) == :would_block
    diff = Time.now - now
    if timeout_in_secs <= diff
      rc = :timeout
      break
    end
    IO.select([@socket], nil, nil, timeout_in_secs - diff)
  end
  rc
rescue => ex
  close 1006, 'Socket is closed'
  raise ConnectionError, ex.message, ex.backtrace
end

#send(data, args) ⇒ Object


85
86
87
88
89
90
91
# File 'lib/satori-rtm-sdk/websocket.rb', line 85

def send(data, args)
  type = args[:type] || :text
  send_frame_unsafe(data, type, args[:code])
rescue => ex
  close 1006, 'Socket is closed'
  raise ConnectionError, ex.message, ex.backtrace
end