websocket_parser 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -19,7 +19,32 @@ Or install it yourself as:
19
19
 
20
20
  $ gem install websocket_parser
21
21
 
22
- ## Usage
22
+ ## Usage. TMTOWTDI.
23
+
24
+ ### Use return values
25
+
26
+ The simplest way to use the websocket parser is to create a new one, fetch
27
+ it with data and call the parse methods.
28
+
29
+ ```ruby
30
+ require 'websocket_parser'
31
+
32
+ parser = WebSocket::Parser.new
33
+
34
+ parser.append data
35
+
36
+ parser.parse # return next message or nil
37
+ parser.parse_all # return all parsed messages
38
+
39
+ ```
40
+
41
+ The returned messages are instances of WebSocket::Message and can be either text messages
42
+ or control frames. Check WebSocket::Message#type to know the kind of a message.
43
+
44
+ ### Use callbacks
45
+
46
+ In addition to return values, you can register callbacks to get notified when a certain event
47
+ happens.
23
48
 
24
49
  ```ruby
25
50
  require 'websocket_parser'
@@ -33,6 +33,10 @@ module WebSocket
33
33
  return true
34
34
  end
35
35
 
36
+ def accept_response
37
+ ServerHandshake.new(response_headers)
38
+ end
39
+
36
40
  def response_headers
37
41
  websocket_key = headers['Sec-Websocket-Key']
38
42
  {
@@ -42,8 +46,13 @@ module WebSocket
42
46
  }
43
47
  end
44
48
 
45
- def accept_response
46
- ServerHandshake.new(response_headers)
49
+ def to_data
50
+ data = "#{method.to_s.upcase} #{uri.path} HTTP/#{version}#{CRLF}"
51
+ @headers.each do |field, value|
52
+ data << "#{field}: #{value}#{CRLF}"
53
+ end
54
+ data << CRLF
55
+ data
47
56
  end
48
57
  end
49
58
  end
@@ -25,6 +25,8 @@ module WebSocket
25
25
  # for more info on the frame format see: http://tools.ietf.org/html/rfc6455#section-5
26
26
  #
27
27
  class Parser
28
+ attr_writer :on_message, :on_error, :on_close, :on_ping, :on_pong
29
+
28
30
  def initialize
29
31
  @data = ''.force_encoding("ASCII-8BIT")
30
32
  @state = :header
@@ -50,19 +52,37 @@ module WebSocket
50
52
  @on_pong = callback
51
53
  end
52
54
 
53
- def receive(data)
55
+ # Stores the data in a buffer for later parsing
56
+ def append(data)
54
57
  @data << data
58
+ end
55
59
 
60
+ # Receive data and parse it return an array of parsed messages
61
+ def receive(data)
62
+ append(data) && next_messages
63
+ end
64
+
65
+ alias_method :<<, :receive
66
+
67
+ # Parse all messages in buffer
68
+ def next_messages
69
+ Array.new.tap do |messages|
70
+ while msg = next_message do
71
+ messages << msg
72
+ end
73
+ end
74
+ end
75
+
76
+ # Parse next message in buffer
77
+ def next_message
56
78
  read_header if @state == :header
57
79
  read_payload_length if @state == :payload_length
58
80
  read_mask_key if @state == :mask
59
81
  read_payload if @state == :payload
60
82
 
61
- process_frame if @state == :complete
83
+ @state == :complete ? process_frame! : nil
62
84
  end
63
85
 
64
- alias_method :<<, :receive
65
-
66
86
  private
67
87
 
68
88
  def read_header
@@ -74,7 +94,7 @@ module WebSocket
74
94
 
75
95
  def read_payload_length
76
96
  @payload_length = if message_size == :small
77
- payload_length_field
97
+ payload_length_field
78
98
  else
79
99
  read_extended_payload_length
80
100
  end
@@ -86,7 +106,7 @@ module WebSocket
86
106
 
87
107
  def read_extended_payload_length
88
108
  if message_size == :medium && @data.size >= 2
89
- unpack_bytes(2,'S<')
109
+ unpack_bytes(2,'S<')
90
110
  elsif message_size == :large && @data.size >= 4
91
111
  unpack_bytes(8,'Q<')
92
112
  end
@@ -121,21 +141,23 @@ module WebSocket
121
141
  [:close, :ping, :pong].include?(opcode)
122
142
  end
123
143
 
124
- def process_frame
144
+ def process_frame!
125
145
  if @current_message
126
146
  @current_message << @payload
127
147
  else
128
148
  @current_message = @payload
129
149
  end
130
150
 
131
- if fin?
132
- process_message
133
- end
151
+ completed_message = fin? ? @current_message :nil
152
+
153
+ process_message! if fin?
134
154
 
135
155
  reset_frame!
156
+
157
+ completed_message
136
158
  end
137
159
 
138
- def process_message
160
+ def process_message!
139
161
  case opcode
140
162
  when :text
141
163
  @on_message.call(@current_message.force_encoding("UTF-8")) if @on_message
@@ -151,7 +173,6 @@ module WebSocket
151
173
 
152
174
  @on_close.call(status, message) if @on_close
153
175
  end
154
-
155
176
  @current_message = nil
156
177
  end
157
178
 
@@ -1,7 +1,5 @@
1
1
  module WebSocket
2
2
  class ServerHandshake < Http::Response
3
- CRLF = "\r\n"
4
-
5
3
  def initialize(headers = {})
6
4
  @headers = headers
7
5
  end
@@ -20,6 +18,7 @@ module WebSocket
20
18
  end
21
19
 
22
20
  data << CRLF
21
+ data
23
22
  end
24
23
  end
25
24
  end
@@ -1,3 +1,3 @@
1
1
  module WebSocket
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -11,6 +11,7 @@ module WebSocket
11
11
 
12
12
  PROTOCOL_VERSION = 13 # RFC 6455
13
13
  GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
14
+ CRLF = "\r\n"
14
15
 
15
16
  # see http://tools.ietf.org/html/rfc6455#section-11.8
16
17
  OPCODES = {
@@ -26,6 +26,19 @@ describe WebSocket::Parser do
26
26
  received_messages.first.should == 'Once upon a time'
27
27
  end
28
28
 
29
+ it "returns parsed messages on parse" do
30
+ msg1 = WebSocket::Message.new('Now is the winter of our discontent').to_data
31
+ msg2 = WebSocket::Message.new('Made glorious summer by this sun of York').to_data
32
+
33
+ messages = parser << msg1.slice!(0,5)
34
+ messages.should be_empty # We don't have a complete message yet
35
+
36
+ messages = parser << msg1 + msg2
37
+
38
+ messages[0].should == 'Now is the winter of our discontent'
39
+ messages[1].should == 'Made glorious summer by this sun of York'
40
+ end
41
+
29
42
  it "can receive a message in parts" do
30
43
  data = WebSocket::Message.new('Once upon a time').to_data
31
44
  parser << data.slice!(0, 5)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: websocket_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -97,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
97
  version: '0'
98
98
  segments:
99
99
  - 0
100
- hash: 1607326669801376036
100
+ hash: 2454613231888263104
101
101
  required_rubygems_version: !ruby/object:Gem::Requirement
102
102
  none: false
103
103
  requirements:
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  version: '0'
107
107
  segments:
108
108
  - 0
109
- hash: 1607326669801376036
109
+ hash: 2454613231888263104
110
110
  requirements: []
111
111
  rubyforge_project:
112
112
  rubygems_version: 1.8.23