jls-lumberjack 0.0.7 → 0.0.8
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/lib/lumberjack/server.rb +163 -85
- metadata +11 -13
data/lib/lumberjack/server.rb
CHANGED
@@ -44,110 +44,188 @@ module Lumberjack
|
|
44
44
|
|
45
45
|
def run(&block)
|
46
46
|
while true
|
47
|
-
|
48
|
-
|
49
|
-
Connection.new(fd).run(&block)
|
50
|
-
end
|
51
|
-
rescue => e
|
52
|
-
p :accept_error => e
|
47
|
+
Thread.new(@ssl_server.accept) do |fd|
|
48
|
+
Connection.new(fd).run(&block)
|
53
49
|
end
|
54
50
|
end
|
55
51
|
end # def run
|
56
52
|
end # class Server
|
57
53
|
|
58
|
-
class
|
59
|
-
def initialize
|
60
|
-
@
|
54
|
+
class Parser
|
55
|
+
def initialize
|
56
|
+
@buffer_offset = 0
|
57
|
+
@buffer = ""
|
58
|
+
@buffer.force_encoding("BINARY")
|
59
|
+
transition(:header, 2)
|
61
60
|
end # def initialize
|
62
61
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
def transition(state, next_length)
|
63
|
+
@state = state
|
64
|
+
#puts :transition => state
|
65
|
+
# TODO(sissel): Assert this self.respond_to?(state)
|
66
|
+
# TODO(sissel): Assert state is in STATES
|
67
|
+
# TODO(sissel): Assert next_length is a number
|
68
|
+
need(next_length)
|
69
|
+
end # def transition
|
70
|
+
|
71
|
+
# Feed data to this parser.
|
72
|
+
#
|
73
|
+
# Currently, it will return the raw payload of websocket messages.
|
74
|
+
# Otherwise, it returns nil if no complete message has yet been consumed.
|
75
|
+
#
|
76
|
+
# @param [String] the string data to feed into the parser.
|
77
|
+
# @return [String, nil] the websocket message payload, if any, nil otherwise.
|
78
|
+
def feed(data, &block)
|
79
|
+
@buffer << data
|
80
|
+
#p :need => @need
|
81
|
+
while have?(@need)
|
82
|
+
send(@state, &block)
|
83
|
+
#case @state
|
84
|
+
#when :header; header(&block)
|
85
|
+
#when :window_size; window_size(&block)
|
86
|
+
#when :data_lead; data_lead(&block)
|
87
|
+
#when :data_field_key_len; data_field_key_len(&block)
|
88
|
+
#when :data_field_key; data_field_key(&block)
|
89
|
+
#when :data_field_value_len; data_field_value_len(&block)
|
90
|
+
#when :data_field_value; data_field_value(&block)
|
91
|
+
#when :data_field_value; data_field_value(&block)
|
92
|
+
#when :compressed_lead; compressed_lead(&block)
|
93
|
+
#when :compressed_payload; compressed_payload(&block)
|
94
|
+
#end # case @state
|
68
95
|
end
|
69
|
-
|
96
|
+
return nil
|
97
|
+
end # def <<
|
98
|
+
|
99
|
+
# Do we have at least 'length' bytes in the buffer?
|
100
|
+
def have?(length)
|
101
|
+
return length <= (@buffer.size - @buffer_offset)
|
102
|
+
end # def have?
|
103
|
+
|
104
|
+
# Get 'length' string from the buffer.
|
105
|
+
def get(length=nil)
|
106
|
+
length = @need if length.nil?
|
107
|
+
data = @buffer[@buffer_offset ... @buffer_offset + length]
|
108
|
+
@buffer_offset += length
|
109
|
+
if @buffer_offset > 16384
|
110
|
+
@buffer = @buffer[@buffer_offset .. -1]
|
111
|
+
@buffer_offset = 0
|
112
|
+
end
|
113
|
+
return data
|
114
|
+
end # def get
|
115
|
+
|
116
|
+
# Set the minimum number of bytes we need in the buffer for the next read.
|
117
|
+
def need(length)
|
118
|
+
@need = length
|
119
|
+
end # def need
|
120
|
+
|
121
|
+
FRAME_WINDOW = "W".ord
|
122
|
+
FRAME_DATA = "D".ord
|
123
|
+
FRAME_COMPRESSED = "C".ord
|
124
|
+
def header(&block)
|
125
|
+
version, frame_type = get.bytes.to_a[0..1]
|
126
|
+
|
127
|
+
case frame_type
|
128
|
+
when FRAME_WINDOW; transition(:window_size, 4)
|
129
|
+
when FRAME_DATA; transition(:data_lead, 8)
|
130
|
+
when FRAME_COMPRESSED; transition(:compressed_lead, 4)
|
131
|
+
else; raise "Unknown frame type: #{frame_type}"
|
132
|
+
end
|
133
|
+
end
|
70
134
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
version = io.read(1)
|
77
|
-
frame = io.read(1)
|
78
|
-
|
79
|
-
if frame == "W" # window size
|
80
|
-
window_size = io.read(4).unpack("N").first / 2
|
81
|
-
#puts "Window size: #{window_size}"
|
82
|
-
next
|
83
|
-
elsif frame == "C" # compressed data
|
84
|
-
length = io.read(4).unpack("N").first
|
85
|
-
#puts "Compressed frame length #{length}"
|
86
|
-
compressed = io.read(length)
|
87
|
-
original = Zlib::Inflate.inflate(compressed)
|
88
|
-
#original = LZ4::uncompress(compressed, length)
|
89
|
-
io.pushback(original)
|
90
|
-
next
|
91
|
-
elsif frame != "D"
|
92
|
-
#puts "Unexpected frame type: #{version.inspect} / #{frame.inspect}"
|
93
|
-
io.close
|
94
|
-
return
|
95
|
-
end
|
96
|
-
#
|
97
|
-
# data frame
|
98
|
-
sequence = io.read(4).unpack("N").first
|
99
|
-
count = io.read(4).unpack("N").first
|
100
|
-
|
101
|
-
map = {}
|
102
|
-
count.times do
|
103
|
-
key_len = io.read(4).unpack("N").first
|
104
|
-
key = io.read(key_len)
|
105
|
-
value_len = io.read(4).unpack("N").first
|
106
|
-
value = io.read(value_len)
|
107
|
-
map[key] = value
|
108
|
-
end
|
135
|
+
def window_size(&block)
|
136
|
+
@window_size = get.unpack("N").first
|
137
|
+
transition(:header, 2)
|
138
|
+
yield :window_size, @window_size
|
139
|
+
end # def window_size
|
109
140
|
|
110
|
-
|
141
|
+
def data_lead(&block)
|
142
|
+
@sequence, @data_count = get.unpack("NN")
|
143
|
+
@data = {}
|
144
|
+
transition(:data_field_key_len, 4)
|
145
|
+
end
|
111
146
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end # def each_event
|
119
|
-
end # class Connection
|
147
|
+
def data_field_key_len(&block)
|
148
|
+
key_len = get.unpack("N").first
|
149
|
+
transition(:data_field_key, key_len)
|
150
|
+
end
|
120
151
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
152
|
+
def data_field_key(&block)
|
153
|
+
@key = get
|
154
|
+
transition(:data_field_value_len, 4)
|
155
|
+
end
|
156
|
+
|
157
|
+
def data_field_value_len(&block)
|
158
|
+
transition(:data_field_value, get.unpack("N").first)
|
126
159
|
end
|
127
160
|
|
128
|
-
def
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
161
|
+
def data_field_value(&block)
|
162
|
+
@value = get
|
163
|
+
|
164
|
+
@data_count -= 1
|
165
|
+
@data[@key] = @value
|
166
|
+
|
167
|
+
if @data_count > 0
|
168
|
+
transition(:data_field_key_len, 4)
|
136
169
|
else
|
137
|
-
|
138
|
-
@buffer.clear
|
139
|
-
return data + @io.read(bytes - data.length)
|
170
|
+
transition(:header, 2)
|
140
171
|
end
|
172
|
+
|
173
|
+
yield :data, @sequence, @data
|
174
|
+
end # def data_field_value
|
175
|
+
|
176
|
+
def compressed_lead(&block)
|
177
|
+
length = get.unpack("N").first
|
178
|
+
transition(:compressed_payload, length)
|
141
179
|
end
|
180
|
+
|
181
|
+
def compressed_payload(&block)
|
182
|
+
original = Zlib::Inflate.inflate(get)
|
183
|
+
transition(:header, 2)
|
142
184
|
|
143
|
-
|
144
|
-
|
145
|
-
@buffer += data
|
185
|
+
# Parse the uncompressed payload.
|
186
|
+
feed(original, &block)
|
146
187
|
end
|
188
|
+
end # class Parser
|
147
189
|
|
148
|
-
|
149
|
-
|
190
|
+
class Connection
|
191
|
+
def initialize(fd)
|
192
|
+
super()
|
193
|
+
@parser = Parser.new
|
194
|
+
@fd = fd
|
195
|
+
@last_ack = 0
|
196
|
+
|
197
|
+
# a safe default until we are told by the client what window size to use
|
198
|
+
@window_size = 1
|
150
199
|
end
|
151
|
-
end # class IOWrap
|
152
|
-
end # module Lumberjack
|
153
200
|
|
201
|
+
def run(&block)
|
202
|
+
while true
|
203
|
+
@parser.feed(@fd.sysread(16384)) do |event, *args|
|
204
|
+
case event
|
205
|
+
when :window_size; window_size(*args, &block)
|
206
|
+
when :data; data(*args, &block)
|
207
|
+
end
|
208
|
+
#send(event, *args)
|
209
|
+
end # feed
|
210
|
+
end # while true
|
211
|
+
rescue EOFError, OpenSSL::SSL::SSLError
|
212
|
+
# EOF or other read errors, only action is to shutdown which we'll do in
|
213
|
+
# 'ensure'
|
214
|
+
ensure
|
215
|
+
@fd.close
|
216
|
+
end # def run
|
217
|
+
|
218
|
+
def window_size(size)
|
219
|
+
@window_size = size
|
220
|
+
end
|
221
|
+
|
222
|
+
def data(sequence, map, &block)
|
223
|
+
block.call(map)
|
224
|
+
if (sequence - @last_ack) >= @window_size
|
225
|
+
@fd.syswrite(["1A", sequence].pack("A*N"))
|
226
|
+
@last_ack = sequence
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end # class Connection
|
230
|
+
|
231
|
+
end # module Lumberjack
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jls-lumberjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.8
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jordan Sissel
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-26 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: lumberjack log transport library
|
15
15
|
email:
|
@@ -22,28 +22,26 @@ files:
|
|
22
22
|
- lib/lumberjack/client.rb
|
23
23
|
homepage: https://github.com/jordansissel/lumberjack
|
24
24
|
licenses: []
|
25
|
-
post_install_message:
|
25
|
+
post_install_message:
|
26
26
|
rdoc_options: []
|
27
27
|
require_paths:
|
28
28
|
- lib
|
29
29
|
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
30
31
|
requirements:
|
31
32
|
- - ! '>='
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
MA==
|
35
|
-
none: false
|
34
|
+
version: '0'
|
36
35
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
37
|
requirements:
|
38
38
|
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
41
|
-
MA==
|
42
|
-
none: false
|
40
|
+
version: '0'
|
43
41
|
requirements: []
|
44
|
-
rubyforge_project:
|
42
|
+
rubyforge_project:
|
45
43
|
rubygems_version: 1.8.24
|
46
|
-
signing_key:
|
44
|
+
signing_key:
|
47
45
|
specification_version: 3
|
48
46
|
summary: lumberjack log transport library
|
49
47
|
test_files: []
|