Class: Protocol::WebSocket::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/websocket/connection.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(framer, mask: nil) ⇒ Connection

Returns a new instance of Connection.

Options Hash (mask:):

  • 4-byte (String)

    mask to be used for frames generated by this connection.



27
28
29
30
31
32
33
# File 'lib/protocol/websocket/connection.rb', line 27

def initialize(framer, mask: nil)
  @framer = framer
  @mask = mask
  
  @state = :open
  @frames = []
end

Instance Attribute Details

#framerObject (readonly)

The framer which is used for reading and writing frames.



36
37
38
# File 'lib/protocol/websocket/connection.rb', line 36

def framer
  @framer
end

#framesObject

Buffered frames which form part of a complete message.



42
43
44
# File 'lib/protocol/websocket/connection.rb', line 42

def frames
  @frames
end

#maskObject (readonly)

The (optional) mask which is used when generating frames.



39
40
41
# File 'lib/protocol/websocket/connection.rb', line 39

def mask
  @mask
end

Instance Method Details

#closeObject



52
53
54
55
56
# File 'lib/protocol/websocket/connection.rb', line 52

def close
  send_close unless closed?
  
  @framer.close
end

#closed?Boolean



48
49
50
# File 'lib/protocol/websocket/connection.rb', line 48

def closed?
  @state == :closed
end

#flushObject



44
45
46
# File 'lib/protocol/websocket/connection.rb', line 44

def flush
  @framer.flush
end

#next_messageObject

Deprecated.



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/protocol/websocket/connection.rb', line 193

def next_message
  @framer.flush
  
  while read_frame
    if @frames.last&.finished?
      frames = @frames
      @frames = []
      
      return frames
    end
  end
end

#open!Object



151
152
153
154
155
# File 'lib/protocol/websocket/connection.rb', line 151

def open!
  @state = :open
  
  return self
end

#readString



179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/protocol/websocket/connection.rb', line 179

def read
  @framer.flush
  
  while read_frame
    if @frames.last&.finished?
      buffer = @frames.map(&:unpack).join
      @frames = []
      
      return buffer
    end
  end
end

#read_frameObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/protocol/websocket/connection.rb', line 58

def read_frame
  return nil if closed?
  
  frame = @framer.read_frame
  
  yield frame if block_given?
  
  frame.apply(self)
  
  return frame
rescue ProtocolError => error
  send_close(error.code, error.message)
  
  raise
rescue
  send_close(Error::PROTOCOL_ERROR, $!.message)
  
  raise
end

#receive_binary(frame) ⇒ Object



90
91
92
93
94
95
96
# File 'lib/protocol/websocket/connection.rb', line 90

def receive_binary(frame)
  if @frames.empty?
    @frames << frame
  else
    raise ProtocolError, "Received binary, but expecting continuation!"
  end
end

#receive_close(frame) ⇒ Object



130
131
132
133
134
135
136
137
138
# File 'lib/protocol/websocket/connection.rb', line 130

def receive_close(frame)
  @state = :closed
  
  code, message = frame.unpack
  
  if code and code != Error::NO_ERROR
    raise ClosedError.new message, code
  end
end

#receive_continuation(frame) ⇒ Object



98
99
100
101
102
103
104
# File 'lib/protocol/websocket/connection.rb', line 98

def receive_continuation(frame)
  if @frames.any?
    @frames << frame
  else
    raise ProtocolError, "Received unexpected continuation!"
  end
end

#receive_frame(frame) ⇒ Object



165
166
167
# File 'lib/protocol/websocket/connection.rb', line 165

def receive_frame(frame)
  warn "Unhandled frame #{frame.inspect}"
end

#receive_ping(frame) ⇒ Object



157
158
159
160
161
162
163
# File 'lib/protocol/websocket/connection.rb', line 157

def receive_ping(frame)
  if @state != :closed
    write_frame(frame.reply)
  else
    raise ProtocolError, "Cannot receive ping in state #{@state}"
  end
end

#receive_text(frame) ⇒ Object



82
83
84
85
86
87
88
# File 'lib/protocol/websocket/connection.rb', line 82

def receive_text(frame)
  if @frames.empty?
    @frames << frame
  else
    raise ProtocolError, "Received text, but expecting continuation!"
  end
end

#send_binary(buffer) ⇒ Object



113
114
115
116
117
118
# File 'lib/protocol/websocket/connection.rb', line 113

def send_binary(buffer)
  frame = BinaryFrame.new(mask: @mask)
  frame.pack buffer
  
  write_frame(frame)
end

#send_close(code = Error::NO_ERROR, message = nil) ⇒ Object



120
121
122
123
124
125
126
127
128
# File 'lib/protocol/websocket/connection.rb', line 120

def send_close(code = Error::NO_ERROR, message = nil)
  frame = CloseFrame.new(mask: @mask)
  frame.pack(code, message)
  
  self.write_frame(frame)
  self.flush
  
  @state = :closed
end

#send_ping(data) ⇒ Object



140
141
142
143
144
145
146
147
148
149
# File 'lib/protocol/websocket/connection.rb', line 140

def send_ping(data)
  if @state != :closed
    frame = PingFrame.new(mask: @mask)
    frame.pack(data)
    
    write_frame(frame)
  else
    raise ProtocolError, "Cannot send ping in state #{@state}"
  end
end

#send_text(buffer) ⇒ Object



106
107
108
109
110
111
# File 'lib/protocol/websocket/connection.rb', line 106

def send_text(buffer)
  frame = TextFrame.new(mask: @mask)
  frame.pack buffer
  
  write_frame(frame)
end

#write(buffer) ⇒ Object



170
171
172
173
174
175
176
# File 'lib/protocol/websocket/connection.rb', line 170

def write(buffer)
  if buffer.encoding == Encoding::UTF_8
    send_text(buffer)
  else
    send_data(buffer)
  end
end

#write_frame(frame) ⇒ Object



78
79
80
# File 'lib/protocol/websocket/connection.rb', line 78

def write_frame(frame)
  @framer.write_frame(frame)
end