protocol-websocket 0.13.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c93940911ada80aa95de9bf5a1412dd20248a77855f4b9bd523a06b699294795
4
- data.tar.gz: f7fd77275a0d1269e3586e56b08f18f2e10f18c816085e8bea7de95da4d282b0
3
+ metadata.gz: ec6ec828408c7579273d456c0a9ce582a794757b5c532e228c45eca4779acee1
4
+ data.tar.gz: 5abe7c8dcb8e1e5cd64e62e06cb0f7585ec0fa8646baf4cecaa6945542cf8b33
5
5
  SHA512:
6
- metadata.gz: 2d54e303617a6ff069bf7ee5e8cb5539c3217bfa0613e2290203edca66695ad926ff40959c2edf694a82b05485a403ec96bedccf76587ae47e3107ff8ccd49ec
7
- data.tar.gz: 8d07512b928d9060af02945caf8cc1680154f220c4f741ee23fc9520f5d8e3f1ae99470aa28d390b9c9611de667eed0e6c58ffb59b705d356b117a51fc3908ee
6
+ metadata.gz: e5daf9a48e29e811b255516dd777fafbbdf084c8ed681d81ebe2fc67eead205702186b42231abfa032060afc62d439a2e6c8c90d1696eec58be37c40cf52d2a9
7
+ data.tar.gz: 6dc89a62a3179b9e2d397cac57204a5d73897ada519abba42d3f85ec184c6f74c1c2f26d81b2ef5277c0fa4b17c35cf283019f99e9a01537d32fece66c76db2b
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2021, by Aurora Nockert.
6
6
 
7
7
  require_relative 'frame'
@@ -9,17 +9,22 @@ require_relative 'message'
9
9
 
10
10
  module Protocol
11
11
  module WebSocket
12
+ # Represents a binary frame that is sent or received by a WebSocket connection.
12
13
  class BinaryFrame < Frame
13
14
  OPCODE = 0x2
14
15
 
16
+ # @returns [Boolean] if the frame contains data.
15
17
  def data?
16
18
  true
17
19
  end
18
20
 
21
+ # Decode the binary buffer into a suitable binary message.
22
+ # @parameter buffer [String] The binary data to unpack.
19
23
  def read_message(buffer)
20
24
  return BinaryMessage.new(buffer)
21
25
  end
22
26
 
27
+ # Apply this frame to the specified connection.
23
28
  def apply(connection)
24
29
  connection.receive_binary(self)
25
30
  end
@@ -1,17 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2021, by Aurora Nockert.
6
6
 
7
7
  require_relative 'frame'
8
8
 
9
9
  module Protocol
10
10
  module WebSocket
11
+ # Represents a close frame that is sent or received by a WebSocket connection.
11
12
  class CloseFrame < Frame
12
13
  OPCODE = 0x8
13
14
  FORMAT = "na*"
14
15
 
16
+ # Unpack the frame data into a close code and reason.
17
+ # @returns [Tuple(Integer, String)] The close code and reason.
15
18
  def unpack
16
19
  data = super
17
20
 
@@ -40,7 +43,10 @@ module Protocol
40
43
  end
41
44
  end
42
45
 
46
+ # Pack a close code and reason into the frame data.
43
47
  # If code is missing, reason is ignored.
48
+ # @parameter code [Integer | Nil] The close code.
49
+ # @parameter reason [String | Nil] The close reason.
44
50
  def pack(code = nil, reason = nil)
45
51
  if code
46
52
  if reason and reason.encoding != Encoding::UTF_8
@@ -53,6 +59,7 @@ module Protocol
53
59
  end
54
60
  end
55
61
 
62
+ # Apply this frame to the specified connection.
56
63
  def apply(connection)
57
64
  connection.receive_close(self)
58
65
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require 'json'
7
+
8
+ module Protocol
9
+ module WebSocket
10
+ module Coder
11
+ # A JSON coder that uses the standard JSON library.
12
+ class JSON
13
+ def initialize(**options)
14
+ @options = options
15
+ end
16
+
17
+ # Parse a JSON buffer into an object.
18
+ def parse(buffer)
19
+ ::JSON.parse(buffer, **@options)
20
+ end
21
+
22
+ # Generate a JSON buffer from an object.
23
+ def generate(object)
24
+ ::JSON.generate(object, **@options)
25
+ end
26
+
27
+ # The default JSON coder. This coder will symbolize names.
28
+ DEFAULT = new(symbolize_names: true)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require_relative 'coder/json'
7
+
8
+ module Protocol
9
+ module WebSocket
10
+ module Coder
11
+ # The default coder for WebSocket messages.
12
+ DEFAULT = JSON::DEFAULT
13
+ end
14
+ end
15
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2019, by William T. Nelson.
6
6
  # Copyright, 2021, by Aurora Nockert.
7
7
 
@@ -26,21 +26,26 @@ module Protocol
26
26
  @writer = self
27
27
  end
28
28
 
29
- # The framer which is used for reading and writing frames.
29
+ # @attribute [Framer] The framer which is used for reading and writing frames.
30
30
  attr :framer
31
31
 
32
- # The (optional) mask which is used when generating frames.
32
+ # @attribte [String | Nil] The optional mask which is used when generating frames.
33
33
  attr :mask
34
34
 
35
- # The allowed reserved bits:
35
+ # @attribute [Integer] The allowed reserved bits.
36
36
  attr :reserved
37
37
 
38
- # Buffered frames which form part of a complete message.
38
+ # @attribute [Array(Frame)] Buffered frames which form part of a complete message.
39
39
  attr_accessor :frames
40
40
 
41
+ # @attribute [Object] The reader which is used to unpack frames into messages.
41
42
  attr_accessor :reader
43
+
44
+ # @attribute [Object] The writer which is used to pack messages into frames.
42
45
  attr_accessor :writer
43
46
 
47
+ # Reserve a bit in the reserved flags for an extension.
48
+ # @parameter bit [Integer] The bit to reserve, see {Frame::RESERVED} for more details.
44
49
  def reserve!(bit)
45
50
  if (@reserved & bit).zero?
46
51
  raise ArgumentError, "Unable to use #{bit}!"
@@ -51,10 +56,12 @@ module Protocol
51
56
  return true
52
57
  end
53
58
 
59
+ # Flush the underlying framer to ensure all buffered data is written to the connection.
54
60
  def flush
55
61
  @framer.flush
56
62
  end
57
63
 
64
+ # Transition the connection to the open state (the default for new connections).
58
65
  def open!
59
66
  @state = :open
60
67
 
@@ -62,6 +69,7 @@ module Protocol
62
69
  end
63
70
 
64
71
  # If not already closed, transition the connection to the closed state and send a close frame.
72
+ # Will try to send a close frame with the specified code and reason, but will ignore any errors that occur while sending.
65
73
  def close!(...)
66
74
  unless @state == :closed
67
75
  @state = :closed
@@ -76,17 +84,19 @@ module Protocol
76
84
  return self
77
85
  end
78
86
 
87
+ # @returns [Boolean] if the connection is in the closed state.
79
88
  def closed?
80
89
  @state == :closed
81
90
  end
82
91
 
83
- # Immediately transition the connection to the closed state and close the underlying connection.
92
+ # Immediately transition the connection to the closed state *and* close the underlying connection.
84
93
  def close(...)
85
94
  close!(...)
86
95
 
87
96
  @framer.close
88
97
  end
89
98
 
99
+ # Read a frame from the framer, and apply it to the connection.
90
100
  def read_frame
91
101
  return nil if closed?
92
102
 
@@ -109,12 +119,15 @@ module Protocol
109
119
  raise
110
120
  end
111
121
 
122
+ # Write a frame to the framer.
123
+ # Note: This does not immediately write the frame to the connection, you must call {#flush} to ensure the frame is written.
112
124
  def write_frame(frame)
113
125
  @framer.write_frame(frame)
114
126
 
115
127
  return frame
116
128
  end
117
129
 
130
+ # Receive a text frame from the connection.
118
131
  def receive_text(frame)
119
132
  if @frames.empty?
120
133
  @frames << frame
@@ -123,6 +136,7 @@ module Protocol
123
136
  end
124
137
  end
125
138
 
139
+ # Receive a binary frame for the connection.
126
140
  def receive_binary(frame)
127
141
  if @frames.empty?
128
142
  @frames << frame
@@ -131,6 +145,7 @@ module Protocol
131
145
  end
132
146
  end
133
147
 
148
+ # Receive a continuation frame for the connection.
134
149
  def receive_continuation(frame)
135
150
  if @frames.any?
136
151
  @frames << frame
@@ -138,7 +153,8 @@ module Protocol
138
153
  raise ProtocolError, "Received unexpected continuation!"
139
154
  end
140
155
  end
141
-
156
+
157
+ # Receive a close frame from the connection.
142
158
  def receive_close(frame)
143
159
  code, reason = frame.unpack
144
160
 
@@ -150,6 +166,8 @@ module Protocol
150
166
  end
151
167
  end
152
168
 
169
+ # Send a ping frame with the specified data.
170
+ # @parameter data [String] The data to send in the ping frame.
153
171
  def send_ping(data = "")
154
172
  if @state != :closed
155
173
  frame = PingFrame.new(mask: @mask)
@@ -161,6 +179,7 @@ module Protocol
161
179
  end
162
180
  end
163
181
 
182
+ # Receive a ping frame from the connection.
164
183
  def receive_ping(frame)
165
184
  if @state != :closed
166
185
  write_frame(frame.reply(mask: @mask))
@@ -169,14 +188,19 @@ module Protocol
169
188
  end
170
189
  end
171
190
 
191
+ # Receive a pong frame from the connection. By default, this method does nothing.
172
192
  def receive_pong(frame)
173
193
  # Ignore.
174
194
  end
175
195
 
196
+ # Receive a frame that is not a control frame. By default, this method raises a {ProtocolError}.
176
197
  def receive_frame(frame)
177
198
  raise ProtocolError, "Unhandled frame: #{frame}"
178
199
  end
179
200
 
201
+ # Pack a text frame with the specified buffer. This is used by the {#writer} interface.
202
+ # @parameter buffer [String] The text to pack into the frame.
203
+ # @returns [TextFrame] The packed frame.
180
204
  def pack_text_frame(buffer, **options)
181
205
  frame = TextFrame.new(mask: @mask)
182
206
  frame.pack(buffer)
@@ -184,10 +208,15 @@ module Protocol
184
208
  return frame
185
209
  end
186
210
 
211
+ # Send a text frame with the specified buffer.
212
+ # @parameter buffer [String] The text to send.
187
213
  def send_text(buffer, **options)
188
214
  write_frame(@writer.pack_text_frame(buffer, **options))
189
215
  end
190
216
 
217
+ # Pack a binary frame with the specified buffer. This is used by the {#writer} interface.
218
+ # @parameter buffer [String] The binary data to pack into the frame.
219
+ # @returns [BinaryFrame] The packed frame.
191
220
  def pack_binary_frame(buffer, **options)
192
221
  frame = BinaryFrame.new(mask: @mask)
193
222
  frame.pack(buffer)
@@ -195,11 +224,15 @@ module Protocol
195
224
  return frame
196
225
  end
197
226
 
227
+ # Send a binary frame with the specified buffer.
228
+ # @parameter buffer [String] The binary data to send.
198
229
  def send_binary(buffer, **options)
199
230
  write_frame(@writer.pack_binary_frame(buffer, **options))
200
231
  end
201
232
 
202
233
  # Send a control frame with data containing a specified control sequence to begin the closing handshake. Does not close the connection, until the remote end responds with a close frame.
234
+ # @parameter code [Integer] The close code to send.
235
+ # @parameter reason [String] The reason for closing the connection.
203
236
  def send_close(code = Error::NO_ERROR, reason = "")
204
237
  frame = CloseFrame.new(mask: @mask)
205
238
  frame.pack(code, reason)
@@ -223,12 +256,15 @@ module Protocol
223
256
  message.send(self, **options)
224
257
  end
225
258
 
226
- # The default implementation for reading a message buffer.
259
+ # The default implementation for reading a message buffer. This is used by the {#reader} interface.
227
260
  def unpack_frames(frames)
228
261
  frames.map(&:unpack).join("")
229
262
  end
230
263
 
231
- # Read a message from the connection.
264
+ # Read a message from the connection. If an error occurs while reading the message, the connection will be closed.
265
+ #
266
+ # If the message is fragmented, this method will buffer the frames until a complete message is received.
267
+ #
232
268
  # @returns message [Message] The received message.
233
269
  def read(**options)
234
270
  @framer.flush
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
 
8
8
  module Protocol
9
9
  module WebSocket
10
+ # Represents a continuation frame that is sent or received by a WebSocket connection when a message is split into multiple frames.
10
11
  class ContinuationFrame < Frame
11
12
  OPCODE = 0x0
12
13
 
14
+ # Apply this frame to the specified connection.
13
15
  def apply(connection)
14
16
  connection.receive_continuation(self)
15
17
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require 'protocol/http/error'
7
7
 
8
8
  module Protocol
9
9
  module WebSocket
10
+ # Represents an error that occurred during the WebSocket protocol negotiation or communication.
10
11
  # Status codes as defined by <https://tools.ietf.org/html/rfc6455#section-7.4.1>.
11
12
  class Error < HTTP::Error
12
13
  # Indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.
@@ -24,9 +25,7 @@ module Protocol
24
25
  # There are other status codes but most of them are "implementation specific".
25
26
  end
26
27
 
27
- # Raised by stream or connection handlers, results in GOAWAY frame
28
- # which signals termination of the current connection. You *cannot*
29
- # recover from this exception, or any exceptions subclassed from it.
28
+ # Raised by stream or connection handlers, results in GOAWAY frame which signals termination of the current connection. You *cannot* recover from this exception, or any exceptions subclassed from it.
30
29
  class ProtocolError < Error
31
30
  def initialize(message, code = PROTOCOL_ERROR)
32
31
  super(message)
@@ -34,6 +33,7 @@ module Protocol
34
33
  @code = code
35
34
  end
36
35
 
36
+ # @attribute [Integer] The status code associated with the error.
37
37
  attr :code
38
38
  end
39
39
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
4
+ # Copyright, 2022-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'compression/constants'
7
7
  require_relative 'compression/inflate'
@@ -10,6 +10,7 @@ require_relative 'compression/deflate'
10
10
  module Protocol
11
11
  module WebSocket
12
12
  module Extension
13
+ # Provides support for the permessage-deflate extension.
13
14
  module Compression
14
15
  # Client offer to server, construct a list of requested compression parameters suitable for the `Sec-WebSocket-Extensions` header.
15
16
  # @returns [Array(String)] a list of compression parameters suitable to send to the server.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
4
+ # Copyright, 2022-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'extension/compression'
7
7
  require_relative 'headers'
@@ -65,6 +65,8 @@ module Protocol
65
65
  @accepted << [klass, options]
66
66
  end
67
67
  end
68
+
69
+ return @accepted
68
70
  end
69
71
 
70
72
  def apply(connection)
@@ -112,14 +114,14 @@ module Protocol
112
114
  # The extension is accepted and no further offers will be considered:
113
115
  named.delete(name)
114
116
 
115
- yield header
117
+ yield header if block_given?
116
118
 
117
119
  @accepted << [klass, options]
118
120
  end
119
121
  end
120
122
  end
121
123
 
122
- return headers
124
+ return @accepted
123
125
  end
124
126
 
125
127
  def apply(connection)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2019, by Soumya.
6
6
  # Copyright, 2021, by Aurora Nockert.
7
7
 
@@ -50,6 +50,7 @@ module Protocol
50
50
  @opcode & 0x8 != 0
51
51
  end
52
52
 
53
+ # @returns [Boolean] if the frame contains data.
53
54
  def data?
54
55
  false
55
56
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
 
@@ -34,16 +34,18 @@ module Protocol
34
34
  @frames = frames
35
35
  end
36
36
 
37
+ # Close the underlying stream.
37
38
  def close
38
39
  @stream.close
39
40
  end
40
41
 
42
+ # Flush the underlying stream.
41
43
  def flush
42
44
  @stream.flush
43
45
  end
44
46
 
45
47
  # Read a frame from the underlying stream.
46
- # @returns [Frame]
48
+ # @returns [Frame] the frame read from the stream.
47
49
  def read_frame(maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
48
50
  # Read the header:
49
51
  finished, flags, opcode = read_header
@@ -55,10 +57,12 @@ module Protocol
55
57
  return frame
56
58
  end
57
59
 
60
+ # Write a frame to the underlying stream.
58
61
  def write_frame(frame)
59
62
  frame.write(@stream)
60
63
  end
61
64
 
65
+ # Read the header of the frame.
62
66
  def read_header
63
67
  if buffer = @stream.read(1) and buffer.bytesize == 1
64
68
  return Frame.parse_header(buffer)
@@ -1,32 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
5
-
6
- require 'json'
4
+ # Copyright, 2022-2024, by Samuel Williams.
7
5
 
8
6
  require_relative 'message'
9
7
 
8
+ warn "Protocol::WebSocket::JSONMessage is deprecated. Use Protocol::WebSocket::TextMessage instead."
9
+
10
10
  module Protocol
11
11
  module WebSocket
12
+ # @deprecated Use {TextMessage} instead.
12
13
  class JSONMessage < TextMessage
13
14
  def self.wrap(message)
14
- if message.is_a?(TextMessage)
15
- self.new(message.buffer)
16
- end
15
+ message
17
16
  end
18
17
 
19
18
  def self.generate(object)
20
19
  self.new(JSON.generate(object))
21
20
  end
22
-
23
- def parse(symbolize_names: true, **options)
24
- JSON.parse(@buffer, symbolize_names: symbolize_names, **options)
25
- end
26
-
27
- def to_h
28
- parse.to_h
29
- end
30
21
  end
31
22
  end
32
23
  end
@@ -1,43 +1,71 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2023, by Samuel Williams.
4
+ # Copyright, 2022-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
+ require_relative 'coder'
7
8
 
8
9
  module Protocol
9
10
  module WebSocket
11
+ # Represents a message that can be sent or received over a WebSocket connection.
10
12
  class Message
13
+ # Create a new message from a buffer.
14
+ # @attribute buffer [String] The message buffer.
11
15
  def initialize(buffer)
12
16
  @buffer = buffer
13
17
  end
14
18
 
19
+ # @attribute [String] The message buffer.
15
20
  attr :buffer
16
21
 
22
+ # @returns [Integer] The size of the message buffer.
17
23
  def size
18
24
  @buffer.bytesize
19
25
  end
20
26
 
21
- # This can be helpful for writing tests.
27
+ # Compare this message to another message or buffer.
22
28
  def == other
23
29
  @buffer == other.to_str
24
30
  end
25
31
 
32
+ # A message is implicitly convertible to it's buffer.
26
33
  def to_str
27
34
  @buffer
28
35
  end
29
36
 
37
+ # The encoding of the message buffer.
38
+ # @returns [Encoding]
30
39
  def encoding
31
40
  @buffer.encoding
32
41
  end
42
+
43
+ # Generate a message from a value using the given coder.
44
+ # @property value [Object] The value to encode.
45
+ # @property coder [Coder] The coder to use. Defaults to JSON.
46
+ def self.generate(value, coder = Coder::DEFAULT)
47
+ new(coder.generate(value))
48
+ end
49
+
50
+ # Parse the message buffer using the given coder. Defaults to JSON.
51
+ def parse(coder = Coder::DEFAULT)
52
+ coder.parse(@buffer)
53
+ end
54
+
55
+ # Convert the message buffer to a hash using the given coder. Defaults to JSON.
56
+ def to_h(...)
57
+ parse(...).to_h
58
+ end
33
59
  end
34
60
 
61
+ # Represents a text message that can be sent or received over a WebSocket connection.
35
62
  class TextMessage < Message
36
63
  def send(connection, **options)
37
64
  connection.send_text(@buffer, **options)
38
65
  end
39
66
  end
40
67
 
68
+ # Represents a binary message that can be sent or received over a WebSocket connection.
41
69
  class BinaryMessage < Message
42
70
  def send(connection, **options)
43
71
  connection.send_binary(@buffer, **options)
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
  require_relative 'pong_frame'
8
8
 
9
9
  module Protocol
10
10
  module WebSocket
11
+ # Represents a ping frame that is sent or received by a WebSocket connection.
11
12
  class PingFrame < Frame
12
13
  OPCODE = 0x9
13
14
 
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'frame'
7
7
 
8
8
  module Protocol
9
9
  module WebSocket
10
+ # Represents a pong frame that is sent or received by a WebSocket connection.
10
11
  class PongFrame < Frame
11
12
  OPCODE = 0xA
12
13
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2021, by Aurora Nockert.
6
6
 
7
7
  require_relative 'frame'
@@ -9,10 +9,11 @@ require_relative 'message'
9
9
 
10
10
  module Protocol
11
11
  module WebSocket
12
- # Implements the text frame for sending and receiving text.
12
+ # Represents a text frame that is sent or received by a WebSocket connection.
13
13
  class TextFrame < Frame
14
14
  OPCODE = 0x1
15
15
 
16
+ # @returns [Boolean] if the frame contains data.
16
17
  def data?
17
18
  true
18
19
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module WebSocket
8
- VERSION = "0.13.0"
8
+ VERSION = "0.15.0"
9
9
  end
10
10
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative 'websocket/version'
7
7
  require_relative 'websocket/framer'
8
8
  require_relative 'websocket/connection'
9
+ require_relative 'websocket/message'
data/readme.md CHANGED
@@ -6,7 +6,11 @@ Provides a low-level implementation of the WebSocket protocol according to [RFC6
6
6
 
7
7
  ## Usage
8
8
 
9
- Please see the [project documentation](https://socketry.github.io/protocol-websocket).
9
+ Please see the [project documentation](https://socketry.github.io/protocol-websocket/) for more details.
10
+
11
+ - [Getting Started](https://socketry.github.io/protocol-websocket/guides/getting-started/index) - This guide explains how to use `protocol-websocket` for implementing a websocket client and server.
12
+
13
+ - [Extensions](https://socketry.github.io/protocol-websocket/guides/extensions/index) - This guide explains how to use `protocol-websocket` for implementing a websocket client and server using extensions.
10
14
 
11
15
  ## Contributing
12
16
 
@@ -20,8 +24,8 @@ We welcome contributions to this project.
20
24
 
21
25
  ### Developer Certificate of Origin
22
26
 
23
- This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted.
27
+ In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
24
28
 
25
- ### Contributor Covenant
29
+ ### Community Guidelines
26
30
 
27
- This project is governed by the [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms.
31
+ This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protocol-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -41,7 +41,7 @@ cert_chain:
41
41
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
42
42
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
43
43
  -----END CERTIFICATE-----
44
- date: 2024-05-17 00:00:00.000000000 Z
44
+ date: 2024-07-03 00:00:00.000000000 Z
45
45
  dependencies:
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: protocol-http
@@ -66,6 +66,8 @@ files:
66
66
  - lib/protocol/websocket.rb
67
67
  - lib/protocol/websocket/binary_frame.rb
68
68
  - lib/protocol/websocket/close_frame.rb
69
+ - lib/protocol/websocket/coder.rb
70
+ - lib/protocol/websocket/coder/json.rb
69
71
  - lib/protocol/websocket/connection.rb
70
72
  - lib/protocol/websocket/continuation_frame.rb
71
73
  - lib/protocol/websocket/error.rb
@@ -73,7 +75,6 @@ files:
73
75
  - lib/protocol/websocket/extension/compression/constants.rb
74
76
  - lib/protocol/websocket/extension/compression/deflate.rb
75
77
  - lib/protocol/websocket/extension/compression/inflate.rb
76
- - lib/protocol/websocket/extensions.md
77
78
  - lib/protocol/websocket/extensions.rb
78
79
  - lib/protocol/websocket/frame.rb
79
80
  - lib/protocol/websocket/framer.rb
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
108
  - !ruby/object:Gem::Version
108
109
  version: '0'
109
110
  requirements: []
110
- rubygems_version: 3.3.7
111
+ rubygems_version: 3.5.11
111
112
  signing_key:
112
113
  specification_version: 4
113
114
  summary: A low level implementation of the WebSocket protocol.
metadata.gz.sig CHANGED
Binary file
@@ -1,13 +0,0 @@
1
- # Extensions
2
-
3
- WebSockets have a mechanism for implementing extensions. The only published extension is for per-message compression. It operates on complete messages rather than individual frames.
4
-
5
- ## Setup
6
-
7
- Clients need to define a set of extensions they want to support. The server then receives this via the `Sec-WebSocket-Extensions` header which includes a list of:
8
-
9
- Name, Options
10
-
11
- The server processes this and returns a subset of accepted `(Name, Options)`. It also instantiates the extensions and applies them to the server connection object.
12
-
13
- The client receives a list of accepted `(Name, Options)` and instantiates the extensions and applies them to the client connection object.