Class: Websocker::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/websocker/client.rb

Defined Under Namespace

Classes: HandshakeNegotiationError, SocketReadError

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Client

Returns a new instance of Client.



16
17
18
19
20
21
22
23
24
# File 'lib/websocker/client.rb', line 16

def initialize(opts = {})
  @host = opts[:host]
  @port = opts[:port] || 80
  @origin = opts[:origin] || "localhost"
  @path = opts[:path] || "/"
  @connected = false
  @logger = opts[:logger] || Logger.new(STDOUT)
  @logger.debug "Connecting to #{@host}:#{@port}#{@path}"
end

Instance Method Details

#closeObject



92
93
94
95
96
# File 'lib/websocker/client.rb', line 92

def close
  @logger.debug "Connection closed"
  @connected = false
  @on_closed.call unless @on_closed.nil?
end

#connectObject



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/websocker/client.rb', line 26

def connect
  @sock = TCPSocket.open(@host, @port)
  @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
  @connected = true
  key = generateKey
  write handshake(key)
  headers = read_headers
  received_key = headers['Sec-WebSocket-Accept']
  expected_key = expected_security_key_answer(key)
  raise HandshakeNegotiationError, 'Key Mismatch' unless received_key == expected_key
  @sock
end

#listenObject



39
40
41
42
43
44
45
# File 'lib/websocker/client.rb', line 39

def listen
  @loop = Thread.new do
    while @connected
      read_once
    end
  end
end

#on_closed(&blk) ⇒ Object



58
59
60
# File 'lib/websocker/client.rb', line 58

def on_closed(&blk)
  @on_closed = blk
end

#on_message(&blk) ⇒ Object



54
55
56
# File 'lib/websocker/client.rb', line 54

def on_message(&blk)
  @on_message = blk
end

#read_onceObject



47
48
49
50
51
52
# File 'lib/websocker/client.rb', line 47

def read_once
  message = read
  return unless @connected
  @logger.debug "received: #{message}"
  @on_message.call(message) unless @on_message.nil?
end

#send(data) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/websocker/client.rb', line 62

def send(data)
  byte1 = 0x80 | 1
  write_byte(byte1)

  # write length
  byte2 = 0x80 # mask flag set to true
  length = data.size
  if length <= 125
    byte2 = byte2 | length
    write_byte(byte2)
  elsif length <= 65535
    byte2 = byte2 | 126
    write_byte(byte2)
    # write length in next two bytes
    write [length].pack('n') # 16-bit unsigned
  else
    byte2 = byte2 | 127
    write_byte(byte2)
    # write length in next eight bytes
    write [length].pack('Q') # 64-bit unsigned
  end
  # masking is required from the client to the server
  masking_key = Array.new(4){ rand(256) }
  write(masking_key.pack("C*"))
  masked_data = apply_mask(data, masking_key)
  # write masked message payload
  write(masked_data)
  @logger.debug "wrote: #{data}"
end