rakie 0.0.2 → 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.
- checksums.yaml +4 -4
- data/lib/rakie.rb +15 -1
- data/lib/rakie/channel.rb +57 -12
- data/lib/rakie/event.rb +70 -35
- data/lib/rakie/http.rb +5 -0
- data/lib/rakie/http_proto.rb +197 -0
- data/lib/rakie/http_server.rb +134 -0
- data/lib/rakie/log.rb +96 -0
- data/lib/rakie/proto.rb +63 -0
- data/lib/rakie/simple_server.rb +7 -11
- data/lib/rakie/tcp_channel.rb +19 -3
- data/lib/rakie/tcp_server_channel.rb +32 -16
- data/lib/rakie/version.rb +11 -0
- data/lib/rakie/websocket.rb +138 -0
- data/lib/rakie/websocket_proto.rb +286 -0
- data/lib/rakie/websocket_server.rb +89 -0
- data/test/test_rakie.rb +8 -3
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81b73eacd5a896ae3c13192543965d353a0b2dcd1e1ae021664e91793d130d77
|
4
|
+
data.tar.gz: bf30ef52373d98df118064c99aaaf7465e6ac8f684d0d49bea01f7d9c6f1a5ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a2152503ca81745b8ed0cc467826cd8efd4d8006b8760ed102500f80c3bc88bf946196d03bc3242f87e7db512152147781384be05d891d51fa4aca4928428d2
|
7
|
+
data.tar.gz: 29934b5f3ecf636d047c04b00a83e45ddf54a581476f65b23cfe106f231c9cf399536d42f5b2b194ed96c747c41639999be7009e4521481ae989727b4902e5eb
|
data/lib/rakie.rb
CHANGED
@@ -1,10 +1,24 @@
|
|
1
1
|
|
2
2
|
module Rakie
|
3
|
-
|
3
|
+
NAME = "rakie"
|
4
|
+
MODE_DEV = 0
|
5
|
+
MODE_REL = 1
|
6
|
+
|
7
|
+
def self.current_mode
|
8
|
+
@current_mode ||= MODE_REL
|
9
|
+
end
|
4
10
|
end
|
5
11
|
|
6
12
|
require "rakie/channel"
|
7
13
|
require "rakie/event"
|
14
|
+
require "rakie/proto"
|
15
|
+
require "rakie/http_proto"
|
16
|
+
require "rakie/websocket_proto"
|
8
17
|
require "rakie/simple_server"
|
18
|
+
require "rakie/http_server"
|
19
|
+
require "rakie/websocket"
|
20
|
+
require "rakie/websocket_server"
|
9
21
|
require "rakie/tcp_channel"
|
10
22
|
require "rakie/tcp_server_channel"
|
23
|
+
require "rakie/log"
|
24
|
+
require "rakie/version"
|
data/lib/rakie/channel.rb
CHANGED
@@ -2,10 +2,13 @@ module Rakie
|
|
2
2
|
class Channel
|
3
3
|
attr_accessor :delegate
|
4
4
|
|
5
|
+
DEFAULT_BUFFER_SIZE = 512 * 1024
|
6
|
+
|
5
7
|
def initialize(io, delegate=nil)
|
6
8
|
@io = io
|
7
9
|
@read_buffer = String.new
|
8
10
|
@write_buffer = String.new
|
11
|
+
@write_task = []
|
9
12
|
@delegate = delegate
|
10
13
|
Event.push(io, self, Event::READ_EVENT)
|
11
14
|
end
|
@@ -13,25 +16,28 @@ module Rakie
|
|
13
16
|
def on_read(io)
|
14
17
|
begin
|
15
18
|
loop do
|
16
|
-
@read_buffer << io.read_nonblock(
|
19
|
+
@read_buffer << io.read_nonblock(DEFAULT_BUFFER_SIZE)
|
17
20
|
end
|
18
21
|
|
19
22
|
rescue IO::EAGAINWaitReadable
|
20
|
-
|
23
|
+
Log.debug("Channel read pending")
|
21
24
|
|
22
|
-
rescue
|
25
|
+
rescue IO::EWOULDBLOCKWaitReadable
|
26
|
+
Log.debug("Channel read pending")
|
27
|
+
|
28
|
+
rescue Exception => e
|
23
29
|
# Process the last message on exception
|
24
30
|
if @delegate != nil
|
25
31
|
@delegate.on_recv(self, @read_buffer)
|
26
32
|
@read_buffer = String.new # Reset buffer
|
27
33
|
end
|
28
34
|
|
29
|
-
|
35
|
+
Log.debug("Channel error #{io}: #{e}")
|
30
36
|
return Event::HANDLE_FAILED
|
31
37
|
end
|
32
38
|
|
33
|
-
puts("Channel has delegate?: #{@delegate}")
|
34
39
|
if @delegate != nil
|
40
|
+
Log.debug("Channel handle on_recv")
|
35
41
|
len = @delegate.on_recv(self, @read_buffer)
|
36
42
|
|
37
43
|
if len > @read_buffer.length
|
@@ -39,40 +45,77 @@ module Rakie
|
|
39
45
|
end
|
40
46
|
|
41
47
|
@read_buffer = @read_buffer[len .. -1]
|
42
|
-
puts("Channel handle on_recv")
|
43
48
|
end
|
44
49
|
|
45
50
|
return Event::HANDLE_CONTINUED
|
46
51
|
end
|
47
52
|
|
53
|
+
def handle_write(len)
|
54
|
+
task = @write_task[0]
|
55
|
+
|
56
|
+
while len > 0
|
57
|
+
if len < task
|
58
|
+
@write_task[0] = task - len
|
59
|
+
end
|
60
|
+
|
61
|
+
len -= task
|
62
|
+
@write_task.shift
|
63
|
+
|
64
|
+
if @delegate != nil
|
65
|
+
@delegate.on_send(self)
|
66
|
+
Log.debug("Channel handle on_send")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
48
71
|
def on_write(io)
|
72
|
+
len = 0
|
73
|
+
offset = 0
|
74
|
+
|
49
75
|
begin
|
50
76
|
while @write_buffer.length > 0
|
51
77
|
len = io.write_nonblock(@write_buffer)
|
78
|
+
offset += len
|
52
79
|
@write_buffer = @write_buffer[len .. -1]
|
53
80
|
end
|
54
81
|
|
55
|
-
|
82
|
+
Log.debug("Channel write finished")
|
56
83
|
|
57
84
|
rescue IO::EAGAINWaitWritable
|
58
|
-
|
85
|
+
self.handle_write(offset)
|
86
|
+
|
87
|
+
Log.debug("Channel write pending")
|
88
|
+
return Event::HANDLE_CONTINUED
|
89
|
+
|
90
|
+
rescue IO::EWOULDBLOCKWaitWritable
|
91
|
+
self.handle_write(offset)
|
92
|
+
|
93
|
+
Log.debug("Channel write pending")
|
59
94
|
return Event::HANDLE_CONTINUED
|
60
95
|
|
61
96
|
rescue
|
62
|
-
|
97
|
+
Log.debug("Channel close #{io}")
|
63
98
|
return Event::HANDLE_FAILED
|
64
99
|
end
|
65
100
|
|
101
|
+
self.handle_write(offset)
|
102
|
+
|
66
103
|
return Event::HANDLE_FINISHED
|
67
104
|
end
|
68
105
|
|
69
|
-
def
|
106
|
+
def on_detach(io)
|
70
107
|
begin
|
71
108
|
io.close
|
72
109
|
|
110
|
+
if @delegate
|
111
|
+
@delegate.on_close(self)
|
112
|
+
end
|
113
|
+
|
73
114
|
rescue
|
74
|
-
|
115
|
+
Log.debug("Channel is already closed")
|
75
116
|
end
|
117
|
+
|
118
|
+
Log.debug("Channel close ok")
|
76
119
|
end
|
77
120
|
|
78
121
|
def read(size)
|
@@ -96,7 +139,9 @@ module Rakie
|
|
96
139
|
end
|
97
140
|
|
98
141
|
@write_buffer << data
|
99
|
-
|
142
|
+
@write_task << data.length
|
143
|
+
|
144
|
+
Event.modify(@io, self, (Event::READ_EVENT | Event::WRITE_EVENT))
|
100
145
|
|
101
146
|
return 0
|
102
147
|
end
|
data/lib/rakie/event.rb
CHANGED
@@ -9,6 +9,10 @@ module Rakie
|
|
9
9
|
HANDLE_CONTINUED = 0
|
10
10
|
HANDLE_FINISHED = 1
|
11
11
|
|
12
|
+
OPERATION_ADD = 0
|
13
|
+
OPERATION_MODIFY = 1
|
14
|
+
OPERATION_DELETE = 2
|
15
|
+
|
12
16
|
def initialize
|
13
17
|
@wait_ios = []
|
14
18
|
@lock = Mutex.new
|
@@ -24,36 +28,39 @@ module Rakie
|
|
24
28
|
|
25
29
|
def process_signal(io)
|
26
30
|
signal = io.read(1)
|
27
|
-
puts("Event handling #{signal}")
|
28
31
|
|
29
|
-
if signal == '
|
30
|
-
|
32
|
+
if signal == 'q'
|
33
|
+
return 1
|
34
|
+
end
|
35
|
+
|
36
|
+
operation, new_io, new_handler, new_event = @wait_ios.shift
|
37
|
+
if new_io.closed?
|
38
|
+
return 0
|
39
|
+
end
|
40
|
+
|
41
|
+
Log.debug("Event handling #{signal} with #{new_io.fileno} to #{new_event}")
|
42
|
+
|
43
|
+
if operation == OPERATION_ADD
|
31
44
|
@ios[new_io] = new_event
|
32
45
|
@handlers[new_io] = new_handler
|
33
|
-
|
46
|
+
Log.debug("Event add all #{new_io.fileno} to #{new_event}")
|
34
47
|
|
35
|
-
elsif
|
36
|
-
new_io, = @wait_ios.shift
|
48
|
+
elsif operation == OPERATION_DELETE
|
37
49
|
handler = @handlers[new_io]
|
38
50
|
|
39
51
|
if handler != nil
|
40
|
-
|
41
|
-
|
52
|
+
Log.debug("Event close #{new_io}")
|
53
|
+
handler.on_detach(new_io)
|
42
54
|
end
|
43
55
|
|
44
56
|
@ios.delete(new_io)
|
45
57
|
@handlers.delete(new_io)
|
58
|
+
Log.debug("Event remove all #{new_io}")
|
46
59
|
|
47
|
-
|
48
|
-
|
49
|
-
elsif signal == 'm'
|
50
|
-
new_io, new_handler, new_event = @wait_ios.shift
|
60
|
+
elsif operation == OPERATION_MODIFY
|
51
61
|
@ios[new_io] = new_event
|
52
62
|
@handlers[new_io] = new_handler
|
53
|
-
|
54
|
-
|
55
|
-
elsif signal == 'q'
|
56
|
-
return 1
|
63
|
+
Log.debug("Event modify all #{new_io.fileno} to #{new_event}")
|
57
64
|
end
|
58
65
|
|
59
66
|
return 0
|
@@ -61,9 +68,18 @@ module Rakie
|
|
61
68
|
|
62
69
|
def run_loop
|
63
70
|
loop do
|
71
|
+
# p @ios
|
72
|
+
# begin
|
73
|
+
# read_ios = @ios.select {|k, v| v & READ_EVENT > 0}
|
74
|
+
# write_ios = @ios.select {|k, v| v & WRITE_EVENT > 0}
|
75
|
+
# rescue Exception => e
|
76
|
+
# p @ios
|
77
|
+
# end
|
78
|
+
|
64
79
|
read_ios = @ios.select {|k, v| v & READ_EVENT > 0}
|
65
80
|
write_ios = @ios.select {|k, v| v & WRITE_EVENT > 0}
|
66
81
|
|
82
|
+
# Log.debug("Event selecting ...")
|
67
83
|
read_ready, write_ready = IO.select(read_ios.keys, write_ios.keys, [], 5)
|
68
84
|
|
69
85
|
if read_ready != nil
|
@@ -89,16 +105,16 @@ module Rakie
|
|
89
105
|
result = handler.on_read(io)
|
90
106
|
|
91
107
|
if result == HANDLE_FINISHED
|
92
|
-
@ios[io]
|
93
|
-
|
108
|
+
@ios[io] &= ~READ_EVENT
|
109
|
+
Log.debug("Event remove read #{io}")
|
94
110
|
|
95
111
|
elsif result == HANDLE_FAILED
|
96
|
-
handler.
|
97
|
-
|
112
|
+
handler.on_detach(io)
|
113
|
+
Log.debug("Event close #{io}")
|
98
114
|
|
99
115
|
@ios.delete(io)
|
100
116
|
@handlers.delete(io)
|
101
|
-
|
117
|
+
Log.debug("Event remove all #{io}")
|
102
118
|
end
|
103
119
|
end
|
104
120
|
end
|
@@ -114,16 +130,16 @@ module Rakie
|
|
114
130
|
result = handler.on_write(io)
|
115
131
|
|
116
132
|
if result == HANDLE_FINISHED
|
117
|
-
@ios[io]
|
118
|
-
|
133
|
+
@ios[io] &= ~WRITE_EVENT
|
134
|
+
Log.debug("Event remove write #{io}")
|
119
135
|
|
120
136
|
elsif result == HANDLE_FAILED
|
121
|
-
handler.
|
122
|
-
|
137
|
+
handler.on_detach(io)
|
138
|
+
Log.debug("Event close #{io}")
|
123
139
|
|
124
140
|
@ios.delete(io)
|
125
141
|
@handlers.delete(io)
|
126
|
-
|
142
|
+
Log.debug("Event remove all #{io}")
|
127
143
|
end
|
128
144
|
end
|
129
145
|
end
|
@@ -132,39 +148,58 @@ module Rakie
|
|
132
148
|
|
133
149
|
def push(io, handler, event)
|
134
150
|
@lock.lock
|
135
|
-
@wait_ios.push([io, handler, event])
|
151
|
+
@wait_ios.push([OPERATION_ADD, io, handler, event])
|
136
152
|
@signal_out.write('a')
|
137
153
|
@lock.unlock
|
138
154
|
end
|
139
155
|
|
140
156
|
def delete(io)
|
141
157
|
@lock.lock
|
142
|
-
@wait_ios.push([io, nil, nil])
|
143
|
-
@signal_out.write('
|
158
|
+
@wait_ios.push([OPERATION_DELETE, io, nil, nil])
|
159
|
+
@signal_out.write('a')
|
144
160
|
@lock.unlock
|
145
161
|
end
|
146
162
|
|
147
163
|
def modify(io, handler, event)
|
148
164
|
@lock.lock
|
149
|
-
@wait_ios.push([io, handler, event])
|
150
|
-
@signal_out.write('
|
165
|
+
@wait_ios.push([OPERATION_MODIFY, io, handler, event])
|
166
|
+
@signal_out.write('a')
|
151
167
|
@lock.unlock
|
152
168
|
end
|
153
169
|
|
154
170
|
def self.instance
|
155
|
-
@instance ||= Event.new
|
171
|
+
@instance ||= Array.new(self.concurrent) { |i| Event.new }
|
156
172
|
end
|
157
173
|
|
158
174
|
def self.push(io, listener, type)
|
159
|
-
|
175
|
+
i = io.fileno % self.concurrent
|
176
|
+
inst = self.instance[i]
|
177
|
+
inst.push(io, listener, type)
|
178
|
+
# instance.push(io, listener, type)
|
160
179
|
end
|
161
180
|
|
162
181
|
def self.delete(io)
|
163
|
-
self.
|
182
|
+
i = io.fileno % self.concurrent
|
183
|
+
inst = self.instance[i]
|
184
|
+
inst.delete(io)
|
185
|
+
# self.instance.delete(io)
|
164
186
|
end
|
165
187
|
|
166
188
|
def self.modify(io, listener, type)
|
167
|
-
|
189
|
+
i = io.fileno % self.concurrent
|
190
|
+
inst = self.instance[i]
|
191
|
+
inst.modify(io, listener, type)
|
192
|
+
# self.instance.modify(io, listener, type)
|
193
|
+
end
|
194
|
+
|
195
|
+
# @return [Integer]
|
196
|
+
def self.concurrent
|
197
|
+
@concurrent ||= 2
|
198
|
+
end
|
199
|
+
|
200
|
+
# @param [Integer] count
|
201
|
+
def self.concurrent=(count)
|
202
|
+
@concurrent = count
|
168
203
|
end
|
169
204
|
end
|
170
205
|
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module Rakie
|
2
|
+
class HttpMIME
|
3
|
+
TEXT = "text/plain"
|
4
|
+
HTML = "text/html"
|
5
|
+
JSON = "application/json"
|
6
|
+
end
|
7
|
+
|
8
|
+
class HttpRequest
|
9
|
+
include Proto
|
10
|
+
|
11
|
+
attr_accessor :head, :headers, :content
|
12
|
+
|
13
|
+
PARSE_HEAD = PARSE_BEGIN
|
14
|
+
PARSE_HEADERS = 1
|
15
|
+
PARSE_CONTENT = 2
|
16
|
+
|
17
|
+
class Head
|
18
|
+
attr_accessor :method, :path, :version
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@method = 'HEAD'
|
22
|
+
@path = '/'
|
23
|
+
@version = 'HTTP/1.1'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@head = Head.new
|
29
|
+
@headers = {}
|
30
|
+
@content = ''
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [String] source
|
34
|
+
def parse_source_head(source)
|
35
|
+
offset = parse_offset
|
36
|
+
|
37
|
+
if eol_offset = source.index("\r\n")
|
38
|
+
head_s = source[0 .. eol_offset]
|
39
|
+
head_method, head_path, head_version = head_s.split(' ')
|
40
|
+
|
41
|
+
head.method = head_method
|
42
|
+
head.path = head_path
|
43
|
+
head.version = head_version
|
44
|
+
|
45
|
+
self.parse_state = PARSE_HEADERS
|
46
|
+
self.parse_offset = offset + 2
|
47
|
+
|
48
|
+
Log.debug("Rakie::HttpRequest parse source head ok")
|
49
|
+
return ParseStatus::CONTINUE
|
50
|
+
end
|
51
|
+
|
52
|
+
return ParseStatus::PENDING
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_source_header_item(header)
|
56
|
+
if semi_offset = header.index(':')
|
57
|
+
return [
|
58
|
+
header[0 .. (semi_offset - 1)].downcase,
|
59
|
+
header[(semi_offset + 1) .. -1].strip
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [String] source
|
67
|
+
def parse_source_headers(source)
|
68
|
+
offset = parse_offset
|
69
|
+
|
70
|
+
while eol_offset = source.index("\r\n", offset)
|
71
|
+
header = source[offset .. (eol_offset - 1)]
|
72
|
+
|
73
|
+
if header.length == 0
|
74
|
+
self.parse_state = PARSE_CONTENT
|
75
|
+
self.parse_offset = eol_offset + 2
|
76
|
+
|
77
|
+
Log.debug("Rakie::HttpRequest parse source header done")
|
78
|
+
return ParseStatus::CONTINUE
|
79
|
+
end
|
80
|
+
|
81
|
+
header_key, header_value = self.parse_source_header_item(header)
|
82
|
+
|
83
|
+
if header_key
|
84
|
+
headers[header_key] = header_value
|
85
|
+
Log.debug("Rakie::HttpRequest parse source #{header_key}, #{header_value} header ok")
|
86
|
+
end
|
87
|
+
|
88
|
+
offset = eol_offset + 2
|
89
|
+
end
|
90
|
+
|
91
|
+
self.parse_offset = offset
|
92
|
+
|
93
|
+
return ParseStatus::PENDING
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param [String] source
|
97
|
+
def parse_source_content(source)
|
98
|
+
len = headers["content-length"]
|
99
|
+
offset = parse_offset
|
100
|
+
|
101
|
+
if len == nil
|
102
|
+
return ParseStatus::COMPLETE
|
103
|
+
end
|
104
|
+
|
105
|
+
len = len.to_i
|
106
|
+
|
107
|
+
if source.length >= len + offset
|
108
|
+
self.content = source[offset .. (offset + len - 1)]
|
109
|
+
self.parse_state = PARSE_HEAD
|
110
|
+
self.parse_offset = offset + len
|
111
|
+
|
112
|
+
Log.debug("Rakie::HttpRequest parse source content ok")
|
113
|
+
return ParseStatus::COMPLETE
|
114
|
+
end
|
115
|
+
|
116
|
+
return ParseStatus::PENDING
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [String] source
|
120
|
+
# @return [Integer]
|
121
|
+
def deserialize(source)
|
122
|
+
current_state = parse_state
|
123
|
+
|
124
|
+
case current_state
|
125
|
+
when PARSE_HEAD
|
126
|
+
return parse_source_head(source)
|
127
|
+
|
128
|
+
when PARSE_HEADERS
|
129
|
+
return parse_source_headers(source)
|
130
|
+
|
131
|
+
when PARSE_CONTENT
|
132
|
+
return parse_source_content(source)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [String]
|
137
|
+
def serialize
|
138
|
+
data = ""
|
139
|
+
|
140
|
+
data += "#{head.method} #{head.path} #{head.version}"
|
141
|
+
data += "\r\n"
|
142
|
+
|
143
|
+
headers_list = []
|
144
|
+
headers.each do |k, v|
|
145
|
+
headers_list << "#{k}: #{v}"
|
146
|
+
end
|
147
|
+
|
148
|
+
data += headers_list.join("\r\n")
|
149
|
+
data += "\r\n\r\n"
|
150
|
+
|
151
|
+
data += content
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class HttpResponse
|
156
|
+
include Proto
|
157
|
+
|
158
|
+
PARSE_HEAD = 0
|
159
|
+
PARSE_HEADERS = 1
|
160
|
+
PARSE_CONTENT = 2
|
161
|
+
|
162
|
+
attr_accessor :head, :headers, :content
|
163
|
+
|
164
|
+
class Head
|
165
|
+
attr_accessor :version, :status, :message
|
166
|
+
|
167
|
+
def initialize
|
168
|
+
@version = 'HTTP/1.1'
|
169
|
+
@status = 200
|
170
|
+
@message = 'OK'
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def initialize
|
175
|
+
@head = Head.new
|
176
|
+
@headers = {}
|
177
|
+
@content = ''
|
178
|
+
end
|
179
|
+
|
180
|
+
def serialize
|
181
|
+
data = ""
|
182
|
+
|
183
|
+
data += "#{head.version} #{head.status} #{head.message}"
|
184
|
+
data += "\r\n"
|
185
|
+
|
186
|
+
headers_list = []
|
187
|
+
headers.each do |k, v|
|
188
|
+
headers_list << "#{k}: #{v}"
|
189
|
+
end
|
190
|
+
|
191
|
+
data += headers_list.join("\r\n")
|
192
|
+
data += "\r\n\r\n"
|
193
|
+
|
194
|
+
data += content
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|